Як програмістам перестати гратися в технології за гроші бізнесу й почати писати код, що працює на продукт
«Talk is cheap. Show me the code.» — Linus Torvalds.
Привіт усім, це Вова Стельмащук, Team Lead Android дейтинг-застосунку Hily в українській продуктовій IT-компанії appflame.
Останні десять років я займаюся розробкою Android-застосунків. А останні два роки разом зі своєю командою розробляю Hily — продукт, що на ринку вже понад семи років, має більш ніж 41 мільйонів користувачів і стабільно входить у Топ-5 за кількістю завантажень у США.
З технічного боку важлива річ — ми А/В-тестуємо буквально все. Двадцять фіче флагів у будь-який момент часу — це для нас нормальний стан проєкту. Водночас весь Android-застосунок пише команда із чотирьох людей, включно зі мною.


Гортайте вбік, щоб подивитися всі зображення
За час своєї роботи я дуже часто бачив, як програмісти граються в технології за гроші бізнесу й намагаються побудувати ідеальну, але повністю відірвану від реальності архітектуру, яка не покриває потреби бізнесу. Тому сьогодні в статті я хочу розповісти, як ми в команді пишемо код, який працює на продукт — простий, читабельний і заточений під бізнес-вимоги. У статті буде:
- перелік red flags, які вказують на те, що у вашого проєкта є проблеми;
- правила, яких ми дотримуємося в команді під час написання коду: поясню, чому всі ці ідеальні архітектури та зайві інтерфейси часто тільки ускладнюють життя програмістам;
- поділюся нашими підходами до рефакторингу;
- і наостанок наведу приклади великих open-source проєктів із GitHub, проте з простою архітектурою.
Ця стаття буде корисною middle/senior розробникам і тім-лідам, які працюють у постійно мінливих продуктах і хочуть навчитися покращувати код без зупинки процесів. А також для тих, хто шукає баланс між простотою коду та бізнес-потребами. Джунам теж може бути цікаво, особливо якщо ви вже читали книжки про архітектуру, але поки не розумієте, як застосовувати знання на практиці.
Red flags, які сигналізують, що у вашого проєкта є проблеми
Red flag 1. Зміни в точці А вашого коду вимагають змін у точці B
Гадаю, усім знайома ситуація, коли ви щось поміняли в одному місці коду й раптом на іншому кінці проєкту щось відвалюється. Ви починаєте це дебажити й виявляється, що в системі був якийсь прихований стан, який неочевидно змінився і тепер кожен раз при оновленні даних X вам треба обов’язково оновлювати дані Y, щоб система й надалі працювала так, як треба.
Вам доводиться довго та нервово перевіряти, які частини коду спираються на дані, котрі ви щойно змінили, які дані залежать одне від одного, і як змінювати їх так, щоби не зламати ще щось. Це збільшує ваш time to market і кількість багів у системі й, відповідно, ускладнює вам життя.
Red flag 2. Бажання написати інструкцію до коду
Важливо не плутати документацію з інструкцією. Документація — це потрібний і важливий інструмент взаємодії між різними департаментами або різними ролями в команді. Також документація — це історичний лог прийнятих рішень.
Red flag — це інструкція або бажання її написати, коли ваш код став надто складним, заплутаним і незрозумілим для програмістів.
Писати інструкції до коду ні у якому випадку не можна, цим ви лише легалізуєте погане технічне рішення на проєкті. Прямуйте до того, щоби під час читання коду вам було одразу зрозуміло, як він працює: звідки приходять дані, що з ними відбувається, які сутності взаємодіють між собою тощо.
Виняток: ви, як команда / організація визнаєте, що якийсь шматок коду запутаний, але зараз у вас немає достатньої технічної експертизи або грошей для того, щоб зробити код простим і зрозумілим. У такому випадку у вас, фактично, немає вибору: вам треба зробити інструкцію і завести процес для її оновлення, щоб вона була актуальною у разі майбутніх змін у коді. Але це дорого й довго, тому подумайте ще раз, чи точно ви хочете залишити код у такому стані, як він є зараз.
Red flag 3. Інтерфейси
В індустрії обожнюють інтерфейси, мовляв, без них неможливо писати тести. І це мій особистий біль, бо інтерфейси не несуть ніякої користі в більшості випадках:
- сигнатура методу сама по собі є гарним контрактом. Якщо вам потрібно змінити реалізацію просто змініть її без зміни сигнатури методу;
- щоб з’явилися тести, треба писати тести, а не інтерфейси.
Ми перестали використовувати інтерфейси на проєкті, і зараз наш код лаконічніший, ніж був до цього. Плюс ми швидше почали виконувати задачі. І, чесно кажучи, — це рідкість, коли задача робиться швидше, ніж планувалося 🙂

Коментар від колеги після того, як ми перестали використовувати інтерфейси
Red flag 4. Одна архітектура на все життя
Стандартний red flag, який я часто бачу по архітектурі — це коли її вважають довічною. Умовно, команда створила проєкт, швидкоруч визначила кілька шарів архітектури та її базову структуру і вважає, що цього вистачить на роки вперед.
Але бізнес змінює вимоги кожні кілька місяців, задачі еволюціонують, і якщо архітектура залишається незмінною, це означає, що вона вже не актуальна.
Тому, якщо ви працюєте на бізнес, який часто змінюється, архітектура має змінюватися разом із бізнес вимогами. Кожна нова потреба, кожна зміна вимог повинна знайти своє відображення в коді.
Якщо ж бізнес змінюється рідко, тоді хвилюватися особливо не варто. Але бізнеси, які не змінюються, не займаються розробкою — вони купують готові рішення.
Правила, яких ми дотримуємося в команді під час написання коду
Протягом двох років ми в команді жодного разу не зупиняли бізнес-задачі заради рефакторингу. Наші бізнес-фічі продовжують активно виходити в продакшн, ми заробляємо гроші, ростимо продуктові метрики і при цьому поступово покращуємо код. Дійти до цього можна зокрема завдяки цим правилам:
- робити архітектуру під бізнес-вимоги;
- робити рефактор паралельно з бізнес-задачами та вміти працювати з «милицями».
Правило 1. Робити архітектуру під бізнес-вимоги

Індустрія нам довго обіцяла, що з появою правил із написання коду весь код одразу стане досконалим.
Перший такий майлстоун — стаття Design Principles у 2000 році, де вперше описали SOLID. Головна ідея лежала в площині п’яти правил, слідуєте ним і весь код стане чудовим. Але за 20+ років після цього поганий код нікуди не зник.
У 2012 році Річ Хіккі виступив із доповіддю Simple Made Easy (до речі, дуже рекомендую подивитися реакцію primeagen на цю доповідь) і показав, як правильно роз’єднувати залежності. Багато людей бачили цю роботу, але я так само бачив багато кепського коду після 2012 року.
І нарешті за діло взявся дядько Боб і у 2017 році випустив книжку Clean Architecture. Але його трактують по-різному, і якість коду від цього теж різниться.
(тут я опускаю такі речі, як еволюція між MVC/MVP/MVVM — вони виглядають дрібною деталлю на фоні перелічених вище подій).
Й ось ми у 2026 році. Що б ви зараз не почули або яку б книжку не прочитали, у мене є гіпотеза, що весь код у світі класним не стане. Із цієї думки випливає те, що треба вміти робити архітектуру. І, мабуть, найкраще про це писали Монсон-Хаефель і Дейкстра:
«Насправді ви не будуєте архітектуру. Архітектуру створюють бізнес-вимоги. Усе, що ви можете зробити, — це максимально ефективно підлаштувати свій код під ці вимоги.»
Тому моя порада тут така — дивіться в майбутнє, у ньому буде прийнято ваше найкраще архітектурне рішення. Як це можна зробити?
Ми всі стикалися із ситуацією, коли відкриваєш якийсь не надто старий код, наприклад,
Але що ми можемо з вами зробити зараз — це дивитися в майбутнє, оцінювати можливі сценарії розвитку продукту та розуміти, чи витримає поточний код майбутні вимоги.
Спілкуйтеся із продакт-менеджерами та дизайнерами, щоби передбачати майбутні зміни й оцінювати архітектурні ризики заздалегідь. Ці люди живуть у майбутньому, відносно нас, програмістів. Поки ми з вами робимо задачі поточного спрінта, вони вже планують наступний.
Слідкуйте за оновленнями конкурентів. Продуктові команди часто аналізують фічі в інших застосунках, щоби зрозуміти очікування користувачів й куди загалом рухається ринок. У мене на телефоні купа дейтинг-застосунків, які я час від часу переглядаю, щоби завчасно зрозуміти, які підходи з’являються в індустрії й чи готова наша архітектура до нових подібних імплементацій.
Не ускладнюйте архітектуру без причини. Будь-яку зміну, котру ви закладаєте на майбутнє, потрібно валідувати з продуктовою командою перед тим, як закладати її в архітектуру.
Наведу приклад. Раніше в нас на проєкті була база даних, яка колись у майбутньому мала знадобитися в разі, якщо в продукті з’явиться офлайн-режим. Але база даних — це маса зайвої роботи: запис у файлову систему, синхронізація даних і так далі. Я вирішив поспілкуватися з продактами й виявилося, що вони не планують додавати офлайн-режим. Тож ми замінили базу даних на Concurrent Hashmaps від Java, завдяки чому в нас впала кількість багів і знизилася battery usage. Працювати з даними in memory простіше ніж із файловою системою, хто б міг подумати 🙂
Підсумовуючи: є лише два місця де, ви можете побачити правдиві дані щодо вашого продукту — це production та майбутнє, усе інше — це гіпотези, які треба валідувати.
Правило 2. Робити рефактор паралельно з бізнес-задачами і вміти працювати з «милицями»
З кожним днем ви все більше дізнаєтеся про бізнес, про те, як він буде змінюватися, і починаєте краще розуміти, як разом із ним буде змінюватися ваш код і які проблеми в ньому можуть виникати в майбутньому.
Іноді буває так, що в команду приходить нова людина, дивиться на шматок коду й каже: «Цей код не можна прочитати — це треба рефакторити». Зазвичай я відповідаю, що теж погано читаю німецькою, але навряд чи це проблема німецької мови.
Суть у тому, що код сам по собі не говорить, чи потрібен рефакторинг. Навіть якщо ми бачимо якийсь банальний антипаттерн, наприклад, копіпасту, то це копіпаста лише в той момент часу, який ми зараз спостерігаємо. Ви не знаєте, як ці фічі розвивалися раніше і як вони будуть змінюватися в майбутньому. Тому рішення про рефакторинг треба приймати, враховуючи історію та перспективу розвитку коду, а не його поточний стан.
Що реально допомагає зрозуміти, чи потрібен рефакторинг — дивитися історію змін у Git. Одна справа, коли ви бачите дві сутності й думаєте, що це копіпаста, а інша — коли відкриваєте Git і бачите, як ці сутності змінювалися із часом.
Наприклад, ви бачите два data class, які зараз однакові, а також з Git-історії видно, що вони змінювалися синхронно — додавання і видалення однакових полів були в одних і тих самих комітах. І тоді можна зрозуміти, що це не просто копіпаста в моменті, а дійсно бізнес-сутності, які зв’язані, і програмісти зробили неправильно, коли не пов’язали їх між собою в коді. І тільки тоді, коли ви це зрозуміли, можна приймати рішення про їхнє правильне об’єднання.
Чи врятує це вас від помилок у майбутньому? Ні. Але ідея в тому, що на основі історії змін у Git ви можете хоча б приблизно оцінити, чи пов’язані ці частини коду, чи ні. І якщо ви бачите, що вони пов’язані, тоді можна сідати й рефакторити, бо ви вже знаєте, як історично змінювався код і, відповідно, можете передбачити, як він буде змінюватися в майбутньому.
Якщо це підсумувати, то правильно сказав Джордж Сантаяна: «Ті, хто не пам’ятають минулого, приречені на його повторення».
Git-історія — це наш історичний лог, який може допомогти нам не повторювати помилки минулого.
Чітко визначайте мету рефакторингу
Завжди чітко визначайте, як саме має покращитися код після рефакторингу. Коли хтось приходить і каже, що треба щось рефакторити, я завжди прошу зробити перелік проблем, які потрібно виправити.
Якщо людина приносить список із кількома пунктами й каже, що рефактор розвʼяже всі ці проблеми — це майже гарантований сигнал, що вона не до кінця все продумала. Скоріш за все, вона перерахувала ті проблеми, які збирається закрити своїм планом, але проблем насправді більше.
Вірний підхід до рефакторингу такий:
- максимально прискіпуватися до коду й зібрати повний список болючих точок у коді, навіть дрібних;
- визначити, які з них можна розвʼязати за одну ітерацію рефактору й не намагатись охопити все одразу;
- оцінити, чи дійсно зміни під час рефакторингу коштуватимуть часу та ресурсу команди;
- після рефакторингу заново пройтися по списку з бажаними змінами й оцініти, чи дійсно рефактор допоміг вам усунути проблеми та чи не створили нових. Бо дуже часто трапляється ситуація, коли щось порефакторили, а код насправді залишився такий самий, тільки в профіль.
І приймайте той факт, що не всі рефакторинги успішні — це нормально. Коли бачите невдалий результат — збирайте команду і проводьте ретро: чому прийняли те чи інше рішення, чому не дійшли до очікуваного ефекту й так далі.
Якщо не робити ретроспектив після рефакторингів — у вас магічним чином 100 % рефакторів будуть успішними. А ми всі дорослі люди і знаємо, що якщо 100 % виконано успішно, значить хтось десь добряче прикрашає реальність.
Розбивайте рефакторинг на маленькі ітерації
Маленькі ітерації — це найкращий друг будь-якого рефакторингу. Адже чим менше ви хитнули систему, тим менше шансів щось глобально зламати. Бо погодьтеся, дуже не ок щось із вечора зарефакторити, а зранку прийти на роботу й у вас половина тест-репорта — червона.
Дуже часто можна лишити код, як він є
Не кожна милиця в коді є проблемою, яку треба терміново виправляти. Особливо якщо цей шматок коду у вас майже не змінюється або ви використовуєте його раз на рік.
Також багато команд часто надто зосереджуються на структурі проєкту, ніж на самому коді й тому, що відбувається всередині самих класів і функцій. Але саме внутрішня логіка визначає підтримуваність системи. Структуру змінити відносно просто, а от якісний рефакторинг складного коду зробити значно важче.
Типовий приклад на скриншоті нижче — проєкт використовує юзкейси, і є популярна думка, що це є маркером хорошої архітектури. Це не так, бо формальна наявність юзкейсів не гарантує якість коду.

У конкретному випадку їх дуже багато, і може скластися оманливе враження, що це гарно розбитий і структурований код. По факту, кожен із них має понад 2000 рядків коду.
Щоби розібратися із цим куском коду, я витратив півтора дня з дебагером і ще близько трьох днів, щоб розв’язати всі залежності. А щоби виправити проблему в структурі проєкту, вистачає години: переносите файли, щось перейменовуєте і структура готова.
Приклади гарної архітектури з реального життя
Якщо відкрити статті по архітектурі на Medium, автори подають більшість із них однаково: обов’язкові шари service, datasource, repository, usecase, без інтерфейсів взагалі ніяк.
Я бачив кілька статей від одного автора, присвячених архітектурі. Його перша стаття у 2008 році стосувалася патерну MVC, потім у 2010 році він перейшов до MVP, далі до MVVM, Clean Architecture і SOLID. І кожен раз у прикладі він використовував один і той самий застосунок, який займає лише півтора екрана й показує погоду в чотирьох містах. Такий застосунок можна написати в одному файлі й код буде читабельний, будь-яка архітектура тут підійде.
У випадку з великими проєктами все складніше, бо там архітектуру формують під впливом різноманітних вимог — продуктивності, масштабування, роботи з legacy, великої кількості розробників тощо. Тож щоби побачити, як дійсно організовують код у великих командах, варто дивитися на проєкти на GitHub.
Приклад архітектури 1. Detekt
Detekt — великий і якісно структурований проєкт. У ньому немає repository/service/usecase і до десяти інтерфейсів на весь проєкт. В detekt супер читабельный код.
Аргумент, який я часто чую — «Нам потрібна складна архітектура, щоб уникати мерж конфліктів». У Detekt зараз понад 300 контриб’юторів, 5000+ закритих pull request’ів, люди працюють із 24 часових поясів, не мають спільних мітингів і загального менеджера. Тож якщо в команді є синхронізація, процеси, регулярні зустрічі й менеджмент, і вам усе одно потрібна надмірна архітектура — проблема, скоріш за все, не в архітектурі.
Приклад архітектури 2: IntelliJ Community Edition
IntelliJ Community Edition — це чудовий приклад великого, складного UI-проєкту. В IntelliJ реалізовано масу складних компонентів: профайлер Java, візуалізацію графів, інспектори, навігацію по AST тощо. Більшість мобільних застосунків значно простіші за цей проєкт, але розглядаючи його код, можна побачити, як організовують складні UI-підсистеми на практиці. Немає популярних прослойок, інтерфейсів, з однією імплементацію тощо. Проєкт можна дуже просто зрозуміти, особливо враховуючи, що в open source у вас немає можливісті запитати щось у живої людини, і ніхто екскурсію по проєкту вам робити не буде.
Висновок
Тож замість того, щоб орієнтуватися на поради з Medium від авторів, які роблять апку погоди, дивіться, що пишуть реальні програмісти на GitHub. Їхній код краще покаже, як розділяти на сутності, організовувати модулі та підтримувати велику кодову базу.
І робіть просто, складно само вийде.
Якщо маєте питання — пишіть у коментарях або мені в LinkedIn.
Сподобалась стаття? Підписуйтесь на автора, щоб отримувати сповіщення про нові публікації на пошту.

32 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарів