Чи бажано проектувати зверху вниз або знизу вгору?


31

Як я розумію, дизайн зверху вниз - це вдосконалення абстрактної концепції високого рівня на менші конкретні та зрозумілі частини, поки не буде визначено найменший будівельний блок. З іншого боку, знизу вгору визначаються деталі низького рівня, потім поступово нарощуйте блоки вищого рівня, поки не буде сформована вся система.

На практиці, як кажуть, найкраще поєднувати два методи: починаючи з специфікації високого рівня, щоб повністю уточнити знання про домен, його взаємозв'язок та обмеження. Як тільки проблема буде добре зрозуміла, для створення системи створюються найменші будівельні блоки.

Процес:

  • Створення специфікації вимог
  • Створіть специфікацію дизайну (із схемами)
  • Реалізація
  • Поставити
  • Повторіть (в процесі ітеративної розробки, а не робити цілий шматок на кожній фазі, ми робимо потроху кожну повторно, і ми проводимо щоденні зустрічі, щоб адаптуватись до динамічної потреби клієнта)

для мене виглядає абсолютно нормально (із специфікаціями як у планах). У нього є свої недоліки, але саме тому ми отримали ітеративну розробку: замість того, щоб витрачати час на одну фазу, каже, аналіз вимог, щоб вивчити кожну можливу річ у доменних знаннях, які зазнають змін (можливо, щодня), ми робимо трохи аналізу, трохи розробити дизайн, а потім реалізувати його.

Інший спосіб полягає в тому, що кожна ітерація - це міні-водоспад, де аналіз робиться за кілька днів (або тиждень). Те саме стосується дизайну. Решту часу витрачається на реалізацію. Чи є щось по суті не так у підході зверху вниз у поєднанні з ітераційним розвитком?

У своєму нарисі Програмування знизу вгору Пол Грехем, схоже, спонукає будувати знизу вгору або програмувати його знизу вгору, але не аналіз вимог / етап проектування:

Досвідчені програмісти Lisp розділяють свої програми по-різному. Як і дизайн зверху вниз, вони дотримуються принципу, який можна назвати дизайном знизу вгору - змінюючи мову відповідно до проблеми.

Наскільки я розумію, що він мав на увазі, що Ліспер все ще виконує дизайн зверху вниз, але програма знизу вгору, це правда? Ще один момент, який він написав:

Варто підкреслити, що дизайн знизу вгору не означає просто писати одну і ту ж програму в іншому порядку. Працюючи знизу вгору, зазвичай ви закінчуєте іншу програму. Замість єдиної, монолітної програми ви отримаєте більшу мову з більш абстрактними операторами та меншою програмою, написаною на ній. Замість перемички ви отримаєте арку.

Чи означає це, що під час написання програми в Ліспі ви закінчуєтесь загальним інструментом?


Можливо, якщо ви надасте посилання на книгу, папір чи статтю, про яку ви посилаєтесь, інші можуть зробити більш обґрунтовану заяву стосовно вашого питання. Також незрозуміло, про що конкретно йдеться у вашому питанні. Ви звертаєтесь за порадами щодо певних особливостей щодо дизайну, який хочете реалізувати, або ставите питання щодо статті, на яку ви посилаєтесь. Можливо, це було б простіше прочитати та відповісти, якби ви розбили їх на пару запитань окремо.
S.Robins

@ S.Robins Підводячи підсумки, я продемонстрував свій звичайний підхід до розробки програмного забезпечення. Однак деякі люди віддають перевагу знизу вгору, і одним з них є Пол Грехем, який є відомою людиною. Я прошу розібратися, як дизайн «знизу вгору» допомагає взагалі, зокрема в Ліспі, оскільки він має особливі особливості для заохочення (як запропонував Пол).
Amumu

1
Amumu Я відредагував приклад, оскільки обидві відповіді, схоже, пропустили його. Будь-ласка, намагайтеся зберегти свої питання лаконічними та задайте лише одне запитання на кожне питання .
янніс

Відповіді:


35

Зверху вниз - це прекрасний спосіб описати речі, які ви знаєте, або відновити речі, які ви вже створили.

