Скільки моделей дизайну та рівнів абстракції необхідні? [зачинено]


29

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

Розробники, з якими я працюю, по-різному програмують ці питання.

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

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

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

Наприклад, коли загальний шар кешування записується за допомогою Memcache. Чи дійсно нам потрібно Memcache, MemcacheAdapter, MemcacheInterface, AbstractCache, CacheFactory, CacheConnector, ... або це легше підтримувати і по- , як і раніше хороший код при використанні тільки половина з цих класів?

Знайдено це у Twitter:

введіть тут опис зображення

( https://twitter.com/rawkode/status/875318003306565633 )


58
Якщо ви ставитесь до моделей дизайну як до речей, які витягуєте з відра і використовуєте для збирання програм, ви використовуєте занадто багато.
Blrfl


5
Ви можете подумати про це зразки дизайну, як мовленнєві шаблони людей. Тому що в певному сенсі ідіоми, метафори тощо - це все дизайнерські зразки. Якщо ви використовуєте ідіому в кожному реченні ... це, мабуть, занадто часто. Але вони можуть допомогти з’ясувати думки та допомогти зрозуміти, що в іншому випадку буде довгою прозою. Насправді не є правильним способом відповісти «як часто я повинен використовувати метафори?» - це залежить від судження автора.
Прем'єр

8
Немає можливості, щоб одна відповідь на ІП могла адекватно висвітлити цю тему. На це потрібно буквально багато років досвіду та наставництва, щоб впоратися. Це явно занадто широко.
jpmc26

5
Дотримуйтесь основного принципу проектування в авіаційній галузі: "Спростіть і додайте більшої легкості". Коли ви виявите, що найкращий спосіб виправити помилку - це просто видалити код, що містить помилку, оскільки він все ще не робить нічого корисного, навіть якщо він був без помилок, ви починаєте правильно розробляти дизайн!
алефзеро

Відповіді:


52

Скільки інгредієнтів потрібно для їжі? Скільки деталей потрібно для створення транспортного засобу?

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

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

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


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

Кількість абстракцій навіть не буде однаковою для різних частин одного проекту!
Т. Сар - Відновлення Моніки

Підказка: перехід від Memcache до іншого механізму кешування (Redis?) - це зміна реалізації .
Огр Псалм33

Ваші два правила (вказівки, як би ви їх не хотіли називати) не працюють, як показав Тулан. Вони також жахливо неповні, навіть якщо вони це зробили. Інша частина публікації - це невідповідь, яка говорить трохи більше, ніж ми не можемо дати відповідь на обґрунтованому рівні. -1
jpmc26

Я б стверджувати , що в разі двох інтерфейсів і сотні класів , що реалізують їх, цілком можливо , були перевантажені ваші абстракції. Я, звичайно, бачив це в проектах, які використовують багаторазове абстрагування в багатьох місцях ( interface Doer {void prepare(); void doIt();}), і рефактор стає болючим, коли ця абстракція більше не підходить. Ключова частина відповіді - тест застосовується тоді, коли абстракція повинна змінитися - якщо це ніколи не відбувається, вона ніколи не завдає болю.
James_pic

24

Проблему з дизайнерськими візерунками можна підсумувати прислів’ям "коли ти тримаєш молоток, все виглядає як цвях". Акт застосування шаблону проектування не поліпшується вашої програми взагалі. Насправді я б заперечував, що ви робите складнішу програму, якщо додаєте шаблон дизайну. Залишається питання, чи вдало ви використовуєте схему дизайну чи ні, і це суть питання, "Коли у нас занадто багато абстракцій?"

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

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

TL; DR Думаю, що мета абстракції сама по собі не є абстрактною. Це слугує дуже практичною метою у вашій програмі, і перш ніж ви вирішите скористатися схемою дизайну або створити інтерфейс, ви повинні запитати себе, чи так це програма легше зрозуміти, незважаючи на додаткову складність чи програма є більш надійною незважаючи на додаткову складність (бажано обидва). Якщо відповідь «ні» чи «може», то задумайте кілька хвилин, щоб розглянути, чому ви хотіли це зробити, і якщо, можливо, це можна зробити краще, а не обов’язково додавати абстракцію до свого коду.


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

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

Я хочу армію навчених білочок для мого горіха.
icc97

6

TL: DR;

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

Довга відповідь

Швидше за все, ви ніколи не дізнаєтеся, на якому рівні абстракцій ви будуєте.

Більшість рівнів абстракції для нас непомітні, і ми приймаємо їх як належне.

Саме міркування призводить мене до такого висновку:

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

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

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


2
"Швидше за все, ви ніколи не дізнаєтеся, на якому рівні ви будуєте абстракції". - Насправді, вся суть абстракції полягає в тому, що ви не знаєте, як вона реалізована, IOW ви не знаєте (і не можете ) знати, скільки рівнів абстракцій вона приховує.
Йорг W Міттаг

4

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

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

  • Ви хочете, щоб абстракції в природних точках інтерфейсу мінімізували їх розмір.

  • Ви не хочете їх змінювати.

  • Ви хочете, щоб вони розділили речі, які можуть бути незалежними.

  • Мати одного в неправильному місці - це гірше, ніж його не мати.

  • Вони не повинні мати великих протікань .


4

Рефакторинг

Я не бачив слова "рефакторинг", яке згадувалося жодного разу досі. Отже, ось ми:

Сміливо реалізуйте нову функцію якомога прямо. Якщо у вас є лише один, простий клас, вам, швидше за все, не потрібен інтерфейс, суперклас, фабрика тощо.

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

Візерунки - це інструмент розуму

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

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

Бібліотеки

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


2

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

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

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

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

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


Наприклад, коли загальний шар кешування записується за допомогою Memcache. Чи справді нам потрібні Memcache, MemcacheAdapter, MemcacheInterface, AbstractCache, CacheFactory, CacheConnector, ... чи це простіше у підтримці та ще хороший код, коли використовується лише половина цих класів?

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


2

Абстракція призначена для полегшення розуміння коду. Якщо шар абстракції зробить речі більш заплутаними - не робіть цього.

Метою є використання правильної кількості абстракцій та інтерфейсів для:

  • мінімізувати час розробки
  • максимізувати ремонтопридатність коду

Анотація лише за потреби

  1. Коли ви виявите, ви пишете супер клас
  2. Коли це дозволить значно використати код
  3. Якщо абстрагування зробить код, він стане значно зрозумілішим та легшим для читання

Не абстрагуйте коли

  1. Це не матиме переваги в повторному використанні коду або чіткості
  2. Це зробить код значно довшим / складнішим без користі

Деякі приклади

  • Якщо у вас буде лише один кеш у всій вашій програмі, не абстрагуйтесь, якщо ви не думаєте, що ви, ймовірно, отримаєте суперклас
  • Якщо у вас є три різних типи буферів, використовуйте загальний інтерфейс для всіх

2

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

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

У вас є конкретний сценарій. Організуйте свій код таким чином. Ось розумний, але дещо надуманий приклад.

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

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

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

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

Саме в такі часи пророчий голос Майка Актона, ігрового двигуна при безсонні, кричить мені в голову:

ЗНАЙТЕ СВОЇ ДАНІ

Він говорить про вхідні дані у вашу програму та бажані результати. І ось ось цей дорогоцінний камінь Фреда Брукса з Міфічного місяця людини:

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

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

  • Чи правильні вихідні дані з моєї програми?
  • Чи виробляється це ефективно / швидко для мого найпоширенішого випадку введення?
  • Чи мій код достатньо простий для локальних причин як для мене, так і для моїх товаришів по команді? Якщо ні, то чи можу це зробити простіше?

Коли ви це зробите, на питання "скільки шарів абстрагування або моделей дизайну потрібно" стає набагато простіше відповісти. Скільки шарів абстракції вам потрібно? Стільки, скільки потрібно для досягнення цих цілей, і не більше. "Що з моделями дизайну? Я жодного не використовував!" Ну а якщо вищезазначені цілі були досягнуті без прямого застосування шаблону, то це добре. Зробіть це так, щоб перейти до наступної проблеми. Почніть зі своїх даних, а не з коду.


2

Архітектура програмного забезпечення - це винахід мов

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

Цей погляд допомагає мені при вирішенні архітектурних питань.

Читабельність

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

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

Концепції, які ви виставляєте, не повинні містити сюрпризів. Це в основному іменування таких конвенцій, як get-and set-method і т.д. Але якщо просто інстанціювання конкретного класу виконує цю роботу, я б вважав за краще це.

Корисність

Мова повинна бути простою у використанні (полегшуючи формулювання "правильних речень").

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

Викриття лише необхідних класів / методів полегшує вашому користувачеві пошук того, що йому потрібно (див. Цитату DocBrowns Антуана де Сент-Екзюпері). Розкриття інтерфейсу замість класу реалізації може зробити це простіше.

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

Підсумок

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

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


1

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

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


-1

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

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


2
Давайте утримаємось від того, щоб відхиляти цей досвід як "фальшивий". Занадто багато абстракцій - справжня проблема. На жаль, люди додають абстракції наперед, тому що "найкраща практика", а не вирішення реальної проблеми. Також ніхто не може вирішити "про ці речі" ... люди покидають компанії, люди приєднуються, ніхто не бере власності на їх грязь.
Rawkode
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.