Ланністери завжди платять за боргами. Як звучить девіз Ланністерів? Юрій Болдирєв розмазує дрібного підкремлівського блогера Роджерса

Практики управління технічним боргом в окремо взятій команді


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


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


Що вдалося отримати в результаті:

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

Давайте розповім, як ми цього досягли.

Що таке технічний обов'язок

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


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


З цього випливає, що поява технічного боргу неминуча у будь-якому довгоживучому проекті.

Коли технічний борг не проблема

Чим поганий технічний обов'язок? Він збільшує вартість подальшої розробки за рахунок низки факторів:

  • Знижується швидкість реалізації нової функціональності.
  • Збільшується ймовірність регресії при виправленні дефектів.
  • Процес розробки стає менш передбачуваним, отже, менш керованим.
  • Подовжується процес введення нового розробника у проект.

Ці втрати іноді називають «відсотками з технічного обов'язку»


Бувають ситуації, коли ці втрати обходяться дешевше, ніж усунення технічного боргу:

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

Що робити з технічним обов'язком? Невдалі підходи

Підхід № 1. "У нас немає часу, реліз треба здати вчора"

Прагнення встигнути у завтрашній дедлайн за будь-яку ціну, на шкоду швидкості розробки післязавтра.


Іноді швидкомонтована конструкція з милиць - об'єктивно правильний вибір. У моїй практиці це було найяскравіше виражено під час виготовлення демоверсій до виставок. Дата заходу жорстко зафіксована, якщо не встиг до важливої ​​виставки – наступна спроба буде за рік. Показувати продукт при цьому можна з рук, акуратно обходячи всі баги. Мені, як інженеру, робити такі проекти неприємно, але милиці в них виправдані.


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

  1. з реалізації самої милиці,
  2. з його наступної заміни на повноцінне рішення,
  3. з страждань від милиці в проміжку між попередніми пунктами.

Другий пункт дуже легко недооцінити, а про третій найдорожчий є ризик не подумати зовсім.


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


Підхід № 2. "Та тут треба все викинути і написати заново"

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


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

Підхід № 3. «Рефакторитимемо ночами і у вихідні, щоб менеджер не дізнався»

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


Що в цьому поганого? О, ціла купа речей:

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

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

Наші принципи

1. Додавати технічні завдання до загального беклогу

Існує ряд закономірностей із життя завдань у проектах:

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

Про ці речі дуже добре розповідає Максим Дорофєєв у своїй «Техніці порожнього інбоксу»


Щоб технічний борг не збирався, роботи з його усунення варто оформляти з огляду на принципи, перераховані вище.


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

  • Якщо код має нетривіальне TODO, воно містить посилання на завдання в белогу. Ми перевіряємо дотримання цього принципу на code review та не приймаємо складні TODO без посилань.

    За коментарем може ховатися драма

    Одного разу поряд з таким TODO було написано: «Милиця. Product Owner змусив мене зробити це. Заберіть якнайшвидше».

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

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

2. Планувати технічні історії з бізнес-пріоритетів

Якщо в лісі дерево впало, але цього ніхто не чув, чи був звук? Якщо проект має поганий код, але цей модуль ніколи не потрібно змінювати, чи є технічний борг?


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


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


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


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


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

3. Залишати код чистіше, ніж він був до тебе

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

  • Приведення до стилю оформлення модулів.
  • Зміна внутрішніх назв змінних більш зрозумілі.
  • Спрощення реалізації за збереження поведінки.
  • Локальні рефакторинги, що не вносять масштабних змін до інших модулів.

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


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

4. Що б не відбувалося, система має залишатися в робочому стані

Один із базових принципів SCRUM говорить, що наприкінці кожного спринту система має приходити у стабільний стан.


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

Будь-які роботи з усунення технічного обов'язку робляться з дотриманням цього принципу.


Великі перетворення обов'язково декомпозуються так, щоб будь-який окремий етап можна було закінчити за один спринт. Наприклад, систему збирання ми змінювали в два етапи (Angular 1.x: webpack, що крадеться, причаївся grunt)


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


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


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

