Як забезпечити якість продукту в стартапі без виділеного QA
Привіт, мене звати Дмитро Гаранжа. Я Head of Engineering у стартапі Howly від венчур-білдера SKELAR. Ми створюємо маркетплейс онлайн-консультанцій, що поєднує кастомерів з певним питанням та експертів, які можуть із цим допомогти. Щодня ми вирішуємо більше тисячі запитань кастомерів.
У статті розгляну основні принципи та підходи, завдяки яким ми підтримуємо високу якість продукту в стартапі без виділеного QA.
Як і в більшості стартапів, для нас основною метрикою інженерної команди є швидкість доставки фіч на production. Ми пройшли шлях від найму та свідомої відмови від QA через погіршення показника Time to market (TTM). Водночас вдалося зберегти такий самий рівень якості продукту.
Трішки контексту
Howly 2,5 роки, консультації надаються в форматі чату на нашому сайті. Мобільних застосунків ми поки що не маємо.
У нас дві кросфункціональні скрам-команди сумарно в 10 інженерів. Основні ролі в команді: Product Owner, Team lead, FE/BE Tech lead, FE/BE Engineer, Designer, Content editor. Проєкт побудований на мікросервісній архітектурі, кожна команда відповідає за свій набір функціоналу.
Наш шлях до no-QA
Розробку MVP ми почали без виділеного QA. Через півроку після ускладнення продукту та збільшення кількості кастомерів відкрили позицію.
Ми шукали такого собі «супермена», який буде повністю відповідати за якість на проєкті:
- базово розумітися в архітектурі, щоб локалізовувати баг до рівня сервісу;
- ухвалювати рішення, на якому рівні автоматизовувати тест-кейс (Unit / Component / E2E);
- верифікувати Unit&Component-тести, які пишуть розробники;
- за потреби дописувати Component-тести самостійно;
- писати E2E-тести на успішні критичні флоу.
Таких людей за півроку пошуків на ринку виявилося дуже мало, тому вирішили взяти Manual QA і донавчити її. На жаль, нам не пощастило: людина виявилася не настільки проактивною, як ми очікували, і навчання рухалося дуже повільно.
Додатково після найму ми стикнулися з двома основними проблемами:
- зростанням TTM в середньому на плюс один день;
- меншою залученістю розробників в забезпеченні якості.
Якщо перший пункт частково фіксився б наймом іншої людини, то другий виникав з самого флоу роботи — у розробників зменшилося відчуття відповідальності за якість.
Згідно з статистикою, наш середній cycle time складає приблизно чотири — п’ять днів, тому навіть один додатковий день затримки уповільнював нас. Як приклад, можна привести A/B-тести, яких ми запускаємо досить багато. У випадку зі стартом спринта в понеділок без QA ми маємо змогу запустити A/B-тест раніше, і за вихідні вже зібрати більше даних.
Тому ми ухвалили рішення далі забезпечувати якість без додаткового степу в процесі в вигляді окремої ролі.
Далі розглянемо за рахунок чого нам вдалося цього досягти.
Культура та цінності
Почнемо з того, яку культуру та цінності ми формуємо всередині інженерної команди.
Цінності важливі, оскільки вони дають зрозуміти, як ви хочете, щоб люди уївалювали рішення в повсякденній роботі.
Перша важлива цінність — це ownership. Якщо сформувати її одним реченням — це відповідальність за результат. В Netflix є чудова стаття на цю тему, де вони називають таких розробників Full cycle developers.
Суть в тому, що розробник відповідає не тільки за написання коду, а за весь цикл розробки — від рефайментів, підготовки технічного рішення, його реалізації та тестуванню до деплою в прод та фіксу інцидентів.
На перший погляд звучить як забагато роботи. Проте завдяки цьому принципу ви сильно пришвидшуєтесь. Оскільки за весь цикл відповідає одна людина, якій не потрібно витрачати час на перехід між контекстами. Для того, щоб полегшити і стандартизувати роботу, розробники перевикористовують рішення інфраструктурних команд — для інфраструктури, тестування та розробки.
Крім зниження TTM і більш оперативного фіксу інцидентів на практиці такий підхід підвищує якість — він змушує розробників відповідальніше ставитися до покриття коду тестами та краще продумувати Edge-кейси та архітектуру.
T-shaped skills
Для реалізації ownership необхідні хоча б базові спеціалізовані знання з інших сфер.
У нашому випадку, наприклад, Back-end інженер має базове розуміння роботи та взаємодії з фронтендом, розробники самостійно вносять зміни в CI чи інфраструктуру.
Такий підхід значно пришвидшує комунікацію між спеціалістами в різних стеках.
Fail fast & cheap
Наступний принцип — рухатися швидко, ітеративно реалізовуючи великі технічні чи продуктові ініціативи. Так ми швидше отримуємо фідбек від кастомерів, розробників чи аналітиків і вже потім вносимо покращення. До речі, це один з принципів Continuous delivery.
Як приклад тут можна привести Canary releases — цей підхід дозволяє в проді вилити зміни на невелику кількість кастомерів, зібрати метрики і, якщо все добре, вилити зміни на 100%. Також тут сильно допомагають системи моніторингу, які ми розглянемо далі.
Learning from failure
The fastest way to succeed is to double your failure rate. Thomas Watson
Основний принцип в культурі навчання над помилками: ми не звинувачуємо конкретну людину у факапі чи багах. Ми приймаємо, що робити помилки — це нормально. Головне зробити з них висновки і внести конкретні покращення в процес.
У наступному розділі більш конкретно розглянемо, за рахунок яких методів це реалізується.
Процеси
Перейдімо безпосередньо до процесу роботи над задачами.
Ключові речі, які б я в ньому виділив:
- ми відносно детально проговорюємо та пропрацьовуємо рішення до реалізації;
- на кожному етапі чи мітингу є невеликі чеклісти, що дозволяють бути впевненими в тому, що ми нічого не пропустили;
- життевий цикл задачі не закінчується деплоєм на прод — у відповідальність розробника входить також моніторинг алертів.
Наприклад, безпосередньо перед рефайментом у нас є зустріч, на якій синхронізуються всі Product Owners & техліди. На ній ми верхньорівнево проговорюємо тікети чи епіки, синхронізуємося в баченні, пріоритетах, архітектурі та попереднім естімейтам.
До рефайменту розробники досить добре готуються: попередньо залишаються коменти з питаннями, готують API взаємодії фронтенду з бекендом, описують структуру сутностей в БД і т. д. Так розробники набагато краще синхронізуються в баченні з Product Owner, і, відповідно, це дозволяє реалізувати вимоги коректно з першого разу без фіксів в майбутньому.
Built-in quality
Quality comes not from inspection, but from improvement of the production process. W. Edwards Deming
Найважливіший принцип, якого ми притримуємося в процесах, це підхід вбудованої якості в процеси. Він був сформований Едвардсом Демінгом і ліг в основу Lean-руху, який зародився в Японії на заводах Toyota.
Суть підходу дуже проста: ви перевіряєте, що кінцевий результат має належну якість, проте це не є останнім етапом, як це зазвичай роблять QA. Ви стежите, щоб на кожному етапі процесу вихідний результат відповідав певним вимогам.
Чому варто приділити цьому час? Усе дуже просто: так ви сильно пришвидшуєтесь.
Реалізується підхід вбудованої якості досить простими речами: ми почали з візуалізації нашого процесу розробки та невеликих чеклістів на
У нашому випадку є чіткі вимоги необхідних речей на кожному етапі. Наприклад, до рефайменту в тікеті, крім безпосередньо вимог, має бути прикріплений дизайн та теобхідний контент, описаний API та створені сабтаски. Під час розробки ми дотримуємося code conventions, які описані в Notion для кожного стеку. Так не витрачаємо час на code review і на суперечки про форматування коду.
Важлива також наявність фідбек лупів, де команда може поділитися складнощами і вносити покращення в процес. Один з простих і ефективних способів — це ретро з усією командою, де можна розглянути ситуацію комплексно.
94% of problems in business are systems driven and only 6% are people driven. W. Edwards Deming
У більшості компаній, на щастя, ретро проводяться, проте не завжди максимально ефективно. Типові проблеми: мітинг часто відміняється, переходить у неконструктивне обговорення і звинувачення одне одного, не наводяться приклади конретних задач, відсутні action points або вони заасайнені на декількох людей чи без дедлайнів.
Incident management
Важливо також структурувати роботу над помилками. Для кожного інциденту (тобто критичної проблеми на проді) після фіксу технічний лід заповнює шаблон post-mortem в Notion з аналізом причин та планом того, як уникнути цієї ситуації в майбутньому.
Рекомендую додавати в post-mortem:
- timeline, починаючи з часу деплою зломаної версії, повідомлення про інцидент, деплой фіксу і т. д. Це в майбутньому дозволяє знайти вузькі місця в вашому процесі. Наприклад, після нашого аналізу ми зрозуміли, що вузьким місцем в нас є не час фіксу проблеми розробником, а довгий час її виявлення — тобто варто прикласти зусилля в сторону моніторингу і алертингу;
- лінкувати issue з issue-трекера;
- кількість кастомерів, яких ми заафектили;
- root-cause. Тут добре допомагають такі техніки, як-от 5 why’s;
- action items.
Оцінка ефективності змін у процесах
Для того, щоб оцінити ефективність змін у ваших процесах (додавання додатково етапу, відмові від QA etc), краще орієнтуватися на об’єктивні показники.
Для оцінки ефективності роботи інженерної команди і змін в процесах ми використовуємо DORA metrics. Це чотири метрики, дві з яких показують швидкість вашої роботи, дві інші — якість.
Для збору та візуалізації ми використовуємо Codacy Solutions.
Це корисно для порівняння ефективності вашої роботи в певні періоди роботи та розуміння загального тренду. Це не інструмент для щоденного використання менеджером — я б рекомендував один — три рази на квартал переглядати статистику. Звісно, це не скасовує інших інженерних метрик, наприклад velocity, cycle time etc.
Тестова стратегія
Перед тим, як розпочинати автоматизацію тестування, варто визначитися з тестовою стратегією — які типи тестів, коли і хто безпосередньо пише.
Думаю практично всі знайомі з класичною тестовою пірамідою. Проте мало хто задумувався над тим, що існують й інші її варіації.
Для початку визначімося з термінологією:
- Unit-тест — тест першого методу класу в ізоляції. Усі залежності класу мокаються.
- Компонентний тест — тест взаємодії всіх компонентів одного сервісу. Зовнішні залежності мокаються, проте БД (Postgres, Redis etc) часто підіймаються в ізольованому контейнері. Для запуску компонентного тесту нам не потрібен повноцінний environment — достатньо декілька ізольованих контейнерів на CI. Можуть запускатися паралельно.
- API-тест — схожий на компонентний, проте зовнішні сервіси не мокаються. Нам потрібен тестовий environment.
- E2E-тест — тестують весь флоу, починаючи з фронтенду і закінчуючи third-party сервісами. Потрібен тестовий environment, виконуються довго.
З мого досвіду роботи над вебзастосунками інженерні команди часто приходять до такого підходу:
- Розробники покривають код в основному тільки Unit-тестами.
- Automation QA пишуть значну кількість E2E- & API-тестів.
Загалом цей підхід добре працює перші півтора — два роки, поки кількість E2E- & API-тестів не починає налічувати тисячі, вони виконуються годинами і стабільно приблизно 5% з них починає падати з рандомних причин.
Це відбувається через те, що QA покривають не тільки основні позитивні кейси чи складні інтеграції, а й усі неуспішні флоу чи edge-кейси (які можна було б покрити більш швидкими і стабільними Unit- чи компонентними тестами). Після цього розробники зазвичай перестають запускати їх перед кожним релізом і більше орієнтуються на Unit-тести.
З Unit-тестами є інша складність: зазвичай писати їх довше, ніж компонентні, і вони дають трохи менший рівень впевненості, що всі компоненти в інтеграції працюють коректно.
Проте в типовому вебзастосунку з мікросервісною та Layered-архітектурою більшість Unit-тестів часто перевантажена моками і тестує тільки факт виклику залежності чи layer нижче.
Кожен проєкт унікальний, проте розгляньмо альтернативу тестовій піраміді в вигляді Test Automation Diamond, яка, можливо, теж краще підійде вашому проєкту.
У цій стратегії основна кількість тестів припадає саме на компонентні. Підтримуючись невеликою частиною Unit- та E2E-тестів. На E2E-тести в цьому випадку припадають тільки критичні (ті, що приносять бізнесу гроші) успішні флоу. Unit-тестами покриваються методи зі складною калькуляцією, алгоритмами і т. д. Усі інші кейси покриваються компонентними тестами.
Observability
Наявність observability-інструментів дозволяють оперативно відстежувати неочікувану поведінку системи та швидко локалізовувати проблему.
У Howly ми використовуємо для цього такий набір:
- Info-логування — ELK-стек. Рекомендую використовувати структурне логування та створити необхідні дашборди в Kibana — це дуже пришвидшить роботу розробників.
- Error-логування — Sentry. Цей інструмент вирішує декілька задач: групує помилки та нотифікує про них та додає контекст до помилки — stacktrace, дані про девайс користувача.
- Tracing — ELK. Для мікросервісної взаємодії це практично must-have інструмент, завдяки якому ви зможете швидко локалізовувати затримки в відповіді та помилки на рівні сервісу.
- Метрики та алерти: Prometheus & Alert manager.
- Зовнішній uptime checker — UptimeRobot.
Звісно що в ролі конкретних інструментів є багато альтернатив, тому варто використовувати найбільш прийнятні для вас. Час, інвестований в налаштування observability, зазвичай окуповує себе вже через квартал.
CI/CD
У ролі моделі роботи з Git ми використовуємо trunk-based development. Це дозволяє нам використовувати мінімальну кількість environments: staging & production.
Зазвичай більш складні моделі бранчування, наприклад, gitflow, потребують більшої кількості середовищ. На перший погляд вони створюють ілюзію підвищення якості: ви спочатку тестуєте фічі на Dev-середовищі, потім QA перевіряють їх на QA-environments і релізи додатково перевіряються на staging.
З практичного досвіду, крім негативного вприву на TTM (ви релізитеся в кращому випадку раз на один — два тижні замість релізів окремих фіч за готовністю), такий підхід не сильно підвищує якість продукту. Тому в випадку з no-QA стратегією краще підходить більш проста модель бранчування.
Для релізів фронтенду ми використовуємо canary releases — це дозволяє швидко отримати фідбек від кастомерів і зрозуміти, чи не погіршують ваші зміни бізнесові чи технічні метрики. Звісно що для критичного функціоналу ми використовуємо A/B-тестування — кожна зміна на воронці виливається на невелику кількість користувачів і аналізується вплив на conversion rate.
Проте великі зміни (наприклад, оновлення версії фреймворку, перехід на SSR, значний рефакторинг) важко запустити A/B-тестом, тому тут canary releases стають у пригоді. Для оцінки перформансу ми порівнюємо бізнесові метрики.
Крім цього canary releases дозволяють відділити волатильність маркетингу (особливо актуально для PPC) від змін на продукті. Так ми швидко локалізуємо проблеми між відділами.
Висновки
Основна думка, яку варто винести із цієї статті: якість продукту — це більш об’ємне поняття, ніж просто QC (тобто перевірка QA того, що певний функціонал працює чи ні).
Це поняття містить культуру, ефективність процесів, відповідну тестову стратегію, наявність observability-інструментів та ефективний CI/CD flow. Крім цього значний влив відіграє слабко зв’язана архітектура застосунку.
Лідити цей процес, на мою думку, має CTO/Head of engineering. Оскільки QA Team lead зазвичай має обмежений вплив на рішення з культурних принципів, організаційної структури та змін у процесах.
Більшість підходів принесуть користь і за наявності виділеного QA в команді. Проте no-QA стратегія дозволить вам релізитися і підтримувати продукт значно швидше. Це відбувається за рахунок зменшення необхідних етапів в вашому SDLC і більшої залученості розробників на всіх етапах.
75 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів