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


11

Це досить розпливчасте запитання, але це те, на що я ніколи не відчував відповіді задовільно, читаючи про належний дизайн.

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

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

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

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

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

Зокрема, проблема, з якою я стикаюсь, що привела мене до форумів, така: я працював над впровадженням інтерпретованої мови програмування (реалізованої в D, але це не актуально), і я вирішив, що аргументи моїх завершень повинні бути на основі ключових слів, а не позиційних, як вони є. Це потребує зміни всього існуючого коду, який викликає анонімні функції, що, на щастя, є досить малим, тому що я рано починаю розвивати свою мову (<2000 рядків), але було б величезним, якби я прийняв це рішення на більш пізньому етапі. У такій ситуації, чи є спосіб, що завдяки належному передбаченню дизайну я міг би полегшити цю модифікацію, або певні (більшість) змін суттєво далекосяжні? Мені цікаво, чи це якимось чином невдача моїх власних дизайнерських навичок - якщо це так, я '

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


Я не бачу, як зміна вашої мови стосується всього іншого, крім аналізатора. Чи можете ви це уточнити?
scfridge

Мовою, що нагадує невеликі розмови, це правда, що вам потрібно буде лише змінити аналізатор, оскільки це було б простою справою foo metarg1: bar metarg2: bazяк foo.metarg1_metarg2_(bar, baz). Однак моя мова вносить більші зміни, а саме параметри на основі списку до параметрів на основі словника, що впливає на час виконання, але не на аналізатор, насправді через особливості моєї мови я зараз не заходжу. Оскільки немає чіткого відображення між аргументованими ключовими словами та позиційними аргументами, час роботи - це головне питання.
існує -протягом

Відповіді:


13

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

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

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

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

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

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


+1 за підтримку нової справи та старої справи, щоб ви могли поступово припинити роботу.
Ерік Реппен

9

Я б рекомендував вам прочитати твір " Великий бал грязі" .

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

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

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

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


1
+1: попередній дизайн роману рідко вдається. Успішні проекти - це або рекапітуляція перевірених конструкцій, або ітеративно вдосконалена.
Кевін Клайн

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

4

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

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

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

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


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

2

Не існує методології проектування, яка б врятувала вас від суттєвих змін вимог / змін. Просто неможливо уявити та врахувати всі можливі зміни, про які можна було б подумати пізніше.

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

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


1

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

Якщо що - то навпаки. Деякі зміни занадто малі, щоб набридати будь-яким «дизайном» або фантазійним мисленням. Наприклад, прості виправлення помилок.

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

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


3
Вихідна позиція також може бути негативною. Не варто недооцінювати силу Спадщини :)
Маглоб

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

1

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

У вашому прикладі, правильна конструкція вже полегшила вашу роботу: потрібно вносити зміни протягом 2000 рядків кодової бази, а не 20000 або 200000 рядків кодової бази.

Правильна конструкція зменшує значні зміни, але не усуває їх.

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


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