Найбільша проблема зверху вниз полягає в тому, що досить часто просто немає «верху». Ви передумаєте, що система повинна робити під час розробки системи та під час дослідження домену. Як може бути вашою відправною точкою щось, чого ви не знаєте (тобто, що ви хочете робити в системі)?

"Місцевий" зверху вниз - це гарна річ ... деякі думки перед кодуванням явно хороші. Але думати і планувати занадто багато немає, тому що те, що ти передбачаєш, не є реальним сценарієм (якщо тільки ти вже там не був, тобто якщо ти не будуєш, а відновлюєш). Глобальний згори вниз при будівництві нових речей - це просто нісенітниця.

Підсумковий підхід повинен бути (в усьому світі) підходом, якщо ви не знаєте 100% проблеми, вам потрібно зашифрувати лише відоме рішення, і вам не байдуже шукати можливі альтернативні рішення.

Ліспський підхід - це дистильована знизу вгору. Ви не тільки будуєте знизу вгору, але також можете формувати цеглини так, як вам потрібно. Нічого не фіксується, свобода тотальна. Звичайно, свобода бере на себе відповідальність, і ви можете зробити жахливі речі, зловживаючи цією владою.

Але жахливий код можна написати будь-якою мовою. Навіть у мовах, що мають форму кліток для розуму, розроблених з надією, що з цими мовами навіть мавпи можуть отримати хороші програми та працювати (ідея настільки неправильна на стільки рівнях, що шкодить навіть просто думати про це).

Ваш приклад стосується веб-сервера. Зараз у 2012 році це чітко визначена проблема, у вас є специфікації, яких потрібно дотримуватися. Веб-сервер - це лише проблема впровадження. Тим більше, якщо ви прагнете написати веб-сервер, істотно ідентичний іншим мільйонам веб-серверів, які знаходяться там, то нічого насправді незрозуміло, крім деяких дрібниць. Навіть ваш коментар про RSA все ще говорить про чітко визначену проблему з формальними специфікаціями.

З чітко визначеною проблемою, з формальними специфікаціями та вже відомими рішеннями, кодування просто з'єднується в точках. Зверху вниз для цього нормально. Це небесний менеджер.

Однак у багатьох випадках не існує перевіреного відомого підходу, який би використовувався для з'єднання крапок. Насправді дуже часто важко сказати навіть, які є точки.

Припустимо, наприклад, що вам запропонують доручити автоматичній машині різання вирівняти деталі, що підлягають розрізуванню, до друкованого матеріалу, який не ідеально відповідає теоретичному повторюваному логотипу. Вам надаються деталі та фотографії матеріалу, зроблені машиною.

Що таке правило вирівнювання? Тобі вирішувати. Що таке візерунок, як його зобразити? Тобі вирішувати. Як вирівняти деталі? Тобі вирішувати. Чи можна деталі «зігнути»? Це залежить, деякі ні, а деякі так, але, звичайно, не надто. Що робити, якщо матеріал просто занадто деформований для частини, щоб його прийнятно розрізати? Тобі вирішувати. Чи всі рулони матеріалу однакові? Звичайно, ні, але ви не можете перешкодити користувачеві адаптувати правила вирівнювання для кожного рулону ... це було б недоцільно. Які фотографії бачать камери? Матеріал, що б це не означало ... це може бути колір, він може бути чорним над чорним, де тільки світловий рефлекс робить шаблон очевидним. Що означає розпізнавати візерунок? Тобі вирішувати.

Тепер спробуйте спроектувати загальну структуру рішення цієї проблеми і дайте цитату в грошах і в часі. Моя обставина, що навіть ваша системна архітектура ... (так, архітектура) буде помилятися. Оцінка витрат і часу буде випадковими числами.

Ми його реалізували і зараз це працююча система, але неодноразово змінювали свою думку про саму форму системи. Ми додали цілі підсистеми, які зараз неможливо дістати навіть із меню. Ми не один раз перемикали ролі головного / підлеглого в протоколах. Напевно, зараз у нас достатньо знань, щоб спробувати її краще відновити.

Інші компанії, звичайно, вирішили ту ж проблему ... але якщо ви не знаходитесь в одній з цих компаній, швидше за все, ваш детальний проект згори вниз буде жартом. Ми можемо спроектувати це зверху вниз. Ви не можете, тому що ніколи раніше цього не робили.

Можливо, ви можете вирішити таку ж проблему. Однак працюємо знизу вгору. Починаючи з того, що знаєте, вивчаючи те, чого ви не робите, і складаючи.

Вирощуються нові складні програмні системи, не розробляються. Раз у раз хтось починає проектувати велику нову складну програмно-програмну систему з нуля (зауважте, що при великому складному програмному проекті є лише три можливості: a) специфікація нечітка, b) специфікація неправильна та суперечлива або с] і те ... і найчастіше [с] так).

Це типові проекти величезної компанії з тисячами і тисячами годин, що підкидаються лише слайдами Powerpoint та діаграмами UML. Вони незмінно повністю виходять з ладу після спалювання незручних обсягів ресурсів ... або в дуже надзвичайному випадку вони нарешті доставляють завищену частину програмного забезпечення, яка реалізує лише мініатюрну частину початкових специфікацій. І це програмне забезпечення незмінно ненависне користувачами ... не той тип програмного забезпечення, який ви купували б, а тип програмного забезпечення, яке ви використовуєте, тому що ви змушені.

Чи означає це, що я думаю, що ви повинні думати лише для кодування? Звичайно, ні. Але, на мою думку, будівництво має починатися знизу (цегла, бетонний код) і повинно підніматися вгору ... і ваша увага та увага до деталей повинні певним чином «згасати», оскільки ви стаєте далі від того, що маєте. Зверху вниз часто подається так, ніби ви повинні одразу ставити один і той же рівень деталізації всієї системи: просто продовжуйте її розбивати кожен вузол, поки все не стане очевидно ... в модулях реальності підсистема "вирощується" з підпрограм. Якщо у вас немає попереднього досвіду вирішення конкретної проблеми, дизайн підсистеми, модуля або бібліотеки буде зверху жахливим. Ви можете спроектувати хорошу бібліотеку, як тільки зрозумієте, які функції потрібно вкласти, а не навпаки.

Багато ідей Lisp стають все більш популярними (функції першого класу, закриття, динамічне введення тексту за замовчуванням, збирання сміття, метапрограмування, інтерактивна розробка), але Lisp все ще є сьогодні (серед мов, яких я знаю) досить унікальний тим, як легко формувати код для того, що вам потрібно.

Наприклад, параметри ключових слів вже є, але якщо їх не було, їх можна додати. Я зробив це (включаючи перевірку ключових слів під час компіляції) для іграшкового компілятора Lisp, з яким я експериментую, і це не потребує великого коду.

Замість цього на C ++ найбільше ви можете отримати купу експертів C ++, які говорять вам про те, що параметри ключових слів не настільки корисні, або неймовірно складна, зламана, наполовину захищена реалізація шаблону, яка насправді не є такою корисною. Чи є об'єкти класу C ++ першокласними? Ні, і ви нічого з цим не можете зробити. Ви можете мати самоаналіз під час виконання або під час компіляції? Ні, і ви нічого з цим не можете зробити.

Ця мовна гнучкість Lisp - це те, що робить його чудовим для будівництва знизу вгору. Ви можете будувати не тільки підпрограми, але й синтаксис та семантику мови. І в певному сенсі сам Лісп знизу вгору.


Так, я мав на увазі місцевий верх зверху вниз. Ви продовжуєте уточнювати вимогу та розвиваєте її за допомогою ітерацій. Сенс зверху вниз полягає в тому, що ми хочемо отримати структуру коду максимально правильною. Постійно рефакторинг. Наприклад, спочатку ви хочете передати рядок функції, але пізніше вам потрібен цілий клас, щоб задовольнити зміни, і рефакторинг займає багато часу, якщо функція вже використовується скрізь.
Amumu

