qpc8

Loading...

Чому більшість кастомного програмного забезпечення стає непідтримуваним через 12 місяців

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

Kevin Kulcsar··8 min read

Обрив через дванадцять місяців

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

Через дванадцять місяців щось потрібно змінити. Нова функція. Інтеграція. Виправлення для робочого процесу, що більше не відповідає реальності. І раптом те, що мало зайняти дні, займає тижні. Те, що мало коштувати 500 EUR, коштує 5 000 EUR. Прості зміни ламають непов'язаний функціонал.

Це не невезіння. Це передбачувано. І причина — майже завжди одні й ті самі патерни.

Патерн 1: Відсутність документації (Проблема "Все в мене в голові")

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

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

Що губиться:

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

Рішення: Документація не є опціональною. Як мінімум: README, що пояснює налаштування, огляд архітектури та коментарі в коді для неочевидних рішень. Це забирає приблизно 10% додаткового часу під час розробки, але економить 500% під час підтримки.

Патерн 2: Нашарування функцій без рефакторингу

Версія 1 мала три функції. Архітектура прекрасно підтримувала три функції.

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

Що відбувається:

  • Функції розростаються з 20 до 200 рядків
  • Файли перетворюються на звалища слабко пов'язаного коду
  • Управління станом стає хаотичним і непередбачуваним
  • "Тимчасові" хаки стають постійними елементами
  • Нові функції вимагають змін у 15 файлах замість 2
Результат: Система перетворюється на мінне поле. Досвідчені розробники бояться її чіпати. Нові не можуть її зрозуміти. Кожна зміна ризикована.

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

Патерн 3: Залежності як міни

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

Що йде не так:

  • Вразливості безпеки вимагають термінових оновлень
  • Оновлення ламають сумісність з іншими залежностями
  • Застарілі пакети перестають отримувати безпекові патчі
  • Різні пакети потребують конфліктуючих версій спільних залежностей
  • Мажорні оновлення вимагають змін коду по всьому застосунку
Хронологія:

Місяць 1: Все працює, залежності актуальні. Місяць 6: Кілька пакетів застарілі, термінових проблем немає. Місяць 12: Декілька пакетів мають відомі вразливості, оновлення потребують каскадних змін, деякі пакети застаріли. Місяць 18: Оновлення чого-небудь — це багатоденний проєкт з непередбачуваними наслідками.

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

Патерн 4: База даних відрощує зуби

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

Потім вимоги змінилися. Нові поля додавалися. Старі неможливо було видалити (щось може від них залежати). Зв'язки, що здавалися зрозумілими, стали неоднозначними.

Типові симптоми:

  • Таблиці з 50+ стовпцями, більшість рідко використовуються
  • Поля з назвами new_status та actual_status, тому що зміна оригіналу була занадто ризикованою
  • Запити, що з'єднують 8 таблиць для відповіді на прості питання
  • Неузгоджені дані через зміни правил валідації при збереженні старих записів
  • Загадкові nullable-поля, призначення яких ніхто не пам'ятає
Результат: Запити до бази даних стають вузькими місцями продуктивності. Проблеми цілісності даних накопичуються. Прості звіти вимагають складних агрегацій.

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

Патерн 5: Тести, що не тестують

Система має тести. Тести проходять. Система все одно ламається.

Що насправді відбувається:

  • Тести перевіряють, що код виконується, а не що він дає правильний результат
  • Тести написані для ідеальних сценаріїв, ніколи для граничних випадків
  • Інтеграційні тести мокають настільки багато, що не тестують інтеграцію
  • Тести ламаються при будь-яких змінах коду, тому розробники перестають їх запускати
  • Метрики покриття підроблені (100% покриття з безглуздими ассертами)
Результат: Хибна впевненість. Зміни деплояться, бо тести проходять. Баги знаходять користувачі. Довіра до тестового набору зникає.

Рішення: Тестуйте поведінку, а не реалізацію. Пишіть тести, що виявили б реальні баги, які ви бачили. Підтримуйте тести як production-код. Видаляйте тести, що не виявляють реальних проблем.

Патерн 6: Розбіжність середовищ

Розробка працює. Стейджинг працює. Продакшен ламається.

Чому це трапляється:

  • Розробка працює на іншій версії ОС
  • Стейджинг має менше пам'яті/CPU, ніж продакшен
  • Змінні середовища різняться непомітно
  • Продакшен має патерни даних, яких немає в тестових середовищах
  • Кешування поводиться інакше під реальним навантаженням
Результат: "На моїй машині працює" стає мемом, тому що це постійно правда. Дебаг production-проблем вимагає відтворення середовищ, які ніхто повністю не розуміє.

Рішення: Контейнеризуйте. Використовуйте однакові Docker-образи у всіх середовищах. Автоматизуйте налаштування середовища. Тестуйте з production-подібними обсягами даних.

Патерн 7: Відсутній bus factor

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

Ризик:

  • Ця людина стає вузьким місцем для всіх рішень
  • Коли вона недоступна, прогрес зупиняється
  • Коли вона йде, інституційне знання йде з нею
  • Вона накопичує "незадокументовані рішення", що стають мінами
Результат: Майбутнє системи залежить від єдиної точки відмови. І ця людина врешті рухається далі — всі це роблять.

Рішення: Парне програмування. Code review, що дійсно передає знання. Вимоги до документації. Перехресне навчання. Жодної одноособової власності на критичні системи.

Як насправді виглядає "підтримуваний" софт

Підтримуваний софт — це не ідеальний софт. Це софт, де:

1. Новий розробник може розібратися за дні, а не тижні. Структура очевидна. Конвенції послідовні. Документація існує.

2. Зміни локалізовані. Модифікація функції X не ламає функції Y та Z. Межі між компонентами чіткі.

3. Залежності керовані. Оновлення не каскадують непередбачувано. Є чіткий процес підтримки актуальності.

4. Тести виявляють реальні проблеми. Коли тести проходять, команда має реальну впевненість. Коли тести падають, збій вказує на реальну проблему.

5. Середовища відтворювані. Налаштування розробки — за скриптом. Стейджинг відповідає продакшену. Деплої передбачувані.

6. Знання розподілені. Кілька людей можуть вносити зміни. Документація фіксує рішення.

Чому це постійно повторюється

Патерн повторюється через невідповідність стимулів:

Під час розробки:

  • Швидкість винагороджується
  • Працюючі функції видимі
  • Документація невидима
  • Технічний борг невидимий
  • Бюджет фіксований
Під час підтримки:
  • Швидкість залежить від якості коду
  • Кожен "зріз" стає видимим
  • Відсутня документація блокує прогрес
  • Технічний борг вимагає оплати
  • Бюджет на "прибирання" важко обґрунтувати
Розробники, що будують систему, часто не ті, хто її підтримує. Бізнес, який платить за функції зараз, не відчуває біль підтримки потім. Усі діють раціонально в межах своїх обмежень — а система передбачувано деградує.

Як ми будуємо в QPC8

У QPC8, підтримуваність — не опціональна. Кожна система, яку ми випускаємо, дотримується одних і тих самих принципів:

Документація — частина постачання. Ми не вважаємо проєкт завершеним, доки README не пояснює налаштування, архітектура не задокументована, а деплоймент не описаний у скрипті.

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

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

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

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

Результат: системи, що залишаються здоровими з часом. Клієнти, які можуть вносити зміни, не натрапляючи на міни. Програмне забезпечення, що залишається активом, а не зобов'язанням.

Вартість правильного підходу

Побудова підтримуваного ПЗ коштує більше на старті. Можливо, на 20-30% більше за найшвидшу можливу постачання.

Але:

  • Підтримка на 2-й рік на 50% дешевша
  • Модифікації на 3-й рік на 70% дешевші
  • Система може еволюціонувати замість заміни
  • Внутрішні команди можуть працювати без зовнішньої допомоги
  • Ви можете змінити вендора без початку з нуля
Бізнеси, що будують найдешевшу можливу V1, часто платять за неї тричі: раз за початкову розробку, раз за екстрені виправлення і раз за остаточну заміну.

Бізнеси, що інвестують у якість на старті, платять один раз та ітерують.

Запитання, які варто поставити розробникам

Якщо ви оцінюєте розробку ПЗ (або підтримуєте існуюче), запитайте:

1. Як мені налаштувати середовище розробки? Якщо відповідь займає більше 10 хвилин — є проблема.

2. Покажіть мені документацію. Якщо її немає — ви залежите від усного знання.

3. Коли ви востаннє оновлювали залежності? Якщо відповідь "при запуску" — у вас бомба сповільненої дії.

4. Що буде, якщо ви потрапите під автобус? Якщо ніхто інший не може підтримувати систему — у вас єдина точка відмови.

5. Як задеплоїти зміну? Якщо процес не задокументований і не автоматизований — кожен деплой ризикований.

Відповіді розкажуть, чи ваше ПЗ є активом чи зобов'язанням.

---

QPC8 будує production-системи, спроєктовані для довгострокової підтримуваності. Дивіться наші реалізовані системи або налаштуйте свій проєкт.

програмна інженеріятехнічний боргпідтримуваністьякість кодуархітектура2025

Need this built?

We build production systems that implement these concepts. Get transparent pricing on your project.

Configure Your System →

Related Posts

Web Systems

Чому більшість SaaS-бекендів не витримують масштабування

Типові архітектурні помилки, що вбивають SaaS-продукти при зростанні. Як будувати бекенди, що витримують 10-кратне навантаження без переписування.

Web Systems

Дешева веб-розробка на Коста дель Соль — що ви реально отримуєте за €290

Шукаєте дешеву веб-розробку на Коста дель Соль? Ось що саме ви отримуєте за €290 — справжній Next.js сайт, а не WordPress-катастрофу.

Web Systems

Найдешевший професійний вебсайт у Малазі — чому €290 краще за безкоштовно

Безкоштовні конструктори сайтів обіцяють все. Ось чому професійний Next.js сайт за €290 перевершує їх усіх — і реально допомагає вашому бізнесу в Малазі рости.