Боремось з одвічною проблемою IT-продуктів — технічним боргом

💡 Усі статті, обговорення, новини про продукти — в одному місці. Приєднуйтесь до Product спільноти!

Привіт, я — Артур, Associate Director в команді продуктової студії Railsware. У компанії я вже 10 років, і цей досвід переконав, що якість роботи та репутація команди — не просто красиві слова, а критично важливий аспект успіху в IT-індустрії. Фактично це означає наявність продуктового майндсету у всіх членів команди та бажання вдосконалювати свій крафт, що дозволяє нам створювати надійні робочі продукти за адекватний час та гроші.

Важливо розуміти, що навіть при найкращих намірах виникає і накопичується технічний борг (TБ чи tech debt). З цим стикається будь-яка IT-компанія. І нехай слово «технічний» не вводить в оману. По суті, це як і борг у реальному світі: ви можете взяти позику для швидкого старту, але в кінці треба його повернути, часто — з великими відсотками. Тож якщо не управляти технічним боргом, він може звести нанівець всі ваші зусилля щодо продукту чи навіть серйозно зашкодити здоровʼю компанії.

Ця стаття стане в пригоді широкому колу колег. Продактам та проджект-менеджерам, які хочуть зрозуміти, як управляти технічним боргом та як він впливає на розвиток продукту. Розробникам, які хочуть краще розуміти наслідки своїх технічних рішень. Студентам і початківцям в IT, які хочуть зрозуміти, що таке технічний борг і як з ним боротися. Сподіваюся, допоможу вам розібратися в цій складній темі, щоб ви могли створювати кращі продукти і досягати більшого успіху в своїй кар’єрі.

Як я розумію технічний борг

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

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

Для себе я визначив, що технічний борг не зводиться до кількох FIX-ME, або TO-DO у кодовій базі. Це радше нюанси ніж борг, як і баги, або погано написаний код. Баги можуть виникати через ТБ, але вони не є основною проблемою. Так само і брудний код.

Технічним боргом полюбляють називати як борг коду, так і архітектури. Тому багато хто неправильно його розуміє і не вміє відстежувати. Я користуюсь двома ознаками виникнення та накопичення ТБ, які легко помітити:

  1. інженерам стало важко впроваджувати зміни в програмне забезпечення,
  2. код стає складнішим після внесення простих змін.

Ризики накопичення технічного боргу

Як і фінансовий борг, ТБ з часом тільки збільшується. Чим довше його ігнорувати, тим дорожче він вам коштуватиме. Наведу вам декілька прикладів негативних наслідків ТБ, що псують життя усім членам команди:

  • Непередбачені витрати в майбутньому. Наприклад, якщо команда інженерів не в змозі регулярно оновлювати залежності, у певний момент їй доведеться витратити незапланований час на заміну застарілих бібліотек чи фреймворків.
  • Погіршення якості продукту та його можливості масштабуватись.
  • Ускладнений ріст команди.
  • Неякісна документація, на яку вже не можна покладатись.
  • Відсутність прогресу розробки через накопичення критичної маси ТБ, оскільки інженери вимушені витрачати весь час на переробку продукту.
  • Швидке вигоряння спеціалістів, що змушені працювати над проблемами, яких можна було б уникнути.

Якщо борг не контролювати, він може серйозно вплинути на прибутки вашої команди (або прибутки клієнта, якщо ви надаєте послуги розробки, а зрештою — і на ваші).

Як краще слідкувати за ТБ

Коли Вейд Каннінгем вперше ввів термін технічний борг у 1990-х роках, він мав на увазі в основному технічний борг коду. Однак відтоді визначення значно розширилося. Зараз ми можемо сказати, що існує кілька різних типів ТБ.

Архітектурний борг. Виникає, коли ми приймаємо неоптимальні рішення або недостатньо добре продумуємо архітектуру системи. Наприклад, ви створюєте вебзастосунок за допомогою платформи з готовими шматками коду (штибу WordPress). Пізніше, отримавши відгуки користувачів, ви розумієте, що продукт потребує значно більше налаштувань, ніж може запропонувати платформа.

Борг коду. Накопичується, якщо написаний код важко розуміти, оновлювати, або підтримувати. Код може бути надскладним, непослідовним, або містити помилки, що призводять до багів та інших проблем.

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

Борг документації. Виникає, коли розробники не вміють правильно документувати свій код. Відсутні, неповні, або застарілі пояснення тільки спантеличать колег і нових членів команди. Якщо продукт великий, борг документації ускладнить інженерам розуміння, як відбуваються певні процеси, як працюють фічі і як частини кодової бази поєднані між собою.

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