Повторно будувати щось добре відоме чітко відомим способом, то згори вниз - це нормально. Ваш веб-браузер є прикладом цього. Навіть використання такої мови, як C ++, яка змушує вас передбачити та формально вказати (використовуючи жахливий синтаксис) усіх типів для значень, що містяться у всіх змінних вашої програми, все ще є життєздатним варіантом.
6502 р.

Я не думаю, що мій приклад є чітко відомим способом, тому що я припускаю, що його створив хтось із базовими знаннями передачі даних, а код C ++ є результатом дуже базової конструкції з доменних знань (у цьому випадку мережевих зв’язків) . Це приклад дизайну еволюції. Під час наступної ітерації розробник дізнається більше про знання домену, тому він розширює свою конструкцію, щоб відповідати розвинутим знанням (наприклад, про додаткові аспекти безпеки у кожному шарі веб-сервера). Потім він доопрацьовує виконання згідно з новим дизайном.
Amumu

Сенс у тому, що власне рішення, отримане з незалежної від домену мови (наприклад, натуральної мови, математики ... залежить від домену). Акт кодування - це лише детальне відображення від створеного рішення до коду.
Amumu

1
Привіт, п. 6502. Через рік, коли я дізнався більше речей, я починаю бачити, що ви сказали, стають правдивішими. Я зробив ще одну нитку: programmers.stackexchange.com/questions/179000 / ... . Якщо у вас є час, я сподіваюся, ви знову проясніть моє мислення: D.
Амуму

6

Я не впевнений, як ця відповідь стосуватиметься Lisp, але я щойно закінчив читати Agile Principles, Patterns and Practices , і автор, дядько Боб , наполегливо виступає за підхід зверху вниз для C # (також застосовно до C ++), з яким я повністю згоден.

Однак, на відміну від деяких інших відповідей, які зробили висновок, що підхід зверху вниз означає, що в першій взаємодії ви доставляєте лише документи та загальний дизайн, книга вказує на інший метод: TDD у поєднанні з еволюційним дизайном.

Ідея полягає в тому, що ви починаєте зверху і визначаєте свої найвищі рівні абстракції (або місцеві найвищі), і як тільки вони визначені, ви змусите їх робити корисну роботу, щоб функція №1 негайно працювала. Тоді, додаючи все нові й нові функції, ви перефактуруєте свій код та розробляєте дизайн за потребою, завжди знаючи принципи SOLID. Таким чином, ви не отримаєте занадто багато шарів абстракції, і ви не закінчите дизайн низького рівня, який не відповідає загальній архітектурі. Якщо ви не впевнені, що це означає, книга, яку я згадав вище, містить цілу главу з прикладом, коли розробники беруть поняття і починають з діаграм UML та класів низького рівня, тільки щоб реалізувати половину цих класів не потрібно, як тільки кодування фактично починається. По суті, при такому підході код низького рівня природно висувається вниз, оскільки в проекті визначено більше деталей високого рівня.

І нарешті, якщо ви практикуєте SOLID, ви не повинні стикатися з ситуацією, коли у вас визначені абстракції високого рівня, а потім вникати в деталі і раптом виявити, що немає OOD чи абстракцій. У цьому насправді не винна конструкція зверху вниз, але ледача інженерія.

Якщо вам цікаво почитати більше про XP та еволюційний дизайн, ось вам добре прочитаний від іншого великого автора Мартіна Фаулера: "Is Design Dead?"


Ідеально. Це те, про що я говорю. Також приємно знати про принцип SOLID, і Agile підтримує підхід зверху вниз (я думав, що за допомогою TDD і XP люди переходять на швидкий код і уникають документації).
Amumu

@Amumu: я додав посилання на іншу статтю, написану Фаулером. Ви можете прочитати докладніше про різницю між кодуванням ковбоя без дизайну / документації та того, що XP / Agile насправді рекламує. Хоча я особисто переконаний, що документація має цінність, і я активно просуваю свою команду, щоб не відставати від наших дизайнерських документів, я поступово змінює свої погляди. Тепер наші "дизайнерські завдання" - це всі речі на дошці / серветці, а фактичні документи оновлюються лише після написання розповіді. Ми також розширюємо масштаби того, що є фактично задокументованим, тому документи охоплюють лише матеріали високого рівня / архітектури
DXM