Як виглядає наш процес

Раз у реліз робимо докладне реву технічного беклогу:

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

З появою бізнес-історій на горизонті робиться технічний аналіз і з бізнес-історією пов'язуються всі технічні історії, які б допомогли в реалізації.


Під час підготовки до планування спринту:

  • Перевіряємо зв'язки технічних та бізнес-історій.
  • Прив'язуємо до технічних історій усі пов'язані баги, які можна дешево виправити у тому місці.

Як формувати технічну частину беклогу

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


Поточне наповнення бэклога технічними завданнями відбувається рахунок описаних вище практик і вимагає окремих зусиль чи аналізу. Крім цього, в беклог додаються нові ідеї з технічного вдосконалення продукту. Це робить будь-який член команди, якому така ідея спала на думку. Головне на цьому етапі – не втратити ідею. Уточнення та визначення пріоритету відбуваються вже згодом, у ході планування робіт.

Висновки

  • Технічний обов'язок неминучий.
  • Для більшості проектів усунення технічного боргу – це гарне вкладення зусиль.
  • Якщо усуненням технічного боргу займатися, швидкість розробки поступово прагнутиме нулю.
  • Спокуса викинути все і написати заново може вбити або сильно покалічити ваш проект.
  • Користу від усунення технічного боргу варто формулювати в ключі користі для бізнесу, інакше є ризик того, що завдання створення нової функціональності завжди будуть вважатися важливішими.
  • Завданнями щодо усунення технічного боргу варто керувати. Такі завдання нічим не відрізняються від інших проектних завдань щодо обліку, планування, пріоритизації.
  • Регулярно виникають ситуації, коли можна зменшити технічний борг та одночасно вирішити бізнес-завдання дешевше, ніж зробити це окремо. Ці можливості треба використати.
  • Продумані та вчасно оновлювані угоди про стиль коду та процес рев'ю допомагає уповільнити виникнення нового технічного боргу.
  • Короткі ітерації корисні для рефакторингів щонайменше, ніж розробки нової функціональності.
  • Команда зазвичай знає, де у проекті технічний обов'язок і наскільки він страшний. Варто використати це знання при формуванні уявлення про технічний обов'язок проекту.

У своїй відповіді я торкнуся не лише Великих будинків, а й деяких інших будинків, інформацію про які мені вдалося добути.

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

2. Ланністери- біля будинку Ланністерів ніби два девізи, один - підтверджує грізний герб -" Почуй мій рев!", другий, що прирівнюється до приказки, але звучить на порядок частіше ніж перший -" Ланністери завжди платять свої боргиПерший девіз можна віднести безпосередньо до герба. На гербі Ланністерів зображено lion rampant-"Лев рикаючий", а девіз "Почуй мій рев" його безпосередньо доповнює, також це свідчення того, що лев - цар звірів, а у Ланністерів - високе становище в суспільстві. Приказка "Ланістери завжди платять свої борги" насамперед пов'язана із Залізним Банком Браавосу «Залізний банк завжди отримає своє». У другу чергу "Ланістери завжди платять свої борги" означає, що Ланністери ніколи не забувають тих, хто їм допоміг і що Ланністери ніколи не прощають заподіяного їм зла.

3. Баратеон - "Нам лють". спочатку належав Дюррандонам зі Штормової Межі. Оріс Баратеон (незаконнонароджений брат Ейгона I Завойовника), вбивши Аргілака Пихатого, останнього Лорда Штормових земель, перейняв і його девіз. Але девіз був перекладений занадто буквально. Наводить логічний переклад девізу". Гнів – наша стихія", з поясненням його значення" Гнів – наша стихія, що означає: коли ви нас злите, ви викидаєте рибу в море, де вона себе чудово почуває."Тобто для Баратеонів буйний прояв емоцій на шкоду холодному розуму - не порок.

4. Грейджою - "Ми не сіємоГрейджої в більшості своїй - пірати. Територія їх земель знаходиться на голих скелях та піску. Девіз цього будинку є прямим посилом того, що Грейджої не працюють на землі (який так і немає до ладу). Вони нічого не сіють і нічого не вирощують, вони грабують тих, хто має врожай і видобуток, оскільки свого вони немає і не може.

5. Таргарієн - "Полум'я та кровДевіз Таргарієнов можна витлумачити двома способами. Перший - Ейгон Завойовник і дві його сестри, на трьох драконах підкорили собі Вестерос, що називається "онем і мечем". Таргарієни - дракононароджені, у них кров Стародавньої Валірії та драконів, а також бонусом несприйнятливість до вогню, та ручні дракони. Коли таргарієни говорять Fire and Blood, вони нагадують про це тим, хто раптом забув."

6. Аррени - "Високий як честьЗ одного боку - Будинок Арренів, на прикладі Джона Аррена, дбав про збереження честі. Джона неможливо було залякати чи підкупити. І на землях Вестероса не можна було знайти нікого, хто дбав би про збереження честі більше, ніж Аррени. Але після смерті Джона , Імовірно більш застосовний інший варіант - аристократична зарозумілість, зневага до нижчих за статусом, мовляв "куди вам до нас".

7. Тарлі - "Перші у битвіБудинок Тарлі породив багатьох великих воїнів і видатних генералів, що і підтверджує даний девіз.

8. Таллі - "Сім'я, борг, честьБудинок Таллі вірний насамперед своїм сімейним узам. Борг і честь у них йдуть після, але сім'я – насамперед. Дім Таллі підтримав Роба Старка у Війні П'яти королів, за що й поплатився.

9. Мартели - "Непохитні, непохитні, непорушніМартелли - єдиний будинок, який Таргарієни не змогли взяти силою. І за поведінкою персонажів цього будинку цілком собі помітно, що вони свавільні та непохитні. Їм не потрібні закони Лордів, схвалення Королів, вони самі по собі, але явно показують, що здаватися вони готові.

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

11. Болтон -"Наші клинки гостріДаний девіз служить скоріше попередженням ворогам (і не тільки) сім'ї Болтон. Представники цього будинку мають похмуру репутацію, у книгах так зовсім носили плащі з людської шкіри і нею ж прикрашали стіни своїх замків: "У голої людини немає секретів, а у освіженого і поготів". "Наші клинки гострі" - мабуть також може означати клинки для освіження плоті.

12. Мормонт - "Тут ми стоїмо". Девіз, який згідно з версією Sunsetsolitude також неправильно переведений на російську. " Here we stand - може означати "Тут наші землі", що в свою чергу означає "Маленький, але гордий острів, який нікого не чіпає, але за себе визначити зуміє. Тут наші землі, пам'ятайте про це, коли потикатиметеся сюди, ми вас попереджали." Або можна перекласти як "На тому стоїмо" - що буде прямою вказівкою на силу впертості Мормонтов"

13. Фрей - "Стоїмо пліч-о-плічФреї цінували сімейні узи і непорушність даного слова, що й відбивав цей девіз. Звідти у Волдера Фрея була невимовна образа на Роба Старка, який порушив свою обіцянку одружитися з його дочкою, що і призвело до сумних наслідків.

"Ланністер завжди платить свої борги". © FFG ( Джейсон Енгл (Jason A. Engle))

Ланістери завжди платять свої борги(також: «Ланністер завжди сплачує свої борги») - популярна в Семи королівствах приказка про будинок Ланністерів і улюблений вислів Тіріона Ланністера. Вона не менш відома, ніж «офіційний» девіз будинку, «Почуй мій рев!». Цей вираз має подвійне значення. З одного боку, воно означає, що Ланністери, як найбагатший будинок у державі, завжди готові заплатити за рахунками та віддячити тим, хто їм допоміг, або пообіцяти винагороду в майбутньому – на щедрість та обов'язковість «левів» завжди можна розраховувати. Але цей девіз має також другий, загрозливий сенс: Ланністери не забувають завданих їм образ і обов'язково помстяться кривдникам.

В устах Серсеї Ланністер приказка звучала в промові, зверненій вже проти самого Тіріона - Серсея звинувачувала брата в інтригах проти неї та Джоффрі і намагалася шантажувати схопленою Алаяєю. Пізніше, опинившись на чолі держави, Серсея тими ж словами доводила рішення припинити виплату державних боргів Залізному Банку Браавоса-Ланністери завжди сплачують свої борги, і цей борг рано чи пізно буде сплачено. Пізніше вона згадувала приказку в діалозі з Бальманом Берчем і Фалісою Стокворт, обіцяючи їм нагороду за допомогу, а потім відправила тирошійця, який спробував обдурити її до ката зі словами «Ланістери платять свої борги, і ти теж заплатиш».

Тайвін Ланністер згадував приказку в розмові з Тіріоном, обґрунтовуючи необхідність віддати Харренхолл Петіру Бейлішу, якщо він сам того побажав. Тіріон сам повторив слова про борги, вимагаючи нагороди вже собі за свої заслуги на посту правиці. Шая повторювала приказку, нагадуючи Тіріону про обіцянку знову поселити її у міському будинку. Дізнавшись про перехід Вестерлінгів на бік Робба Старка, Тіріон думав про себе, що Тайвін неодмінно покарає зрадників, і пригадав приказку.

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

Сам Едмар Таллі згадував приказку, дізнавшись про вбивство Рікардом Карстарком Віллема Ланністера та Теона Фрея. Русе Болтон, говорячи про намір покинути Харренхолл і залишити його Варго Хоуту, говорив «Ланістери не єдині, хто платить свої борги». Джейме повторив приказку при недоброму прощанні з Бравими Дітлахами при від'їзді із замку, натякаючи, що помститься їм, а потім, повернувшись у замок за Брієною, звернувся з тими самими словами до Варго Хоута, кажучи, що той отримає викуп і за Джейме, і за Брієнну

Практики управління технічним боргом в окремо взятій команді


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


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


Що вдалося отримати в результаті:

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

Давайте розповім, як ми цього досягли.

Що таке технічний обов'язок

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


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


З цього випливає, що поява технічного боргу неминуча у будь-якому довгоживучому проекті.

Коли технічний борг не проблема

Чим поганий технічний обов'язок? Він збільшує вартість подальшої розробки за рахунок низки факторів:

  • Знижується швидкість реалізації нової функціональності.
  • Збільшується ймовірність регресії при виправленні дефектів.
  • Процес розробки стає менш передбачуваним, отже, менш керованим.
  • Подовжується процес введення нового розробника у проект.

Ці втрати іноді називають «відсотками з технічного обов'язку»


Бувають ситуації, коли ці втрати обходяться дешевше, ніж усунення технічного боргу:

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

Що робити з технічним обов'язком? Невдалі підходи

Підхід № 1. "У нас немає часу, реліз треба здати вчора"

Прагнення встигнути у завтрашній дедлайн за будь-яку ціну, на шкоду швидкості розробки післязавтра.


Іноді швидкомонтована конструкція з милиць - об'єктивно правильний вибір. У моїй практиці це було найяскравіше виражено під час виготовлення демоверсій до виставок. Дата заходу жорстко зафіксована, якщо не встиг до важливої ​​виставки – наступна спроба буде за рік. Показувати продукт при цьому можна з рук, акуратно обходячи всі баги. Мені, як інженеру, робити такі проекти неприємно, але милиці в них виправдані.


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

  1. з реалізації самої милиці,
  2. з його наступної заміни на повноцінне рішення,
  3. з страждань від милиці в проміжку між попередніми пунктами.

Другий пункт дуже легко недооцінити, а про третій найдорожчий є ризик не подумати зовсім.


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


Підхід № 2. "Та тут треба все викинути і написати заново"

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


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

Підхід № 3. «Рефакторитимемо ночами і у вихідні, щоб менеджер не дізнався»

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


Що в цьому поганого? О, ціла купа речей:

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

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

Наші принципи

1. Додавати технічні завдання до загального беклогу

Існує ряд закономірностей із життя завдань у проектах:

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

Про ці речі дуже добре розповідає Максим Дорофєєв у своїй «Техніці порожнього інбоксу»


Щоб технічний борг не збирався, роботи з його усунення варто оформляти з огляду на принципи, перераховані вище.


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

  • Якщо код має нетривіальне TODO, воно містить посилання на завдання в белогу. Ми перевіряємо дотримання цього принципу на code review та не приймаємо складні TODO без посилань.

    За коментарем може ховатися драма

    Одного разу поряд з таким TODO було написано: «Милиця. Product Owner змусив мене зробити це. Заберіть якнайшвидше».

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

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

2. Планувати технічні історії з бізнес-пріоритетів

Якщо в лісі дерево впало, але цього ніхто не чув, чи був звук? Якщо проект має поганий код, але цей модуль ніколи не потрібно змінювати, чи є технічний борг?


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


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


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


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


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

3. Залишати код чистіше, ніж він був до тебе

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

  • Приведення до стилю оформлення модулів.
  • Зміна внутрішніх назв змінних більш зрозумілі.
  • Спрощення реалізації за збереження поведінки.
  • Локальні рефакторинги, що не вносять масштабних змін до інших модулів.

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


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

4. Що б не відбувалося, система має залишатися в робочому стані

Один із базових принципів SCRUM говорить, що наприкінці кожного спринту система має приходити у стабільний стан.


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

Будь-які роботи з усунення технічного обов'язку робляться з дотриманням цього принципу.


Великі перетворення обов'язково декомпозуються так, щоб будь-який окремий етап можна було закінчити за один спринт. Наприклад, систему складання ми змінювали у два етапи.


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


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


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

Як виглядає наш процес

Раз у реліз робимо докладне реву технічного беклогу:

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

З появою бізнес-історій на горизонті робиться технічний аналіз і з бізнес-історією пов'язуються всі технічні історії, які б допомогли в реалізації.


Під час підготовки до планування спринту:

  • Перевіряємо зв'язки технічних та бізнес-історій.
  • Прив'язуємо до технічних історій усі пов'язані баги, які можна дешево виправити у тому місці.

Як формувати технічну частину беклогу

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


Поточне наповнення бэклога технічними завданнями відбувається рахунок описаних вище практик і вимагає окремих зусиль чи аналізу. Крім цього, в беклог додаються нові ідеї з технічного вдосконалення продукту. Це робить будь-який член команди, якому така ідея спала на думку. Головне на цьому етапі – не втратити ідею. Уточнення та визначення пріоритету відбуваються вже згодом, у ході планування робіт.

Висновки

  • Технічний обов'язок неминучий.
  • Для більшості проектів усунення технічного боргу – це гарне вкладення зусиль.
  • Якщо усуненням технічного боргу займатися, швидкість розробки поступово прагнутиме нулю.
  • Спокуса викинути все і написати заново може вбити або сильно покалічити ваш проект.
  • Користу від усунення технічного боргу варто формулювати в ключі користі для бізнесу, інакше є ризик того, що завдання створення нової функціональності завжди будуть вважатися важливішими.
  • Завданнями щодо усунення технічного боргу варто керувати. Такі завдання нічим не відрізняються від інших проектних завдань щодо обліку, планування, пріоритизації.
  • Регулярно виникають ситуації, коли можна зменшити технічний борг та одночасно вирішити бізнес-завдання дешевше, ніж зробити це окремо. Ці можливості треба використати.
  • Продумані та вчасно оновлювані угоди про стиль коду та процес рев'ю допомагає уповільнити виникнення нового технічного боргу.
  • Короткі ітерації корисні для рефакторингів щонайменше, ніж розробки нової функціональності.
  • Команда зазвичай знає, де у проекті технічний обов'язок і наскільки він страшний. Варто використати це знання при формуванні уявлення про технічний обов'язок проекту.

КАТЕГОРІЇ

ПОПУЛЯРНІ СТАТТІ

2024 «kingad.ru» - УЗД дослідження органів людини