Динамика нарастания долгов
Теперь рассмотрим динамику нарастания долгов и их оплату реальными деньгами. Закрашенная серая площадь показывает общую сумму, которую потратили не на сам проект, а на оплату за технические долги.
Рисунок показывает на сколько больше денег было потрачено на проект из-за долгов в коде.
Интересно отметить тенденции:
- До первого релиза проекта идет интенсивное наращивание функциональности. Работа кипит.
- В какой-то момент (первая красная точка) программисты понимают, что без улучшения качества кода будет трудно двигаться вперед. Этот момент показывает спад долгов в коде (до первой зеленой точки).
- Перед релизом приходит руководитель проекта и начинает подгонять команду, напоминать о приближающихся сроках или, что еще хуже, эти сроки урезать. Здесь мы видим резкий скачок. В этот момент увеличивается как само количество долгов в коде, так и выплаты по уже существующим.
Эта тенденция повторяется от релиза к релизу. Чем больше мы работаем с проектом, тем больше мы платим за оставленные в коде долги.
Continuous Inspection – ключевые принципы
Что же вообще такое Continuous Inspection (непрерывная инспекция кода), какие у нее ключевые принципы и из чего она состоит?
Основной ее постулат заключается в том, что качество – это общая задача всей команды разработки и результат выполнения этой задачи зависит непосредственно от самих разработчиков, потому что они производят код, за который несут ответственность.
Второй ключевой принцип – это актуальность информации. Если мы проверяем нашу систему и получаем о ней какие-то качественные показатели, мы должны их получать регулярно, чтобы у нас под рукой всегда была актуальная информация о текущем состоянии нашей кодовой базы.
Данные о качестве (как показатели, так и какие-то списки замечаний), мы должны получать не только в абсолютных значениях, но и в разностных. Мы должны понимать, а что же у нас изменилось за неделю с выхода прошлой версии, за день и т.д.
Проверка качества должна быть автоматизированной, и мы в идеале должны исключить каких-то конечных людей (внешних аудиторов либо самих разработчиков в плане ручного code-review), чтобы проводить эти проверки автоматически.
И еще один ключевой принцип – стандарты качества должны быть едиными для всех проектов. Часто бывает ситуация, когда какая-то команда уже 8 лет внедряет УПП, а теперь начала внедрять УТ 11 на управляемых формах. И в головах возникает такое отношение – проекту по УПП уже 8 лет, 1С этот продукт уже давным-давно не поддерживает, там уже в принципе все плохо и за его качеством можно не следить. А вот для УТ 11 в плане контроля качества еще можно что-то сделать, поэтому следить будем только за ним. Это – неправильно. Не смотря на то, что УПП – это система, которая разрабатывается давным-давно, стандарты качества к ней точно такие же. Просто здесь на первый план выходят не абсолютные показатели (когда мы знаем, что за 8 лет разработки у нас накопилось 10 лет технического долга), а именно относительные – когда мы разрабатываем новую версию функциональности, мы должны быть уверенными в том, что мы ее сделали качественно.
Последний ключевой принцип – это то, что все новые замечания, особенно критические, должны иметь ответственного. И если у нас несколько человек в команде, то каждое выявленное замечание по качеству должно относиться на конкретного разработчика
Может быть, он уже уволился – это неважно, но в принципе, мы должны понимать, кто привел к конкретной проблеме.
Как объяснить бизнесу, что рефакторинг необходим
Владельцам софта нужна прибыль, поэтому они не хотят затягивать процесс разработки и бороться с техдолгом — особенно если близок старт продаж. Однако долг всегда приходится возвращать — иначе он создаёт проблемы в будущем продукте.
Конфликт разработчиков и бизнеса из-за рефакторинга — один из самых запутанных и сложных. Если игнорировать и копить техдолг, то разработчики потеряют мотивацию, а компания станет «техническим банкротом». Если же включить режим перфекциониста и слишком сильно фокусироваться на долге, конкуренты получат преимущество в скорости, быстрее выпустят новые фичи и захватят рынок. А полученную в ходе экспансии прибыль они вложат в погашение критичного долга — и останутся в выигрыше.
Вообще, Уорд Каннингем придумал концепцию техдолга именно для того, чтобы в понятных для бизнеса терминах аргументировать необходимость рефакторинга. Метафора простая: первая версия программы — как заём в банке. А каждая минута, которая тратится на исправление «костылей» в коде, — как проценты по кредиту. Если проценты долго не гасить, банк истребует весь долг и компания может закрыться. Однако небольшой долг, как и разумно взятый кредит, ускоряет разработку и помогает расти, главное — выплачивать его вовремя.
«Представьте платформу для нескольких независимых друг от друга клиентов (из терминологии «клиент — сервер». — Прим. ред.). У каждого есть собственный сервис, весьма требовательный к аппаратным ресурсам. Пока клиентов мало, эта схема работает. Когда же количество клиентов резко увеличивается, возникает необходимость менять архитектуру и запускать один сервис, который будет обслуживать всех, вместо нескольких копий, работающих параллельно. А это уже экономия в чистом виде и вполне убедительный аргумент для бизнеса.
Пока критической ситуации не возникло, многие воспринимают технический долг как нечто абстрактное. К сожалению, часто осознание приходит, только когда бизнес теряет деньги или несёт репутационные потери
Но после этого он сразу понимает важность рефакторинга»
Николай Мельников, руководитель компании Sebbia
Важный момент: договариваться о ресурсах и времени команды, которые будут тратиться на рефакторинг, лучше до начала работ. Потому что вовремя гасить технический долг — критично для любого программного продукта. С заказчиком необходимо говорить на его языке: объяснять финансовые риски и приводить примеры из жизни.
«У нас в BestDoctor есть договорённость, что один день в неделю каждый программист выделяет на работу с техническим долгом и автоматизацию, которая улучшает жизнь всей команде разработки. Этот день полностью посвящён не продуктовым, а инженерным задачам. Я рекомендую ввести обязательный процесс отдачи технического долга раз в неделю или раз в две недели. Это позволит не запускать его».
Михаил Корнеев, тимлид в BestDoctor, автор YouTube-канала «Хитрый питон»
Качественный рефакторинг возможен, только если вы «брали» техдолг осознанно, понимали, что перфекционизм в этот момент навредил бы бизнесу, и фиксировали момент создания долга. Поэтому небрежно писать код и думать, что исправишь всё когда-нибудь потом, — плохая идея.
«Если уже сложилась ситуация, когда надо немедленно реагировать и что-то делать с техдолгом, значит, что-то не так с процессами. Нужно сразу планировать работу так, чтобы оставалось время на рефакторинг — от 5% до 33% рабочей недели. Команда должна знать, что у неё есть выделенное время для таких задач».
Николай Мельников, руководитель компании Sebbia
Педагогический терминологический словарь
этическое понятие, которое обозначает нравственно аргументированное принуждение к поступкам; нравственную необходимость, фиксированную в качестве субъективного принципа поведения. Д. выражает императивность морали. Действия, поскольку они мотивированы Д., именуются обязанностями. Русское слово «Д.» имеет ещё второй смысл (то, что взято взаймы).
Начало теоретического осмысления Д. восходит к стоической школе, к предложенному Зеноном из Кития выделению в человеческом поведении двух срезов: собственно нравственного и надлежащего.
В книге «Об обязанностях» Цицерон трансформировал стоическое учение о Д. таким образом, что два способа мотивации поведения были интерпретированы как две разные ступени нравственного поведения. Он подразделял обязанности на «совершенные», которые может достичь только мудрец, и «обыкновенные», или «средние», которые касаются всех людей. Фома Аквинский обосновывал Д., исходя из необходимо заданной цели — Бога, божественного устройства мира. Все действия, направленные на её достижение, также становятся необходимыми, т.е. обязанностями, Д. Согласно противоположной точке зрения (Августин, Дунс Скот, Оккам), источником норм и обязанностей является ничем не скованная воля Бога. Новой попыткой синтеза этих аспектов в рамках новоевропейской теории естественного права стала версия Д., согласно которой сама процедура честного соглашения налагает на человека обязательство по отношению к обязательствам, зафиксированным в соглашении.
В своей этике (принято называть её этикой Д.) Кант связывал с понятием Д. специфику нравственности: нравственный закон выступает в форме категорического императива и его субъективной опорой, благодаря которой он приобретает действенность, является Д. Нравственный закон является абсолютно необходимым, всеобщим и общезначимым. Он был бы единственным основанием разумной воли, если бы речь шла о совершенном разумном существе. Однако человек несовершенен, ибо на его волю помимо разума воздействуют склонности, и для него нравственный закон выступает в форме безусловного принуждения к поступку. Соответственно единственным субъективным основанием, благодаря которому нравственный закон обретает действенность, является Д. Он есть принуждение к поступку нравственным законом; Д. и категорический императив — по сути дела одно и то же. Д. принимает в расчёт только способность максимы быть требованием всеобщего законодательства, о чём говорит первая формулировка категорического императива. Нравственным, по Канту, можно признать только такой поступок, который не просто сообразен Д., а совершается ради Д. Вторая формулировка категорического императива вменяет в Д. относиться к человечеству (человечности) в лице каждого индивида как к цели и никогда не относиться к нему только как к средству. Третья — рассматривает нравственный закон как автономию воли. Д. есть моральный закон, явленный как человеческий мотив. Механизм Д. — уважение к нравственному закону и достоинству человека, поскольку он обладает автономией воли и творит этот закон из себя. Понятие «уважение», присоединённое к двум другим понятиям: «необходимость поступка» и «закон» даёт определение Д. — это «необходимость поступка из уважения к закону».
В современной философии ценностный статус Д. снижен, Д. смещается на периферию моральной жизни.
(Бим-Бад Б.М. Педагогический энциклопедический словарь. — М., 2002. С. 75)
Рефакторинг
Одним из способов борьбы с техническим долгом и легаси является рефáкторинг. Библией рефакторинга для разработчиков является книжка Мартина Фаулера «Рефакторинг: улучшение существующего кода».
Признаком хорошей программистской культуры является фоновый рефакторинг. Часы на него накидываются при оценке. При доработке модуля или исправлении дефекта, разработчик тут же производит рефакторинг этого модуля. Если к вам приходит архитектор и говорит, что код слишком «устал» и требуется уделить рефакторингу целую итерацию, это
Ранее я писал о том, что время от времени нужно «». Рефакторинг в целом, тоже относится к этой практике. Так вот, подтачивать пилу нужно в фоне, в процессе работы, чтобы не приходилось отвлекаться от основной работы на осязаемый промежуток времени. В общем, фоновый рефакторинг — наш выбор.
Если с заточкой пилы пролюбились, фоновый рефакторинг не работает, а на радикальный рефакторинг нужно слишком много времени, можно применить то, о чём я писал про Битрикс в начале статьи, то есть реинжиниринг. Не исключаю, что для реинжиниринга придётся нанять более квалифицированного архитектора.
Какие типы технического долга существуют и как их устранять
Существуют различные типы технического долга, и каждый из них требует своего подхода к его устранению:
-
Кодовый долг: Это недостатки в коде, такие как повторяющийся код, отсутствие комментариев и плохо структурированный код. Для устранения кодового долга необходимо провести рефакторинг кода, улучшить его читаемость, повысить модульность и внести необходимые исправления.
-
Долг по архитектуре: Когда архитектура программного продукта не соответствует требованиям, возникает долг по архитектуре. Это может быть связано с отсутствием модульности, плохой структурой проекта и недостаточным разделением ответственности. Для устранения долга по архитектуре необходимо провести анализ и переработку архитектуры, привести ее в соответствие с оптимальными практиками и требованиями продукта.
-
Долг по тестированию: Отсутствие достаточного покрытия юнит-тестами и интеграционными тестами может привести к нарушению функциональности программного продукта. Долг по тестированию может быть устранен путем создания недостающих тестов, автоматизации тестирования и тщательного тестирования функциональности.
-
Долг по документации: Отсутствие актуальной и полноценной документации может затруднять работу разработчиков и аналитиков. Долг по документации может быть устранен путем создания и обновления документации, описывающей архитектуру, функциональность и использование программного продукта.
-
Долг по безопасности: Небезопасные практики разработки, неправильные настройки и уязвимости могут привести к угрозам безопасности продукта. Долг по безопасности должен быть устранен путем проведения аудита безопасности, исправления выявленных проблем и внедрения соответствующих мер безопасности.
Устранение технического долга является постоянным процессом, требующим внимания и участия всей команды разработчиков. Путем систематического устранения технического долга можно значительно повысить качество и поддерживаемость программного продукта.
Типы долгов
В общем, все долги в коде можно разделить на несколько категорий. Все они разные по сути и по ущербу, который наносят, но конечный результат их действия на проект один и тот же — повышение затрат на разработку приложения.
Это самый простой и очевидный тип долгов. Они накапливаются, если программист делает ошибки при разработке проекта, неверно применяя шаблоны проектирования или неправильно используя принципы ООП.
В тоже время, это самый опасный тип долгов, т.к. разработчики не видят рисков. Они не могут правильно оценивать время на добавление новой функциональности или реорганизации уже работающей системы.
Кратковременные
При разработке проекта, мы всегда стараемся оставить его в положении наиболее выгодном для будущих изменений. Сделать ее более гибкой. Но большинство из нас пишет код для коммерческого использования. В условиях конкуренции нужно завоевывать рынки и опережать конкурентов бизнеса, на который мы работаем. Поэтому, когда сроки поджимают, руководитель проекта слышать не хочет про качественный код, ему нужен результат, причем быстро. Мы начинаем действительно быстро писать код. Оставлять дублирование, не писать тесты, использовать магические числа в коде в надежде, что после выхода очередной версии продукта мы это все исправим. Но правда в том, что мы этого никогда не исправим. Ни после этой версии, ни после какой-то другой. К тому же, если мы опустили планку качества в проекте, то эта планка будет падать с ускорением все ниже и ниже.
Долговременные
Эти долги лежат у самого основания нашего проекта. С ними мы миримся и договариваемся, что они являются нормой. К примеру, мы не будем поддерживать Oracle ни в какой версии нашей системы. С таким утверждением можно вполне спокойно развивать проект. Или например, система будет иметь пользовательский интерфейс на ASP.NET. Если приходится платить по этим долгам (например, переход с MS SQL на Oracle), то в конечном счете это означает создание качественно нового приложения.
Давайте дадим определение техническому долгу…
Часто под техническим долгом подразумевается поспешный процесс разработки или недостаток общих знаний у членов команды. Однако не забывайте, что во многих случаях технический долг неизбежен и является частью нормального процесса разработки программного обеспечения.
Например, инженеры могут не внедрить правильные паттерны проектирования в вашу инфраструктуру, потому что вы хотите сэкономить время на поставку новых функций. Другие примеры включают в себя отсутствие документации для обмена знаниями или низкое покрытие тестами кода.
Короче говоря, качество кода страдает в результате различных причин, таких как отсутствие обмена знаниями или поспешность в определенных аспектах жизненного цикла разработки. Вот краткий обзор наиболее значимых видов технического долга, которых следует избегать:
1. Технический долг, основанный на знаниях
Чтобы понять, что такое технический долг, основанный на знаниях, давайте рассмотрим пример. Представьте, что два инженера-программиста работали над новой функцией. Они владеют всеми знаниями об этой конкретной функции. Однако другие инженеры-программисты в вашей команде не обладают этими знаниями. Когда им придется работать над этой функцией или выполнять реализацию, использующую эту функцию, у них не будет знаний, необходимых для правильной реализации новой функции.
Поэтому очень важно активно делиться знаниями о функциях и важных изменениях в кодовой базе. Это включает в себя создание документации, примеров, тестов и обмен знаниями во время ретроспективных встреч
Обмен знаниями — один из самых простых методов решения проблемы технического долга.
2. Задолженность за дизайн
Задолженность по дизайну часто возникает на высококонкурентных рынках или в стартапах, где скорость выхода на рынок часто является наивысшим приоритетом.При быстрой поставке новых функций вы не думаете о структуре функций или архитектуре вашей кодовой базы. Этим часто пренебрегают, в результате чего добавлять новые функции становится все труднее. И теперь вам приходится исправлять это всей командой.
Поэтому проектный долг тесно связан со структурированием функций и следованием паттернам проектирования.
3. Задолженность по коду
Долг по коду — это написание плохого кода и несвоевременное его исправление. Например, разработчик хочет быстро объединить код, не написав достаточного количества тестов и не придерживаясь стандартов кода.
Многие организации используют инструменты автоматизации, такие как pre-commit hooks с линтингом кода для проверки качества кода. Если вы не применяете такие проверки кода, плохой код может быстро снизить общее качество вашей базы данных.
Бонус
Мы подготовили чек-лист признаков, указывающих на то, что бизнесу требуется CPM-система:
-
Нет возможности масштабировать расчёты и считать в детализации, которая обеспечит точность планирования.
-
Большое количество ошибок в расчётах в связи с человеческим фактором.
-
Необходимость разграничивать права доступа и гибко ими управлять, определять области видимости данных между сотрудниками.
-
Отсутствует или ограничена возможность работать в совместном доступе над одним и тем же блоком разным людям, при том что такая необходимость есть.
-
Тратится много времени на перенос драйверов расчёта из систем-источников (например, ручные выгрузки с ручным копированием из выгрузок).
-
Невозможно проследить расчёт от конечной цифры до исходных данных.
-
Сложно поддерживать изменения модели – переход на новый год планирования/ появление новых аналитических разрезов или новых элементов в них приводит к необходимости долго и мучительно перестраивать всю модель.
-
Невозможность контроля действий пользователей, отсутствие логирования.
-
Не хватает ресурсов проводить планирование по различным сценариям или делать ежемесячно скользящий прогноз.
-
Не выдерживаются сроки/ получаемый результат требует дополнительной интерпретации.
-
Отсутствие возможности получать обновлённые версии ПО/ возможность утраты лицензии или поддержки зарубежного вендора.
Дорогой читатель, мы знаем, что публика Хабра довольно разнообразна: есть большое число знатоков всего и вся вокруг ИТ-технологий, но также есть и те, которые хотят структурировать свои знания и даже глубже в чём-то разобраться. Возможно, есть и непосредственно представители бизнеса, которые хотели бы уже сейчас, пробежав по чек-листу, оценить необходимость перехода на современные CPM-решения. Мы готовы проконсультировать и помочь определиться. Пишите нам на fi@glowbyteconsulting.com. С радостью ответим на ваши вопросы.
В следующей публикации планируем рассказать о том, какие отечественные CPM-решения есть на российском рынке и чем они хороши.
3 лучших способа борьбы с технической задолженностью и ее предотвращения
Техническая задолженность растет с каждым днем, и лучшее время для внедрения процесса ее решения — сейчас. Вот несколько проверенных методов.
1. Рефакторинг кода и архитектуры
Одно из самых простых решений для предотвращения и/или устранения задолженности по коду и дизайну — организация недели рефакторинга каждые X спринтов. Неделя рефакторинга позволяет вашей команде устранить открытые ошибки, оценить текущую архитектуру и подготовить архитектуру для предстоящих функций продукта.Например, выделите время, чтобы подумать о том, как новые функции могут повлиять на архитектуру вашей кодовой базы.
Польза: неделя рефакторинга дает разработчикам необходимую передышку для оценки и осмысления кода перед внедрением нового набора функций. Это отлично подходит для решения больших проблем.
Недостатки: Процесс разработки замедляется, пока вы проводите рефакторинг, и ваша команда не решает проблемы постоянно.
2. Начните регулярные обсуждения технического долга
Ретроспективные встречи — это золотой стандарт обмена знаниями между инженерами. Можно даже привлечь к этим встречам больше заинтересованных сторон, например, владельцев продукта, чтобы создать общее понимание кодовой базы и проблем, с которыми сталкиваются инженеры.
На ретроспективном совещании рассматривается, что прошло хорошо, а что нет. Это открытый этап для обмена мнениями без возложения вины. Будет лучше, если вы сосредоточитесь на улучшении.
Преимущество: Вы можете использовать ретроспективные совещания для обмена новостями о коде. Инженеры могут показать, чего они достигли. В основном, несколько инженеров получают возможность представить свои изменения в кодовой базе и объяснить, как это влияет на кодовую базу или как они этого добились. Поэтому ретроспективное совещание — это отличный инструмент для обмена знаниями после каждого спринта кодирования.
Недостатки: Заинтересованные стороны и руководители должны быть согласны с концепцией и предоставить инженерам время для организации таких встреч.
3. Начните отслеживать технический долг в своем редакторе
Лучшее, что вы можете сделать для здоровья вашей кодовой базы, — это максимально упростить инженерам решение технических проблем. Отслеживание технического долга в редакторе позволяет инженерам:
- Получить полную информацию о технической задолженности
- Просмотр контекста для каждой проблемы кодовой базы
- Сократите переключение контекста
- Постоянное решение технических проблем
Вы можете использовать различные инструменты для отслеживания технического долга, но самый быстрый и простой способ начать работу — использовать бесплатные расширения Stepsize для VSCode или JetBrains, которые интегрируются с Jira, Linear, Asana и другими инструментами управления проектами.
Преимущество: Разработчики и так проводят большую часть времени в редакторе, поэтому это лучшее место для отслеживания и сообщения о технических проблемах. Внедрение процесса управления техническим долгом положительно скажется на моральном состоянии команды инженеров и удовлетворенности клиентов.
Недостатки: Запуск новой привычки требует времени и усилий от членов команды, и без героя технического долга здесь не обойтись.
Что такое костыли
Я не знаю где этот термин появился впервые, но сейчас, когда разработчики и менеджеры говорят про «костыли в коде», они имеют в виде изменения, несовместимые с текущей архитектурой и приделанные к ней снаружи, только чтобы удовлетворить требования заказчика. Как человеку с больной ногой выдают костыль, чтобы он мог хоть как-то передвигаться, так и в программу добавляют код-костыль, чтобы хоть как-то выполнить задачу. Огромная разница заключается в том, что у человека нога рано или поздно заживет сама. А вот костыли, добавленные в код, сами никуда не денутся, и останутся в нем, формируя технический долг. Говоря иными словами, внося несовместимые с архитектурой изменения, разработчик «берет в долг» время разработки, обещая в будущем «сделать все как надо».
На практике это будущее никогда не наступает — у незнакомого с концепцией технического долга заказчика всегда есть срочная работа, которую надо делать вместо того, чтобы делать «непонятно что». Технический долг копится, парализуя архитектуру программы — ведь он добавляет гораздо больше сложностей, чем обычные изменения, так как костыли, добавленные в код, «по живому» модифицируют архитектуру непредусмотренным способом.
Пример из жизни, которым я часто иллюстрирую костыли и технический долг на тренингах и консультациях — это полки. Обычные полки, которые крепятся к несущей стене перфоратором, дюбелями и шурупами. Предположим, у нас уже висят две полки и нам нужно повесить между ними третью. И тут, беда-печалька, ломается перфоратор. С точки зрения архитектуры, правильным решением будет починить перфоратор и сделать, как полагается. Но если полки надо кровь из носу повесить до вечера, то делается костыль — третью полку гвоздями или шурупами прикручивают к уже висящим двум. Торжественно при этом обещая, когда починится перфоратор, все переделать. Данное решение, кроме очевидных минусов меньшего поддерживаемого веса, повышает сложность системы и затрудняет ее изменение. Через два года, когда про костыль все забудут, пришедшие монтировать шкаф для встроенного холодильника сборщики мебели решат снять крайнюю полку…
Ну вы догадываетесь, что будет. С техническим долгом все абсолютно то же самое — костыли копятся в коде, раскладывая по нему ловушки и мины, повышая сложность. Если не отдавать технический долг вовремя, то даже небольшая программа может в один далеко не прекрасный момент оказаться совершенно неподдерживаемой, потому что ее сложность за счет костылей уже давно вышла за пределы кошелька Миллера.