Оверінжиніринг — невидимий ворог компанії. Або що занадто, то недобре
Привіт, мене звати Антон Пінкевич, я — Full Stack Tech Lead у продуктовій ІТ-компанії Universe з екосистеми Genesis. Ми створюємо функціональні бізнес-застосунки (утиліти для iOS) та розвиваємо власний R&D-центр.
Я в розробці вже понад девʼять років, але протягом останніх двох ловлю дзен у своїй професії. Здається, мені вдалося знайти баланс у роботі продуктової та технічної команд. При цьому використовувати нові технології, розвивати продукт у потрібному напрямі та уникати legacy коду. До цього я працював в декількох продуктових компаніях, в онлайн-магазині, запустив кілька власних проєктів. Тому я знайомий зі стилем роботи різних команд. Багато програмістів прагнуть знаходити ідеальні рішення, що призводить до ускладнення системи.
У цій статті я розмірковую над тим, як технічний стек впливає на успішність продукту. А також ділюся спостереженнями, як досягти гнучкості та стабільності системи та водночас не ускладнити її. Стаття призначена для розробників і техлідів, які хочуть більше розібратися в процесах бізнесу та додати сенсу своїй роботі.
Передмова
Технічні фахівці сваряться майже в кожному пабліку. Бекендщики та дизайнери не люблять фронтендщиків. Тестувальники жаліються на фронтендщиків та бекендщиків. А самі фронтендщики мають претензії до тестувальників та дизайнерів. Продовжувати можна довго, це перетворюється на порочне коло. Мені здається, ці конфлікти відбуваються з таких причин:
- продуктові менеджери прагнуть отримати працюючу функцію в максимально стислі терміни;
- тестувальники намагаються ретельно перевірити її та переконатися, що програма працюватиме у всіх можливих та неможливих ситуаціях;
- бекендщикам хочеться розробити архітектуру, яка зможе витримувати мільярдні навантаження і бути максимально розширюваною та захищеною;
- дизайнерам потрібно зробити нові UX патерни, провести user research, щоб викласти мега case study на Behance;
- фронтендщики обʼєднують те, що створили дизайнери та бекендщики, у щось, що працює для кінцевого користувача, додають від себе анімацію та інші «смаколики».
Кожен намагається зробити свою роботу максимально якісно, але інколи не думає про кінцеву мету. Це призводить до зайвих ускладнень на кожному етапі розробки. Але найбільше страждає бізнес. Тож з чого почати? Почну з історії.
Як створити шедевр, який нікому не потрібен
Жив-був програміст. Назвемо його Антон. Він працював у великій продуктовій компанії та відповідав за розробку одного із напрямів. Його постійно підганяли менеджери й маркетологи, питаючи, де нові функції, і чому розробка триває так довго. Антону це не подобалося, адже він — програміст і хоче писати якісний софт.
Згодом він усвідомив, що йому вистачає досвіду, тож чому б не запустити власну компанію? У ній він буде босом і зможе сам вирішувати, який продукт і як робити. А якщо здійсниться все задумане, компанія стане найуспішнішою у світі. Тож Антон накопичив стартовий капітал, звільнився, відгородився від усього світу і взявся до роботи.
Протягом першого місяця він розробляв правильну архітектуру, щоб користувачі отримували контент максимально швидко, а розширювати систему було легко. Другий місяць пішов на розробку ідеального дизайну та анімації, які принесуть користувачам нескінченну радість від використання програми. Протягом третього місяця він налаштовував зручну систему CI/CD — робиш один коміт, і всі 10 000 потрібних сервісів збираються автоматично. У наступні місяці писався максимально правильний код: покриття тестами на 100%, усі модулі системи спілкуються між собою через інтерфейси, кожен модуль має свою відповідальність, усі залежності впроваджуються через DI контейнер тощо. Через рік плідної щоденної роботи продукт був готовий. Вийшов шедевр програмного забезпечення: простий, швидкий, зручний.
Настав час публічного запуску. Антон написав великий пост у соціальні мережі, описав продукт, своє бачення і процес. Пост отримав сотні лайків від друзів та знайомих, усі його похвалили. Але минає тиждень, а в нього лише дві покупки: від самого Антона під час тестування системи та від випадкового користувача, який згодом попросив повернути гроші. Люди не користувалися продуктом і тим більше не платили за нього. Час минав, ситуація ніяк не змінювалася. Накопичені гроші закінчувались. Антон не розумів, де він схибив.
«Маркетинг! Звичайно ж!» — подумалося йому. Він узяв грошей у борг та запустив рекламну кампанію. Вона була дорогою, бо раніше Антон такого не робив. Після цього почали з’являтися перші користувачі. Вони реєструвалися, використовували продукт декілька днів, а потім йшли й ніколи не поверталися.
Гроші скінчилися, й Антон був змушений відкласти продукт та повернутися в компанію, для якої прибуток був першочерговим.
Помилковий підхід
Проблема Антона не в маркетингу, а в підході до розробки програмного забезпечення. Люди готові використовувати продукти з поганими інтерфейсами, тимчасово терпіти баги та незручності. Головне — щоби продукт вирішував їхню проблему.
Нижче скриншот з софту, яким користуються сотні тисяч стоматологів. Компанія успішна? Так. Чи продукт вирішує проблему? Так. Чи є цей продукт ідеальним? Не впевнений, судячи з дизайну.
На фото зображений Denticon
В історії про Антона я спеціально опустив те, що саме він розробив. У ментальності більшості програмістів це не має значення. Їм важливо писати «якісний софт», яким можливо навіть ніхто й не буде користуватися. Тому вони можуть ускладнити систему заради того, щоб вона була абсолютно правильно спроєктована та реалізована. Але ця «правильність» часто помилкова.
На мою думку, технічний стек не впливає на успішність продукту. Є такий хлопець levelsio, який сам собі програміст-бізнесмен. Його сумарний дохід на рік складає близько $4 млн, у тому числі прибуток — $3,6 млн. Він пише на php+html+чистий js, часом виправляє код прямо на сервері та пише про все це у Twitter.
Нещодавно він запустив новий бізнес, який назвав avatarai.me. Такий проєкт реалізувати просто, якщо не займатись оверінжинірингом (вже є кілька клонів). На скріншотах нижче видно, як його продукт виглядає на момент написання статті. Як бачимо, навіть форма додавання файлів не стилізована.
Ідея стартапу в тому, щоб через посадкову сторінку отримувати від користувачів кілька фотографій і вручну «згодовувати» їх в інтерфейс нейромережі. Коли мережа була навчена, розробник генерував фотографії та «руками» відправляв на пошти людям, які заплатили.
Коли гіпотеза підтвердилася, він автоматизував цей процес. Зараз стартап зростає дуже швидко: сервіс уже заробив $100К за 10 днів, а весь Twitter забитий аватарками, зробленими з його допомогою.
Зрозуміло, що цей хлопець — виняток. Але я хочу донести думку: не потрібно намагатися виконувати свою роботу ідеально в рамках вашого розуміння. Її потрібно робити так, щоб вона ідеально розв’язувала проблеми кінцевого споживача. Уся команда, уся архітектура та сервіси мають бути націлені саме на це.
Є готове SaaS-рішення вашої проблеми? Добре, використовуйте його. Базу даних можна поки не підіймати, а використовувати redis, чи взагалі зберігати в одному об’єкті на сервері? Супер, уперед. Надсилання повідомлень користувачам можна робити вручну раз на тиждень? Прекрасно, можна опустити інтеграцію сервісу сповіщень. Головне, щоб від цього не страждав клієнт.
Звичайно, важливо не потонути в технічному боргу, вчасно все інтегрувати й автоматизувати. Тут відіграє велику роль досвід продуктового менеджера та технічного ліда.
Додаткова цінність
Щоб визначити, що насправді важливо, потрібно розуміти, як влаштований бізнес і яку цінність створює продукт для користувача. Якщо уявити, що весь бізнес — це ієрархія департаментів, які пов’язані між собою, то отримаємо наступне:
Найважливіший зв’язок — клієнт-продукт. Саме тут створюється найбільша цінність, за яку компанія отримує гроші.
Користувачі задоволені — компанія прибуткова.
Користувачі незадоволені — вони йдуть, а компанія стає збитковою.
Як бачите, продукт у цьому випадку є найважливішим. І це необов’язково має бути щось з IT (сайт, додаток тощо). Наприклад, у нашому випадку продукт — це контент. Чи має принципове значення те, як ми його доставлятимемо користувачеві? Не зовсім.
Якщо загалом подивитися на вимоги до продукту, їх можна спростити до одного речення: дати користувачеві можливість заплатити та отримати навчальний контент.
Уявімо ситуацію, що в нас взагалі немає IT-департаменту. У найгіршому випадку можна отримувати від користувачів перекази за допомогою банківських платежів та надсилати їм посилання на курси електронною поштою. Якщо взяти дещо кращий приклад, можна отримувати оплати через систему stripe і давати клієнтам інвайт у notion. Варіант ще кращий — використовувати систему teachable тощо.
Створення власної системи з нуля — не є принциповим, але обов’язковим, якщо ви збираєтеся отримати конкурентну перевагу у вигляді кращого UX.
Наприклад, продукт компанії Netfilx — це контент. Ще у
Сьогодні ми бачимо перегони стримінгових сервісів, які роблять акцент на кінопродукції. За неповний 2022 рік Netflix вже витратили $18 млрд на створення власного контенту. Користувачі платять за доступ до серіалів та фільмів, а не за геніальний сайт. Якби на Netflix не було регулярних оновлень контенту, ніхто б не підписувався, і не було б доходу. Найімовірніше програмістів звільнили б, і вони пішли додому (привіт хлопцям з Twitter).
У будь-якій ніші існує певний поріг якості. Якщо ваш продукт нижче цього порога — ви неконкурентні. Якщо вище, то користувачам уже не так важливо, наскільки «високо».
Культ software
Програмне забезпечення лише допомагає бізнесу вести свою діяльність. Досить робити зі створення софту і своєї роботи культ. Що відбувається, коли hardware-інженери займаються оверінжинірингом? Виходять машини Голдберга.
Найцікавіше, що програмісти намагаються розв’язати неіснуючі проблеми не тільки користувачів, а свої власні також. Ніхто не хоче виходити з «бульбашки» і стикатися з реальним світом, де потрібно заглиблюватися в складну тему, робити помилки, виправляти їх, і все це по колу. Набагато простіше вигадати проблему і вирішити її, ніж займатися нагальними питаннями.
Часто вирішенням реальних завдань є проривна технологія. Як, наприклад, свого часу став React. Але для цього потрібно бути сміливим, розумним, наполегливим і, взагалі, візіонером. Нині ж ми маємо купу аналогів, які вирішують уже неіснуючу проблему.
Виглядає кумедно, але це наша поточна реальність у софтверній розробці, де нові фреймворки та мови програмування випускаються чи не щомісяця, часто без зворотної сумісності зі старими технологіями. Програмісти намагаються встигати за трендами, але виходить, що вони просто ускладнюють власні системи.
Іноді розробляти нові фреймворки на основі React може бути вигідно, але якщо ви вирішуєте інше завдання. Так нещодавно був викуплений новий фреймворк Remix компанією Shopify. Або подивіться на успіх компанії Vercel (творців NextJS).
Я не проти прогресу, і не проти нових фреймворків. Це рухає нас уперед. Едісон створив тисячу лампочок до того, як отримав робочий варіант. Але поки Едісон експериментував, ніхто не змінював усі лампочки в місті з кожним новим прототипом. А ще він намагався отримати доступніше світло, а не просто закручував дріт у скло ногами. Круто, складно, але не горить.
Я пропоную повернутися до основ, зрозуміти, у чому полягає наше завдання і вже від цього відштовхуватися під час розв’язання проблем і поставлених завдань.
Основне завдання софту — автоматизація бізнесу
Завдання вважається виконаним, коли софт автоматизував бізнес-процес та заощадив компанії гроші. Розробляти, тестувати та підтримувати ПЗ досить складно та дорого. Тому і з’явилися різні архітектури та методики ведення проєктів, покликані здешевити цей процес. Тобто не для того, щоби програмісти вчилися нового, не для того, щоб робити софт заради софту, а для того, щоби бізнес постійно зменшував свої витрати під час розширення.
Нижче опишу свої скромні спостереження, які можуть допомогти на старті нових проєктів.
Весь софт, як і бізнес, можна розділити на різні домени (модулі). Водночас треба враховувати основний продукт компанії: як він створюється, де зберігається, де збирається, як поширюється і кому призначений.
Найважливіший модуль — той, який приносить гроші вашій компанії, є унікальним, створює цінність та конкурентну перевагу. Інші модулі потрібно робити максимально дешево та швидко. Ця ідея дуже добре розкривається в книзі Domain Driven Design (DDD), написаній Еріком Евансом.
Як можна досягти гнучкості, стабільності та при цьому не дуже ускладнити? За допомогою інтерфейсів та розумного поділу відповідальностей.
- Розбиваєте всю систему на модулі, які будуть використовувати лише інтерфейси для зв’язку між собою. Якщо ми замінили один із модулів — система продовжує працювати за умови, що новий модуль реалізує інтерфейс.
- Створюйте швидке рішення, яке відповідає мінімальним вимогам користувачів. Можна використовувати зовнішні сервіси, писати процедурний або спагеті-код, або як буде швидше та зручніше команді.
- Зважаючи на те, що модуль буде ізольований інтерфейсом, його «начинку» можна буде переписувати нескінченну кількість разів. Тут важливо стежити за тим, щоб у вашій системі не було абстракцій, що «протекли», тобто реалізації з різних модулів не посилалися безпосередньо одна на одну.
- Найскладніше — щоби кожен модуль був невеликого розміру. Основний критерій — можливість написання модуля з нуля протягом одного-двох тижнів. Якщо це стартап / проєкт, що починається, то кількість часу можна зменшити до трьох днів.
- Але з інтерфейсами всередині модулів не варто переборщувати. Кожен із них створює новий шар абстракції. І в певний момент рівень абстракцій знаходиться занадто далеко від проблеми. І щоби зрозуміти, що робить модуль, потрібно переглянути весь шлях даних. У такій великій кількості рядків коду також збільшується кількість можливих багів, що впливає на час тестування. А ще людина може пам’ятати обмежену кількість сутностей. І якщо рівнів дуже багато, то продуктивно програмувати можуть лише генії. Кожен сам знаходить власну золоту середину. Для мене працює правило: не більше пʼяти рівнів абстракцій.
- Дотримуватися цих пунктів можна й на фронтенді, і на беку. Це дозволяє швидко постачати софт і бути впевненим у тому, що в майбутньому можна буде безпроблемно замінювати погані модулі на якісніші аналоги. Прям як Корабель Тесея: на ходу міняємо дошки та пливемо до мети.
Ми дотримуємося таких правил при розробці фронтової частини Wisey вже рік. Про те, яку архітектуру я розробив, описував в попередній статті. Наразі ми маємо близько 100 великих незалежних модулів, кожен з яких виконує певну функцію. Багато з них були переписані з нуля кілька разів, наприклад модуль уроку, аутентифікації, оплат, особистий кабінет користувача та інші.
У даному підході добре те, що можна не змінювати старий код, якщо приходять нові вимоги, а просто написати новий модуль. Закрити його feature flag і замінити старий, що використовується в системі. Коли модуль протестований, ми просто видаляємо стару версію. Таким чином можна не турбуватися про стабільність системи в продакшені.
У крайньому разі є можливість повернути стару версію модуля на час виправлень. Також подібний підхід спрощує A/B тестування за допомогою перемикання версій модуля для різних користувачів. Крім того, новому члену команди досить просто працювати з великою кодовою базою: усі модулі очевидно дотримуються інтерфейсів (контрактів).
Я описав наш підхід стисло й не повторював те, що вже написано розумними людьми. Безумовно, тема дуже глибока і вимагає чимало часу на вивчення. Якщо вона вам цікава, то раджу ознайомитися:
- CQRS (command-query responsibility segregation) + ES (event sourcing) + event-driven architecture — покликані декомпозувати систему на маленькі шматочки, які можна легко збирати разом;
- Domain-driven design — книга про те, як подружити бізнес та розробку ПЗ;
- Методологія мови Rust — мені подобається погляд авторів на проблеми мов програмування та методи їх вирішення;
- Scrum — як правильно вести проєкти та працювати в команді.
Замість висновку
Прийнятне швидке рішення, яке розв’язує проблему, краще за ідеальне, розробка якого займе місяці. Час — дуже цінний ресурс для бізнесу. Поки ви писатимете свій ідеальний код, бізнес може закритися.
У цій статті я хотів звернути увагу на невтішний тренд та закликати колег глибше замислюватися про потреби клієнтів та більш свідомо підходити до своєї роботи. Я не закликаю бути посередністю. Код потрібно писати добре, але важливо прислухатися до команди, поважати колег і ставити цілі бізнесу вище за особисті при роботі над продуктом.
Леонардо да Вінчі намагався досягти досконалості у своїй роботі, тому часто не дописував картини до кінця. Уявляєте скільки шедеврів втратило людство через критерії, придумані в голові генія, але абсолютно нерелевантні для загальної маси людей? Іноді досконале — ворог хорошого.
25 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів