Абстракція: Війна між вирішенням проблеми та загальним рішенням [закрито]


33

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

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

Тоді цей голос в моїй голові каже, просто вирішити проблему манекен його так просто! Навіщо витрачати більше часу, ніж потрібно?

Ми всі зіткнулися з цим питанням, коли абстракція стоїть на правому плечі, а ліворуч - ліве.

Кого слухати і як часто? Яка ваша стратегія для цього? Чи слід все абстрагувати?


1
"Як абстрактний і як загальний", як правило, відомий як обрив програміста :) Однак, через закон Мерфі, одна ступінь адаптації, яка вам знадобиться при роботі над наступним завданням, буде тією, яку ви не надали.
Матьє М.

1
Одне з найкращих питань коли-небудь!
explorest

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

Відповіді:


27

Кого слухати і як часто?

Ніколи не абстрагуйтесь, поки не повинні.

Наприклад, у Java потрібно використовувати інтерфейси. Вони - абстракція.

У Python у вас немає інтерфейсів, у вас Duck Typing, і вам не потрібні високі рівні абстракції. Так що ви просто цього не робите.

Яка ваша стратегія для цього?

Не абстрагуйтесь, поки ви не написали це три рази.

Один раз - добре - один раз. Просто вирішіть це і рухайтеся далі.

Двічі - це вказівка ​​на те, що тут може бути візерунок. Або не може. Це може бути просто збіг.

Тричі - це початок візерунка. Тепер це виходить за збіг обставин. Тепер ви можете успішно абстрагуватися.

Чи слід все абстрагувати?

Ні.

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

Це зазвичай дозволяє мені повторно використовувати свій код

Це припущення, яке часто хибне. Абстракція може зовсім не допомогти. Це можна зробити погано. Тому не робіть цього, поки не обов’язково.


1
"Ніколи не абстрагуйся, поки не повинен". - Я вважаю, ви уникаєте використання класів, методів, циклів, або якщо заяви? Ці речі - це все абстракції. Якщо ви думаєте над цим, код, написаний мовами високого рівня, дуже абстрактний, подобається вам це чи ні. Питання не в тому, чи абстрактно. Це які абстракції використовувати.
Джейсон Бейкер

9
@ Джейсон Бейкер: "Я вважаю, ви уникаєте використання класів, методів, циклів, або якщо заяви". Мабуть, не про це йшлося. Чому варто абсурдно стверджувати, що все програмування неможливо, якщо ми уникаємо занадто абстрагувати свої дизайни?
С.Лотт

1
Мені пригадується старий анекдот, де чоловік запитує жінку, чи спить вона з ним за мільйон доларів. Коли вона каже так, він запитує, чи вона спить з ним за п’ять доларів. Коли вона каже: "За яку жінку ти мене береш?" відповідь "Ну, ми вже встановили, що ви будете спати з кимось для сексу. Зараз ми просто тормозимо ціну." Моя думка, що ніколи не йдеться про рішення абстрактно чи ні. Йдеться про те, скільки абстрагувати та які абстракції вибрати. Ви не можете вибрати відмову від абстракції, якщо ви не пишете чисту збірку.
Джейсон Бейкер

9
@ Джейсон Бейкер: "Ви не можете вибрати відмову від абстракції, якщо ви не будете писати чисті збори" Це тривіально неправдиво. Збірка - це абстракція над машинною мовою. Що є абстракцією над апаратними схемами. Будь ласка, перестаньте занадто багато читати відповідь, яка не була в першу чергу під питанням. Питання полягало не в тому, що "Абстракція" як концепція чи інтелектуальний інструмент. Йшлося про абстракцію як техніку проектування ОО - неправильно застосовується - занадто часто. Моя відповідь була не в тому, що абстрагування неможливе. Але це "над абстракцією" - це погано.
С.Лотт

1
@JasonBaker - це не нечувана причина спати з кимось. Можливо, ви думали про "гроші"?

19

Ах, ЯГНІ. Найбільш зловживана концепція програмування.

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

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

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

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


Приємна відмінність між simpleі easy!
Матьє М.


"Але мій досвід полягає в тому, що мало компаній", - що цікаво, навпаки може бути правдою в наукових колах.
Стів Беннетт

12

Силогізм:

  1. Загальність дорога.

  2. Ви витрачаєте чужі гроші.

  3. Тому витрати на загальність повинні бути виправдані для зацікавлених сторін.

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

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