Борг безпеки. Накопичується, якщо не вживати належних заходів під час розробки ПЗ. Наприклад, якщо команда відкладає усунення відомої вразливості системи, яка серйозно збільшує ймовірність атаки шляхом SQL-ін’єкції. Некерований борг безпеки може призвести до масивних витоків даних та інших проблем.

Як виникає технічний борг

Перш ніж я розкажу про те, як наша команда бореться з ТБ, я хотів би навести основні причини його виникнення, щоб вам було зрозуміліше з чим саме варто боротись.

Причини, пов’язані з управлінням

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

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

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

Часта зміна стратегії або вимог. Різкі зміни або доповнення до специфікації проєкту також можуть призвести до накопичення технічного боргу.

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

Причини, пов’язані з командою

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

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

Оверінжиніринг. Прагнення до досконалості також може мати зворотний результат. Складність заради складності часто створює непотрібні труднощі. Наприклад, якщо команда занадто рано перейде від монолітної архітектури до мікросервісів, це ускладнить можливість внесення змін у наступних ітераціях.

Помилки. Звичайно помилки роблять усі, навіть досвідчені розробники. Іноді, попри попередні дослідження та планування, правильне рішення стає очевидним лише після того, як помилки з’явились. Це одна з причин, чому технічний борг неминучий.

Навмисний і ненавмисний технічний борг

Навмисний технічний борг виникає, коли команда усвідомлено приймає компромісні рішення задля досягнення короткострокової мети. Частіше це трапляється на початку розробки, коли швидкість виходу продукту на ринок — пріоритет (створення прототипу, MVP тощо). Але подібні ситуації також трапляються, коли є жорсткі дедлайни, а команда мусить випустити оновлення в строк.

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

Як працювати з технічним боргом

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

Детальне планування

Без готової стратегії продукту і плану, як її реалізувати, команда інженерів не може приймати правильні рішення. Ось чому так важливо мати роадмеп — дорожню карту продукту.

Дорожня карта — це більше ніж просто перелік завдань. Ми вважаємо її «живим» документом, який відображає усі важливі елементи стратегії продукту. Вона містить чітко пріоритезовані фічі, щоб члени команди від початку знали, на чому зосередити зусилля. З першого погляду інженери бачать пріоритети проєкту і розуміють, як їхній код буде впливати на продукт в цілому.

Водночас саме беклог допомагає команді своєчасно відстежувати технічні борги. Знаю, часом просто хочеться вдати, що проблеми не існує. Але якщо ви будете чітко відстежувати виникнення проблем, вирішувати їх буде набагато легше (і дешевше).

Отже, інженери повинні створювати тікети в беклозі кожного разу, коли помічають проблему. І коли команда матиме вільні ресурси, вона зможе пріоритезувати проблему та вирішити її малими зусиллями.

Фокус на важливому

Не всі проблеми є однаково важливими. Часто немає сенсу рефакторити фічу, яка відіграє незначну роль в користуванні продуктом. Краще, зверніть увагу на код, який насправді має значення. У кожній ітерації працюйте над покращенням ключової архітектури продукту та елементами інфраструктури. Поступово підвищуйте загальну гнучкість продукту і не витрачайте час на постійне удосконалення «достатньо хорошого» коду.

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

Увага до інженерів

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

Досить дієвою також є культура відкритого фідбеку, де всіх членів команди заохочують висловлювати свої думки і занепокоєння.

Спрощена ієрархія в команді

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

Як це не дивно звучить, але в Railsware немає менеджерів, що призначають ролі й розподіляють задачі. Ми самостійно організуємося в команди і гільдії, щоб тісно співпрацювати та досягати спільної мети.

Поясню на прикладі команди нашого SaaS-продукту Mailtrap — у ній окремі гільдії створюються під час кожного спринту. Ось деякі з них:

  • Гільдія фронтенду. Інженери працюють над новими фічами, підтримують чистоту коду на фронтенді та впроваджують нові підходи за потреби.
  • Гільдія підтримки. Розробники працюють над удосконаленням тих частин системи, у яких були виявлені помилки.
  • Гільдія OSS працює над тими аспектами продукту, де використовуються опенсорсні інструменти (геми, SDK).
  • Гільдія безпеки працює над посиленням захисту даних шляхом покращення процесів доступу до них та управління доступом до ресурсів проєкту.

У контексті запобігання ТБ «гільдійний» підхід має кілька ключових переваг. По-перше, команда отримує виділений час і ресурси для вдосконалення системи та усунення проблемних місць в коді. По-друге, члени команди можуть працювати над різними частинами проєкту протягом кількох місяців, що дозволяє їм глибше розуміти вимоги проєкту та активніше долучатись до прийняття рішень щодо його розвитку.

Виділення ресурсів на парне програмування

Робота в парах допомагає нам ефективніше розв’язувати проблеми та створювати кращі, надійніші рішення. Тому ми дуже часто практикуємо її для різних цілей. Такі сесії зазвичай тривають 2-3 годин в залежності від складності задачі. І витрачений час завжди того вартий.

Коли справа доходить до запобігання технічним боргам, основні переваги парного програмування — це:

  • Код кращої якості. З додатковою парою очей баги легше помітити й відразу пофіксити. Так в них не буде шансів перетворитися на технічний борг.
  • Можливість побачити загальну картину. Коли інженери працюють у парах, вони вже розглядають не одну, а дві точки зору, що допомагає формувати спільне розуміння продукту.
  • Обмін знаннями. Члени команди мають більше можливостей для спілкування. Це допомагає їм приймати кращі рішення та підтримувати сталий ріст продукту.

Регулярна перевірка пул-реквестів

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

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

Ось кілька порад, як це краще зробити:

  • Перед відправкою пул-реквеста на перевірку, автор має спробувати дистанціюватися від свого коду та поглянути на нього об’єктивно в контексті продукту. Таким чином він зможе виправити деякі явні відхилення та зменшити частину робочого навантаження на перевіряючого.
  • Для великих і складних пул-реквестів автори повинні додавати to-do списки до їхнього опису.
  • Інженери-ревʼювери мають бути проактивними та переглядати пул-реквести принаймні раз на день.
  • Під час перевірки, ревʼюверам варто переконатися, що їхні коментарі чіткі, практичні та коректні. На сайті Conventional Comments можна знайти багато гарних прикладів.
  • Якщо пул-реквест занадто великий або незрозумілий, рев’ювер має зв’язатись з автором та разом перевірити код.
  • Автоматизуйте перевірку. В нашій RoR-команді ми часто використовуємо Rubocop для належного форматування коду та виявлення потенційних проблем.
  • Також, користуємось Simplecov для перевірки покриття коду та Brakeman для пошуку будь-яких проблем безпеки.
  • Команда має прагнути закрити пул-реквест протягом 2-3 днів, інакше накопичиться багато роботи і буде важче приділити кожній задачі належну увагу.
  • Коли рев’ювер бачить, що щось можна покращити, але це напряму не стосується цілей пул-реквеста, він все одно має його заапрувити і залишити свій коментар щодо покращення. Вказуйте на помилки, пропонуйте кращі назви змінних, але завжди пам’ятайте про пріоритети проєкту.

Наостанок

Усі ми хочемо, щоб технічного боргу не існувало. Але це нереально. Тому, щоб не дати ТБ завдати серйозної шкоди продуктові, важливо чітко розуміти, що це таке та як він накопичується. Важливо переконатися, що усі інженери залучені до процесу прийняття рішення та мають автономію, щоб брати на себе відповідальність за технічний борг і бути більш активними в керуванні ним.

Проведення регулярних сесій код рев’ю допоможе команді тримати технічний борг під контролем та правильно визначати пріоритетність проблем. А парне програмування сприятиме виявленню проблеми на ранній стадії та допоможе переконатися, що код відповідає необхідним стандартам.

Що допомагає вам в боротьбі з технічним боргом? Діліться у коментарях!

👍ПодобаєтьсяСподобалось11
До обраногоВ обраному6
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Як ви боретесь з байдужістю розробників і менеджерів до технічного боргу ? Тому що я бачу є така категорія людей які не зацікавлені у «покращенні», якось є і добре. Можна ж просто робити задачі і пох що маленька фіча буде робитись місяць.

намагаємось байдужих не наймати :)

Дуже часто на великих проєктах проблема технічного боргу тісно пов’язана з проблемою «боргу вимог». Якщо якась функціональність не до кінця продумана і описана у вимогах — будь яка технічна реалізація не може вважатися правильною.
Далі це призводить до того, що можна назвати «війною припущень». Якщо нема чітких вимог — кожен починає будувати свої припущення. Наприклад: два рази на рік, якесь заплановане завдання може припадати на період зміни часу на літнє / зимове. У 90% випадків той, хто писав вимоги про це навіть не подумав!
Як має працювати система? Наприклад у водія було 2 години доїхати — по годиннику так і є. Але через переведення годинників насправді у нього тільки 1 реальна година! Припустимо що система має це врахувати і додати годину. Але потім припущення тільки збільшуються: що робити з розрахунками на витрату пального, що з оплатою праці? По годиннику виходить водій їхав 3 години. А якщо навпаки — і годинник переводять у інший бік?
Такі самі питання виникають коли водій, наприклад переїхав із одного часового поясу у інший. Знову у більшості проектів ніхто не опише такий сценарій у вимогах. І навіть спитавши овнерів проєкту чи кінцевих користувачів — у кожного буде свій погляд як має працювати система у цьому випадку.
Насправді на будь-якому довгому проекті можна знайти безліч таких припущень. Іноді деякі баги відкриваються кожен рік — бо черговий QA бачить «неправильну» з його точки зору поведінку і не знає що до цього вже був баг де домовилися зробити саме так (але, звичайно, у вимогах це не відобразили).
Отже не дарма кажуть що чітко сформульована задача — це половина рішення. Код — це тільки форма рішення придатна для машини. Перш, ніж писати код — спочатку потрібно написати рішення мовою, зрозумілою для людини.

А ще є «Вискосна секунда», коли в хвилині 61 або 59 секунд. Вся галузь стогне від цього костиля. uk.wikipedia.org/wiki/Високосна_секунда

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

вимоги можуть змінюватись або бути нелогічними на перший погляд. дуже допомагає описувати вимоги у таск трекері (джира чи будь що) — як на етапі планування, так і підчас змін посеред ітерації. а потім лінкувати таск трекер до пулреквестів чи коммітів.
в мене в самого були не раз ситуації, коли дивишся на код і думаєш «що це таке», потім знаходиш таску 3річної давності, яку добра людина детально описала і одразу «а ось воно що»

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

От прикинь, треба тобі зробити в хаті ремонт, скажімо тобі особисто хочеться нові обої та замінити світильники. Приходе такий прораб, каже ай-яй-яй. Якщо я зараз зніму старі обої, то під ними стара індійська штукатурка яка осипатиметься. А також у вас тут алюмінієва погана проводка, яку теж треба усю замінити мідною, а краще посеребряною, проводи вкласти в гофри і т.д. На пів року естімейту і бюджет на пів вартості квартири. Що ти зробиш.? Швидше за усе підеш до іншого прораба, який привезе бригаду молдован чи таджиків, а ті по клеять нові обої прямо на старі і просто замінять світильники. Це я про, що ? — Усе дуже відносно, не завжди у клієнтів є бажання і гроші робити, щоб «дуже добре було». Згодний замовник на капітальний ремонт — добре, не згодний теж напевно добре. І не важливо хто замовник, в продуктовій команді він просто із вами в одній організації працює. Так само власний проект можна вилизувати до досконалості за власним розумінням досконалості, або нашвидкоруч зробити MVP та прогорнутись. Технічний борг, це те чим має керуватись швидше власник. Якщо бачить, що система дісталась рівня ентропії коли треба робити реплатформінг — це його справа. Хоче підтримувати COBOL — теж його справа. Тут дієвий метод з нашої сторони один — просто не братись за COBOL, ввічливо відмовлятись від таких пропозицій.

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

Так і відбувається, як мінімум з львівськими прорабами. А інший прораб каже те саме. Яка бригада молдаван зараз?
Ще треба повозитись, щоб висмикнути конкретного виконавця, який просто переклеїть обої. При тому іноді настільки, що простіше буде самому зробити. (Взагалі я пробую шукати переселенців, вони менше виносять мозг)

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

Залежить від цілі.
Якщо тобі в цій хаті жити багато років, то каще слухати прораба.
А вот йкщо хата на продаж чи під аренду, тоді можна обої можна поверх старих наліпити щоб стіни не розсипались.

Йдеться річ більше про те, що в ІТ часта ситуація, коли для компанії ситуація перша, а менеджери ради премій та покращення КПІ роблять друге по колу.
А коли вже слої обоїв перестають тримати стіни, тоді компанія «дізнаеться» що потрібно будувати новий дім, так как цей аварійний і взагалі завіть пів року ще не простоїть.

Я дуже багато разів це бачив, коли нанімають спеціалістів, але не слухають їх, так як «вас наняли кліїти обої»

Pull request аж два дні на закриття? Щось занадто. За статтю дуже вдячний, так і є. Особливо документація, ніхто не хоче писати хорошу документацію.

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

До речі, крута штука з моєї практики — Documentation as code. Просто редагуєш набір файликів *.MD. Це дуже цікавий підхід, бо ти можеш не лише код ревʼювати, а й документацію з одного інтерфейсу. З переваг: синхронність з кодом, файлики легко конвертуються в красиві html і апдейтити разом з релізом.

This is great strategy! We store docs in the same repository as a code — github.com/...​iaMetrics/VictoriaMetrics . The docs are stored inside “docs” folder, and the docs.victoriametrics.com is re-generated with each new commit pushed to master branch.

Підписатись на коментарі