Радикальний підхід до організації коду та контролю версій

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

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

Я частково вже використовував цей підхід і він дуже добре себе проявив. Наприклад, коли більшість розробників просто додали б нове поле до існуючої таблиці/реляції, я створював окрему таблицю та відповідну їй так звану ActiveRecord “модель”. Така гранулярність дозволяла тримати “моделі” досить простими та зрозумілими, а також дозволяла без блокувань та навантажень на СУРБД мігрувати та відкатувати назад схему даних.

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

Усі версії файлу зберігаються у проєкті, а система побудови за замовчуванням використовує останні версії файлів. Наприклад, якщо деяку особливість/вимогу можна помістити у файл orderConfirmation.js, то тепер це має бути orderConfirmation/20230526032334-<version comment, JIRA task number, etc.>.js чи щось типу того. Усі версії усіх файлів існують одночасно і зовсім немає необхідності подорожувати по історії т.з. комітів, аби вивчити еволюцію того чи іншого файла.

Якщо якийсь файл/feature необхідно прибрати з усіх зборок, то можна створити нову версію файла з розширенням *.disabled, наприклад: orderConfirmation/202305040221-disable_orderConfirmation(PFX-10376).disabled, що буде повідомляти нашу систему побудови про необхідність ігнорування компонента processOrder. При необхідності ми можемо явно задавати системі побудови конкретні версії файлів, навіть якщо якісь із них були позначені як disabled, адже намір явний, а усі явні наміри мають бути дозволені.

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

Типовий приклад такого анти-патерну в організації коду – т.з. “товсті моделі”, що дуже характерні для проєктів на Ruby on Rails, і не тільки. І в проєктах на Ruby/Rails і в проєктах на Golang та JavaScript я безліч разів бачив “моделі”(сутності) User, які взаємодіють майже з усіма іншими сутностями та налічують іноді декілька тисяч строк коду.

Якщо Ви облаштовуєте склад чи певну систему зберігання, то це хороша ідея зберігати шурупи та саморізи окремо, але не всі шурупи чи саморізи мають зберігатися разом. Вони мають бути розділені ще по розмірам, матеріалу, покриттю, кольору і т.д. Тільки уявіть, що Ви приходите у магазин купиту саморізів аби побудувати дах із металочерепиці. Замість того, аби просто дати Вам три коробки по 100 штук, продавець пірнає у басейн з саморізами самого різного типу і по одному відшукує ті, що Вам необхідні. Хіба таке виконання роботи може бути ефективним? – Ні! Тоді чому таким чином виглядає код майже усіх проєктів?!

Хороша архітектура – це коли додати зміни так же легко, як додати новий файл.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *