Як створити MVP, який переживе півот
Ми пережили 2 серйозні зміни в Scrimmage. Ми починали як аналітичний продукт для B2C, потім переключилися на WEB3-гру для заробітку, а потім стали B2B SaaS-продуктом. Під час першого переходу весь наш код був заархівований, і нам знадобилося 5 місяців, щоб підготувати продукт до запуску. Під час другого півота ми повторно використали 90% кодової бази, і нам знадобився 1 місяць, щоб підготуватися. Як стартапер, ви вірите в те, що робите, але зміни неминучі. Ви хочете створити продукт, який зможе легко адаптуватися до вимог ринку? Ось як ми це зробили.
Створюємо здорові уявлення про абстракції
Мені знадобилося 4 роки програмування, щоб навчитися будувати здорові абстракції. Ідея полягає в тому, щоб бути якомога менш конкретним, називаючи свої змінні та класи, щоб ви могли застосовувати їх за різних обставин.
Наприклад, ми створювали гру з персонажем-драконом, який може підвищувати рівень і виконувати квести. Замість того, щоб називати змінні "драконами", ми називаємо їх "NFT". Ця невелика зміна в іменуванні змусить вас мислити більш абстрактно. Замість того, щоб думати "Що можуть робити дракони", ви будете думати "Що може робити NFT". Тепер ви можете легко повторно використовувати цей клас у всіх своїх майбутніх проектах, які будуть використовувати NFT.
Іншим поширеним прикладом є спроба відокремити архітектурну абстракцію від логіки конкретного додатку. Якщо ви будуєте архітектуру як кодове рішення або просто CI/CD, не називайте речі своїми іменами, називайте їх за призначенням. Якщо у вас є 10 мікросервісів, ви можете захотіти створити Docker-файл і CI/CD-файл для кожного з них, замість цього ви можете створити архітектурну абстракцію під назвою "deployable", яка матиме реалізацію Docker-файлу і CI/CD за замовчуванням і вимагатиме від мікросервісу лише декілька вхідних змінних, таких як ім'я, порт і зображення. K8S не повинен знати про логіку вашого додатку.
Якщо ви будете дотримуватися правильних абстракцій, ви зможете відкрити новий спосіб написання коду - будувати механізми, які можуть вирішувати проблеми, замість того, щоб вирішувати їх безросередньо.
Ми будуємо механізми, які можуть вирішувати проблеми, замість того, щоб вирішувати їх безросередньо.
Ця ідея базується на бажанні підтримувати всі майбутні бізнес-вимоги без внесення змін до коду. Якщо ви помітили, що є файл, який дуже часто змінюється, настав час побудувати механізм підтримки подальших змін без зміни коду.
Прикладом може слугувати те, як ми організували нашу програму винагород. Ідея додатку полягала в тому, що користувачі можуть робити ставки, а ми даємо їм токени за кожну зроблену ставку. Замість того, щоб називати "ставку" "ставкою", ми назвали її "винагородою". Замість того, щоб жорстко кодувати кількість токенів для винагороди за ставку, ми реалізували механізм, який дозволяє нам налаштовувати винагороду за кожну "винагороду" з бази даних. Тепер ми можемо нараховувати токени за будь-що, не змінюючи жодного рядка коду.
Ще один яскравий приклад: ми хотіли збільшити винагороду користувачам, коли вони виграють ставку. Замість того, щоб писати код на кшталт "Якщо ставка приносить винагороду і якщо ця ставка має статус ВИГРАШ, помножити винагороду на 2", ми впровадили механіку "модифікації". Модифікації дозволяють нам змінювати винагороду на основі попередньо визначених фільтрів. Ви вказуєте фільтри в базі даних, і цей фільтр буде автоматично застосовуватися до кожної нагороди. Наприклад, у нас є фільтр "Коли тип винагороди - ставка, а поле РЕЗУЛЬТАТ має значення ВИГРАШ, помножити винагороду на 2". Завтра прийде клієнт і попросить збільшити винагороду за програш. Ми можемо зробити це з бази даних, змінивши 0 рядків коду.
Цей код просто безцінний і може бути використаний мільйонами способів для підтримки мільярдів варіантів використання. Такий код займає більше часу на написання, але ви витратите набагато менше часу на його підтримку.
Якщо ви будуєте здорові абстракції і використовуєте їх для створення узагальнених механізмів, ви можете подумати про те, щоб винести деякі механізми в окремі мікросервіси, які нічого не знають про решту системи.
Ми створюємо мікросервіси з відкритим вихідним кодом
Уявіть, що ваш мікросервіс використовуватимуть тисячі інших розробників в абсолютно не пов'язаних з вашим проектах. Ця ідея змушує вас переосмислити залежність ваших мікросервісів один від одного. Це вберігає наш код від жаху залежностей і робить його придатним для повторного використання у всіх майбутніх проектах і поворотних моментах.
Прикладом може слугувати механізм планування, який ми реалізували. Ми запустили наш додаток як окремий додаток із cronjobs, якi запускаються з коду. Проблема в тому, що ми не можемо масштабувати цей сервіс горизонтально, тому нам довелося відокремити логіку планування деінде. Замість того, щоб налаштовувати cronjob за допомогою коду, ми впроваджували і постійно додавали до них нові значення, ми реалізували K8S-Scheduler, який є керованою діаграмою, що розгортається в нашому кластері. Ця діаграма сканує всі наші мікросервіси на наявність визначень cronjob і виконує їх за допомогою викликів API. Тепер ми можемо описати cronjob під час створення нового endpoint, і тоді Scheduler почне планувати його, не втручаючись у код.
Наступний приклад - аутентифікація користувача за допомогою JWT. Замість того, щоб зробити її частиною одного з наших мікросервісів, ми зробили її окремим мікросервісом, який автентифікує користувачів і повертає токен JWT, який можна застосувати у всіх інших мікросервісах. Тепер цей мікросервіс можна повторно використовувати на будь-якому майбутньому півоті або проекті, виконавши єдину команду для його розгортання.
Якщо ви будете дотримуватися цього принципу, через 2 роки у вас буде бібліотека з 10 мікросервісів, які можна використовувати для створення будь-якого продукту, пов'язаного з вашою діяльністю, за лічені дні. Тепер у вас є конструктор продуктів, який дозволяє створювати їх, використовуючи лише конфігурації.
Ми створюємо конструктори продуктів замість продуктів
Ви можете назвати це надмірною конфігурацією, але ми називаємо це архітектурою. Тепер, коли ви зрозуміли, що ваш продукт не відповідає вимогам ринку, ви можете швидко переналаштувати його, змінивши пару змінних у вашій базі даних і розгорнувши деякі з ваших минулих мікросервісів у новому кластері. Однак керувати всіма цими мікросервісами може бути складно.
Terraform добре допомагає нам у цьому питанні. Вона надає нам архітектурну абстракцію, яка дозволяє нам дивитися на інфраструктуру як на код, який можна легко модифікувати, зациклювати та конфігурувати. Якщо вам потрібна якась нова функціональність, якої у вас ще немає, ви вже маєте чіткий інтерфейс, щоб створювати її і додавати до тераформи, яка об'єднає її з усіма іншими мікросервісами. Він автоматично додасть до нього авторизацію, що зробить його доступним для огляду, розгортання та планування. Він також передасть всі необхідні змінні середовища і розмістить його у відкритому доступі.
Підсумки
Ми впровадили систему, яка дозволяє нам розробляти програмне забезпечення за допомогою конфігурацій. Це має бути кінцевою метою кожного ІТ-продукту, який хоче мати можливість утримувати десятки інженерів під своїм дахом і пережити майбутні кардинальні зміни.
Не кожне програмне забезпечення потребує такого підходу. Іноді ви хочете створити швидкий прототип, який протестує ринок. Але важливо відрізняти " сирий" прототип від MVP, у якого попереду довге життя, сповнене змін та вимог.