Чи слід оновлювати старіший код, щоб використовувати новіші мовні конструкції, чи слід дотримуватися застарілі конструкції?


15

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

Повинен я:

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

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

Відповіді:


10

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

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

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

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


1
Я частково не згоден. Ми повинні слідувати принципу відкритого закриття. Тому ми повинні намагатися максимально ізолювати новий код, і в той же час написати новий код з можливою останньою мовною конструкцією.
Ананд Вайдя

3
@AnandVaidya: це IMHO нереальне очікування, оскільки він передбачає, що старий код слідує за OCP або його можна легко змінити, щоб слідувати за OCP, що рідко буває у справі, або просто не вартих зусиль.
Док Браун

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

2
@AnandVaidya: коли ти не маєш на увазі OCP, ти не повинен називати це так. Я думаю, що ви дійсно маєте на увазі те, що Перо називає написання нового коду методом паростка , тож можна обмежити новий стиль коду новим відокремленим методом. Коли це можливо і розумно, ти маєш рацію, це добре. На жаль, такий підхід не завжди застосовується, принаймні, не, якщо ви хочете зберегти старий код DRY.
Док Браун

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

5

Значною мірою код і те, як він виглядає, не мають значення . Що робить код - це важливо.

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

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

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

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


4

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

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

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

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

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

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

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

Якщо вимоги змінилися, вам може знадобитися також ознайомитись із типом змін і що саме сприяє зміні. Наприклад, припустимо, що ви модифікували Git для заміни його використання SHA-1 на SHA-256. Це зміна вимог, але сфера чітко визначена і досить вузька. Після правильного зберігання та використання SHA-256 ви навряд чи зможете зіткнутися з іншими змінами, які впливають на решту бази коду.

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

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


1

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

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


1

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

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

Підсумовуючи: ваше остаточне рішення має базуватися на аналізі "витрати" / "вигоди" вашого конкретного випадку.

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