І нарешті, не існує такого поняття, як "максимально загальне". Припустимо, ви пишете програмне забезпечення на C #, просто заради аргументу. Ви збираєтесь змусити кожен клас реалізувати інтерфейс? Кожен клас абстрактний базовий клас з кожним методом абстрактний метод? Це досить загально, але він ніде не є "таким загальним", як це можливо. Це просто дозволяє людям змінити реалізацію будь-якого методу через підкласифікацію. Що робити, якщо вони хочуть змінити реалізацію методу без підкласингу? Ви можете зробити кожен метод фактично властивістю типу делегата, із сетером, щоб люди могли змінити кожен метод на щось інше. Але що робити, якщо хтось хоче додати більше методів? Тепер кожен об'єкт має бути розширеним.

У цей момент вам слід відмовитися від C # і прийняти JavaScript. Але ви все ще не дісталися ніде поблизу досить загального; що робити, якщо хтось хоче змінити, як шукає член для цього конкретного об'єкта? Можливо, вам слід написати все на Python.

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


2
+1 за корисні принципи, -1 за те, щоб заробити все про гроші.
Мейсон Уілер

4
@ Мейсон: Справа не в грошах , а в зусиллях . Гроші - це практична міра зусиль . Ефективність - це переваги, накопичені за зусилля, що виробляються; знову ж таки, прибуток у грошах - це практична міра нарахованих виплат . Простіше обговорити абстракцію грошей, ніж придумати якийсь спосіб виміру зусиль, витрат і вигоди. Чи хотіли б ви міряти зусилля, витрати та вигоду якось іншим способом? Не соромтеся зробити пропозицію кращого способу.
Ерік Ліпперт

2
Я згоден з точкою @Mason Wheeler. Я знаходжу тут рішення - не залучати зацікавлених сторін до цього рівня проекту. Це, очевидно, сильно залежить від галузі, але клієнти зазвичай не бачать код. Також усі ці відповіді здаються анти-зусиллями, здаються ледачими.
Увімкнення

2
@Orbling: Я рішуче проти непотрібних, дорогих, марних зусиль, які відбирають ресурси у гідних та важливих проектів. Якщо ви припускаєте, що це робить мене "ледачим", то я стверджую, що ви використовуєте слово "ледачий" незвично.
Ерік Ліпперт

1
На мій досвід, інші проекти, як правило, не зникають, тому зазвичай варто вкласти стільки часу, скільки потрібно в поточному проекті, перш ніж рухатися далі.
Увімкнення

5

Щоб було зрозуміло, зробити щось узагальнене і здійснити абстракцію - це дві різні речі цілком.

Наприклад, розглянемо функцію, яка копіює пам'ять.

Функція - це абстракція, яка приховує, як копіюються 4 байти.

int copy4Bytes (char * pSrc, char * pDest)

Узагальнення змушує цю функцію копіювати будь-яку кількість байтів.

int copyBytes (char * pSrc, char * pDest, int numBytesToCopy)

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

Більш конкретно, пов'язане з вашим запитанням, Абстракція корисна не лише з точки зору повторного використання коду. Часто, якщо це зробити правильно, це зробить ваш код більш читабельним і доступним для обслуговування. Використовуючи наведений вище приклад, що простіше читати та розуміти, якщо ви переглядаєте код copyBytes () або цикл, що ітераціює через масив, що переміщується, по одному індексу? Абстракція може надати своєрідну документацію, яка, на мою думку, полегшує роботу з кодом.

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


+1 для визначення різниці між абстракцією та узагальненням.
Йоріс Мейс

4

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

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


1
Це дуже схоже на мою версію Правила рефакторингу: страйк два! рефактор!
Френк Шірар

@Frank: Це, мабуть, ваше правило рефакторингу, але з другого пункту додано з особистого досвіду.
Ларрі Коулман

+1: Я вважаю, що це також відзначається досить рано в Прагматичному програмісті майже дослівно IIRC.
Стівен Еверс

о, безумовно. Нічого не можна абстрагувати лише одним прикладом: як тільки у вас є другий приклад, ви можете побачити, що є загальним (спільним), а що ні, і ви можете абстрактно відірватися!
Френк Шірар

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

2

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

По-перше: Передчасна загальність дорога.

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

По-третє: тримайте політику подалі від своїх механізмів.


1

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

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


0

Я великий фанат принципу KISS.

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


Чому неприязнь до перфекціонізму? (Я, до речі, не проголосував вас)
забороняється

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

-1

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

Я не згоден з "вирішити це дурно" , я вважаю, що це може бути і "вирішити розумно" .

Що розумніше:

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

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

Узагальнене рішення повинно бути лише тоді, коли вам відомо, що це щось, що буде використано у кількох різних проектах / випадках.

Зазвичай я вважаю, що узагальнені рішення найкраще подаються як "Основний бібліотечний код"


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

@Jeff Я не зовсім впевнений, що я розумію твій коментар ..
Darknight

Ви вивели "Розв’яжи дурне" поза контекстом.
Брайан Харрінгтон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.