3

Для мене найважливіші зауваження, які робить Пол Грехем у своїй статті, такі:

[...] Програмісти Lisp [...] дотримуються принципу, який можна назвати дизайном знизу вгору - змінюючи мову відповідно до проблеми. У Lisp ви не просто записуєте програму до мови, але й будуєте мову до своєї програми.

Або, як відомо в колах C ++: Дизайн бібліотеки - це мовний дизайн (Bjarne Stroustrup)

Основна ідея дизайну зверху вниз: спочатку плануєте, потім кодуєте. Біноу правильно, коли пише , що виникають проблеми, коли виконуваний код заходить пізно в процесі. У дизайні знизу вгору завжди є код і той код, який можна перевірити.

Також ваш код не вказаний. Маючи на увазі, я маю на увазі більше рівнів менших абстракцій. У дизайні зверху вниз люди часто стикаються з великими абстракціями до якогось довільного рівня і нижче, ніж відсутність абстракцій. Код, розроблений OTOH, часто містить менш низький рівень контролю та структури даних, оскільки вони, ймовірно, будуть абстраговані.


2

В ідеалі написання програми будь-якою мовою, а не лише Lisp, дозволяє написати цілий набір загальних інструментів, які можуть прискорити наступну програму або підвищення швидкості до поточної.

На практиці відслідковувати ці засоби може бути складно. Документація погана і неорганізована, і люди, які знають про них, залишають. На практиці повторне використання коду часто є більшим клопотом, ніж варто. Але якщо код задокументований і організований належним чином, а програмісти дотримуються (або зберігають власний запас корисного коду), величезну кількість роботи можна врятувати, захопивши код зі складу, а не відновлюючи його.

Весь дизайн повинен бути зверху вниз, інакше ви не знаєте, що робите. Ви будуєте сарай чи машину? Ви не можете зрозуміти, що з дизайном знизу вгору. Але якщо ви збираєтеся побудувати ліве переднє колесо, ви можете подумати, що згодом вам можуть знадобитися більше коліс, як для цього проекту, так і для інших. А якщо ви будуєте колесо для багаторазового використання, у вас буде чотири за ціну одного. (І 18 для того причепа-трактора, який ви будуєте поруч, і все безкоштовно.)

Зауважте, що на відміну від справжніх автомобілів та справжніх коліс, якщо ви створили одне програмне "колесо", ви створили нескінченну кількість їх.

Детальніше про дизайн зверху вниз: хоча ви повинні почати з цього, я відчуваю обов'язок зазначити, що якщо ви не можете створити колесо, вам потрібно це дізнатися, перш ніж робити велику роботу над своїм автомобілем. Тому вам потрібно працювати знизу вгору майже паралельно з роботою зверху вниз. Крім того, знаючи, що ти можеш побудувати колесо, може підказати безліч проектів, про які б ти не думав раніше, як трактор-причіп. Я думаю, що підхід зверху вниз повинен домінувати, але з дуже легким дотиком.

Отже, щоб перефразовувати Пола Ґрема, в ідеалі, коли ви пишете програму, ви отримуєте багато частин для багаторазового використання, які можуть заощадити багато часу як на оригінальній програмі, так і на інших. Щоб трохи відстатися від Пола Грема, це працює будь-якою мовою (хоча деякі заохочують цей процес більше, ніж інші).

Ворогом цього майже магічного процесу є програмісти з дуже короткотерміновими перспективами. Це може бути наслідком вад особистості, але частіше від перемикання робочих місць і занадто швидко реагує як всередині, так і між компаніями, що працюють.


Нічого, мені відповіли 16 лютого, і в папці "Вхідні" нічого не було. Я згоден з вами, завжди потрібно мати план, навіть дуже легкий, а потім трохи скласти, а потім уточнити план. Це цілком розумно. Однак я, здається, не розумію, чому багато розробників люблять планувати все в голові під час написання коду. Досить багато часу можна заощадити, і вони можуть зосередитись на тому, щоб більше працювати над реальною проблемою, а не тривалим рефактором архітектури коду під час процесу впровадження.
Amumu

@Amumu Однією з причин планування під час написання: Деякі програмісти знають так багато про те, що вони роблять на клавіатурі та миші - це вузьке місце кодування, а не процес планування. (Код для багаторазового використання дозволив би їм зробити нову, творчу роботу, яка дозволить мислення знову бути важкою частиною.)
RalphChapin

@Amumu Ще одна причина планування під час написання: з деякими комбінаціями мови / програміста / проблеми мова є найкращим способом думати про проблему. Мова - це найпростіший спосіб викласти свої думки на «папір». Я тут і там про Лісп читав лише невеликі шматочки, але, підозрюю, це особливо добре для цього. (Деякі мови вперше були створені як спосіб висловити проблему, а не отримати машину для її вирішення.) Якщо так просто переставити свій код, як і ваші думки, може також кодуватись. Але програміст, мова та проблеми повинні добре поєднуватись, щоб це працювало.
РальфЧапін

Це надійно. Ідея планування полягає в розділенні доменних знань та ідентифікацій взаємозв'язку між доменними концепціями до фактичного процесу програмування. Уявіть, якщо клас використовується десятками інших класів, не маючи чіткого плану створення інтерфейсу для спілкування з іншими класами, ми можемо легко потрапити в інтеграцію та рефакторинг пекла. У цьому випадку витрачений час на введення та реструктуризацію коду значно перевищує час, витрачений на ідентифікацію на папері.
Amumu

Візьмемо приклад. Припустимо, ми пишемо заявку клієнт / сервер. Перше, що нам належить визначити протокол, визначивши обмінні повідомлення, як повідомлення викладається в пам'ять (тобто заголовок 16 байт, id 4 байти ....). Діаграма не дорівнює моделюванню / плануванню: abstratt.com/blog/2009/05/03/on-code-being-model . Нам не потрібно використовувати UML або діаграму для моделювання, оскільки UML в значній мірі зосереджується лише на OOP, а витрачений час на введення діаграми класу UML не менше, ніж введення фактичного коду, якщо не більше.
Amumu

1

Що не так із підходом зверху вниз у поєднанні з ітераційним розвитком?

Використання підходу зверху вниз при ітераційній розробці не забезпечує жодного робочого коду в перших ітераціях. Він доставляє проектні документи та такі, про які замовнику буде важко з відгуками. Відповіді на кшталт "так, я думаю (це для мене занадто абстрактно)" не допоможуть тобі в подальшому уточнення специфіки потрібної системи клієнтом.

Натомість ви створюєте лише загальний огляд того, що вимагається. (Вимоги) використовувати як загальну інструкцію щодо того, що визначає готовий продукт і що заслуговує на пріоритет для реалізації. Звідти ви створюєте робочі продукти для кожної ітерації, з якою клієнт може насправді іграти, щоб побачити, чи це було на увазі. Якщо ні, то це не буде проблемою, оскільки не було витрачено сотні годин на розробку системи, яка працює на відміну від того, що запитує зараз замовник.

Пол Грехем спонукав будувати повністю знизу вгору? Або просто запрограмуйте його знизу вгору, але не аналіз вимог / фаза розробки?

Я не буду говорити за іншу людину. Також я не читав його реферату. Відповідь, яку я вам даю, випливає з моєї освіти, а також досвіду.

Це означає, що під час написання програми в Ліспі ви отримуєте загальний інструмент, який можна використовувати для написання подібних програм оригіналу, чи не так?

Використання цього підходу означає, що ви отримаєте більш абстрактні будівельні блоки. Просто тому, що вам доведеться створити окремі підсистеми, які можна представити відразу, ви не можете створити конструкцію зверху вниз, яка сильно переплетена і повинна бути реалізована відразу. Це покращує повторну користування, ремонтопридатність, але найбільше дозволяє більш гнучко реагувати на зміни.


1
На мої очі, жирний шрифт непотрібний, коли ви вже блокуєте цитування…
mk12
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.