Интервью о техническом долге
Что такое технический долг? Можно ли понимать его, как плохое исполнение разработчиками своих обязанностей? Возможно ли избежать появления технического долга, и следует ли его избегать? Как связан технический долг с архитектурой приложения и с доверием между заказчиком и исполнителем? Какие стратегии применяются для контроля технического долга?
Предлагаю вашему вниманию перевод интервью, вышедшего в подкасте «Software Enginering Radio» в апреле 2015 года. Свен Йохан и Эберхард Вольф обсуждают внутреннее и внешнее качество ПО, вспоминают общепринятые модели качества и стратегии, направленные на поддержание внутреннего качества ПО. Технический долг, в основном, рассматривается в контексте управления программными проектами.
- Что такое технический долг
- Действительно ли технический долг – это плохо?
- Технический долг как осознанная стратегия
- Технический долг и архитектура
- Можно ли вообще избежать технического долга?
- Выявление технического долга
- Что можно предпринять?
- Технический долг и доверие между заказчиком и исполнителем
- Платить или не платить?
Вольф: Итак, очередной выпуск Software Engineering Radio. В этот раз, мы рассмотрим единственную тему в формате классического интервью. У меня в гостях Свен Йохан. Мы с ним соавторы статьи по теме технического долга, так что наши мысли, во многом, совпадают. Прежде чем мы начнём, Свен, расскажи о себе?
Йохан: Меня зовут Свен Йохан, я разработчик ПО в компании TRIFORK MCDM. Я также участвую в конференциях GOTO, и мне выпала честь проводить митап «Микросервисы».
Вольф: Звучит интересно. Что ж, меня зовут Эберхард Вольф, я консультант-фрилансер, глава консультативного комитета в Adesso AG, докладчик на немецкоязычных конференциях, на конференции GOTO и на нескольких других. Я также автор книги по непрерывному развертыванию ПО. Итак, перейдём к теме.
Что такое технический долг
Технический долг, без сомнения, связан с харатеристиками качества ПО. Поэтому стоит сначала кратко вспомнить вначале тему качества. Качество ПО бывает двух видов: внутреннее и внешнее. Внешнее качество ПО – это именно то, что ощущает пользователь или заказчик. Это может быть производительность, может быть другие качества вроде безопасности, устойчивой работы, масштабируемости и так далее. Внешнее качество ПО возможно оценить или измерить объективно. Оно – часть коммерческой ценности продукта, и оно должно быть предметом внимания продукта и нетехнического руководства.
Более сложная для понимания часть – это внутреннее качество. Внутреннее качество может быть оценено лишь разработчиками и техническими специалистами; сюда входит всё, что делает поддержку и развитие кода проще или сложнее. Протестирована та или иная функциональность, или недоработана? Обеспечивают ли тесты легкое внесение изменений в код? Получает ли проект выгоду от хорошей архитектуры, или испытывает архитектурные проблемы? Сюда же входит качество кода, которой может быть слишком сложным или слишком упрощённым. То, что эта часть не видна со стороны, усложняет ситуацию. Если вы не технический специалист, вам сложно оценить внутреннее качество ПО и понять, как оно влияет на процесс разработки.
Как вы понимаете «технический долг», Свен?
Йохан: В принципе, технический долг – это метафора, которая означает код с существенными недостатками. Мы сравниваем технический долг с финансовым долгом, чтобы разъяснить соображения внутреннего качества и технических рисков программного проекта людям, которые не являются техническим специалистами. Неспециалисты редко понимают разницу между плохим и хорошим кодом. Для них это выглядит как «Продукт работает, и замечательно! Зачем мне вкладываться в качество?»
Термин «Технический долг» позволяет нам пояснить, что, если мы хотим что-то построить на базе кода с существенными недостатками, это существенно удорожит развитие проекта в будущем, включая расширение функциональности. Кроме того, низкое внутреннее качество рано или поздно проявится внешне, и это надо понимать. Низкое качество кода не только замедляет добавление функциональности, но и может привести к проявлению большого количества багов. В итоге, это тормозит команду настолько, что внутренние проблемы однажды становится невозможно сдержать – и они становятся проблемами пользователей, заказчика, других заинтересованных сторон.
По сути, технический долг – это проблема масштаба компании, а не внутренний вопрос разработчиков. Известны случаи, когда из-за большого технического долга инженерное подразделение компании останавливалось целиком. Я полагаю, немало компаний имело опыт с 30-летними системами, в которых внесение даже незначительного изменения является практически невозможным.
Вольф: Да, можно утверждать, что технический долг это один из ключевых факторов, влияющих на коммерческий успех ПО. Сам термин «технический долг» предложил Вард Кёнингем в 1992 году. Вот цитата:
«Поставка сырого кода напоминает займ. Небольшие займы ускоряют развитие проекта до тех пор, пока их вовремя выплачивают, и платой является переписывание. Угроза возникает в тот момент, когда мы перестаём платить по долгам. Каждая минута, потраченная на код с существенными недостатками, является выплатой процентов по займу. Организация целиком может быть парализована под грузом долга, порождённого непродуманной реализацией – будь то объектно-ориентированная реализация или какая-то ещё».
Как видите, метафора напрямую упоминает финансовый долг. Здесь говорится об ускорении поставок путём заимствований; впоследствии, вы вынуждены либо вернуть долги, либо платить «проценты», которые проявляются в том, что ваша проактивность исчезает, а разработка существенно замедляется. Как сказал Свен, эта метафора хороша для разговора с руководством, поскольку они обычно мыслят в экономических терминах. Таково было изначальное определение. Но есть и альтернативное определение, не так ли, Свен?
Йохан: Разумеется. Научное сообщество скорее предпочитает определение Стива Макконнелла. Он формулирует так:
Технический долг – это подход к проектированию или конструированию на коротком отрезке времени, который за счёт создания технологического контекста приводит к тому, что отложенные изменения оказываются более дорогими, чем немедленные, в том числе за счёт создания накладных расходов в процессе разработки.
Я думаю, это определение шире распространено. Это то, что мы обычно подразумеваем, когда говорим о «техническом долге»: мы делаем что-то быстро и некрасиво, получая немедленную выгоду – однако, мы знаем, что в дальней перспективе нам это повредит.
Действительно ли технический долг – это плохо
Вольф: Итак, мы обсудили определение. Но я думаю, самое важное – это действия, которые вы можете предпринять в отношении технического долга, раз уж он является одним из ключевых факторов успешного бизнеса.
Первый вопрос, пожалуй, такой: действительно ли технический долг – это плохо? Если задуматься, привлечение заимствований далеко не такая плохая вещь. Если вы приобрели дом в кредит, вы можете больше не платить ренту; в конечном итоге вы останетесь с прибылью, так что подобная инвестиция может быть выгодной. По той же причине, промышленность привлекает займы для покупки более производительного оборудования, которое обеспечивает больший выпуск, и больший доход. Однако если вы тратите заёмные деньги на покупку предметов роскоши, или подарков к Новому году, это может быть плохой идеей. В этом случае, деньги не инвестированы, а потрачены без возможности их вернуть.
Опять же, метафора наводит на мысль, что выплата долгов не всегда имеет смысл. Почему так? Потому что, в отличие от денежного кредита, вы платите проценты только в том случае, если вы меняете код. Внутреннее качество кода сводится к возможностям его изменения. И если код не подлежит изменению, технический долг может вас не беспокоить. По сути, бессмысленно выплачивать «долги» по тем частям продукта, которые не изменяются.
Есть и другой повод забыть про технический долг, из-за которого разработка ПО иногда напоминает игру «Сапёр»: человек, которому предстоит выплачивать долги — это не обязательно тот же человек, которых их создаёт. Если, в вашем случае, созданием продукта занимается одна команда, а поддержку продукта будет выполнять другая, то первая команда свободна от «выплаты процентов». В этом случае, практические интересы первой команды вполне допускают создание огромного технического долга из рациональных соображений, поскольку это может сократить сроки поставки. Об этом явлении нужно помнить, когда мы говорим о проблеме технического долга. Если его игнорировать, это может вызвать недопонимание.
Технический долг как стратегия
Йохан: Да. В недавней дискуссии мы дошли до того, что технический долг, на самом деле, является стратегией. Почему стратегией? Потому что мы можем оперативно достичь бизнес-цели таким способом, понимая что, к примеру, намного более важно выйти на рынок в кратчайшие сроки, нежели, написать безупречный код и опоздать. Мы можем оказаться первыми среди конкурентов или вообще первыми в данной области.
Примечательно, что, к примеру, Эрик Риc приводил некоторые данные по этому поводу. В своей книге, он пишет:
Когда я работал в стартапах, я всегда испытывал радость от написания совершенного кода. Но в итоге, этот код оказывался невостребованным. Намного лучше оперативно создать нечто, что можно представить пользователю, чтобы понять – нужен ли наш продукт вообще кому-нибудь. И, если пользователь найден – отлично, тогда мы можем выплатить наш технический долг. Но если мы тратим силы на качественный код, не зная, будет ли он полезен, это в целом является бесполезной тратой времени.
Примерно год назад, Генрик Ниберг из Spotify написал пост на ту же тему, где он сказал: «В целом, мы рассматриваем совершенный код как растрату сил, если у нас нет оснований считать, что созданная им функциональность будет по-настоящему полезной». Они крайне быстро разрабатывают функциональность. Результат неидеален, но его показывают пользователю. И если выясняется, что пользователю это нравится, и если предполагается дальнейшее развитие этой части кода, они рефакторят код, приводя его в нормальное состояние.
Как мы видим, незамысловатые стратегии, применённые снова и снова, могут быть связаны с такими известными историями успеха, как Амазон и Твиттер. Насчёт Твиттера, складывается впечатление, что они непрерывно переписывают систему. В самом начале Твиттер был приложением Ruby on Rails, и теперь это мессенджер. Амазон также сильно отличается от того, каким он был в самом начале. Я думаю, это всё проявления стратегии.
Вольф: Верно. Если говорить про Амазон, одна из глав книги «The City of Amazon»(?) рассказывает, что в самом начале Амазон был огромным, монолитным приложением, которое было очень непросто поддерживать; и когда автор книги присоединился к компании, весь код был полностью переписан. Одним из результатов этой переработки стали красивые архитектурные решения, известные как Amazon Cloud. Здесь важно, что если бы Амазон был создан с мыслями о высоком качестве ПО и превосходной масштабируемости, он бы, скорее всего, не выжил, так как команда не смогла бы создавать функциональность с той скорость, которая требуется. Это отличный пример того, как программный продукт может быть полностью переписан из-за технического долга, но при этом оказаться невероятно успешным.
Йохан: Я думаю, с Твиттером всё было аналогично, поскольку изначально они не имели представления, на какое количество пользователей им следует рассчитывать. Есть существенная разница: ожидаете ли вы тысячу пользователей, или миллион, или сто миллионов; но вам всё равно надо с чего-то начинать.
Технический долг и архитектура
Вольф: Кстати, этот момент я бы обязательно упомянул в ситуации, когда мне пришлось бы говорить с архитекторами ПО. Я заметил, что они чересчур часто поднимают вопросы масштабирования. Похоже, что масштабируемость ПО – это их главный интерес, в то время как, вероятно, им было бы лучше сфокусироваться на time-to-market. В противном случае, у них есть все шансы не увидеть тот момент, когда масштабируемость понадобится, так как к тому времени компания может обанкротиться или предполагаемый источник прибыли пропадёт.
Как вы видите, плохая масштабируемость – это тоже не всегда плохо. Тем не менее, технический долг вам так или иначе нужно контролировать. Одна из лучших идей, которые я встречал, принадлежит Эрику Эвансу. Эванс известен как автор книги «Domain-Driven Design»; и в то время, как одна часть его подхода, касающаяся использования в команде единой терминологии, репозиториев и тому подобного, широко известна, есть и другая часть, с которой, похоже, мало кто знаком. Это часть, касающаяся cтратегического проектирования и проектирования на уровне крупномасштабных структур.
Суть его идеи в следующем: прежде всего, вы не можете иметь одинаковое качество кода во всех частях своей системы (вообще говоря, это довольно очевидный момент, хотя бы потому, что разные члены команды отличаются разным качеством кода; и даже самая лучшая команда не является однородной). Что же делать? Хотя вы могли бы просто оставить на волю случая, какие части вашей системы будут написаны хорошо, а какие – плохо, лучше принять сознательное решение. Один из способов справиться с техническим долгом – это задать себе вопрос «Какие части системы действительно важны, учитывая текущие и будущие изменения?» Ответ можно найти, изучив историю изменений или посмотрев со стороны предметной области: какие части системы дадут нам конкурентное преимущество, если мы будем способны их быстро дорабатывать? Если, к примеру, для вашего магазина очень важны способы доставки, разумно задаться целью, чтобы отвечающая за это функциональность часть кода имела высокое внутреннее качество. Эванс, в своей книге, рассмотрел довольно много шаблонов, относящихся к этому. Лучшая из его идей – это то, что вы можете иметь границы между контекстами, каждый из которых придаёт большую или меньшую важность определённому аспекту предметной области, и тогда между этими контекстами вы можете создать «защитный слой».
Применяя этот подход к проблеме внутреннего качества, вы могли бы создать часть системы – в нашем примере, отвечающую за доставку товара – с действительно качественной моделью предметной области, где находится качественный и сложный код, и вторую часть системы, например, отвечающую за взаимодействие с покупателем, в которой будут «временно» обитать части кода, отличающиеся низким качеством и посредственным моделированием. Чтобы убедиться, что плохие модели не повлияют на вашу бесценную систему доставки, вы создаёт защитный слой, разделяющий две части системы и транслирующий вызовы между ними. Используя этот подход – я применяю для него метафору «клеток», аналогично клеткам живого организма – вы сохраняете каждую из клеток от проникновения внешних проблем. Это довольно неплохой способ стратегически управлять качеством и техническим долгом. Одни части системы вы поддерживаете на наивысшем уровне, постоянно отслеживая качество, в то время как для других вы используете стандартные, покупные или устаревшие компоненты. Мне кажется, что при разработке достаточно сложных систем эта стратегия заслуживает внимания.
Можно ли вообще избежать технического долга?
Йохан: Один из известных вопросов, конечно – почему вообще мы создаём технический долг? Не можем ли мы изготавливать качественное ПО с самого начала?
С точки зрения разработчика… почти каждый разработчик желает создавать отличный продукт, и едва ли кто-то хочет быть автором второсортного кода. Так как же получается, что мы выдаём низкокачественный код, не имея такого намерения? Тому есть несколько причин.
- Самая очевидная причина, это, конечно, давление сроков: мы хотим сделать что-то хорошо, но времени нет. Мы должны делать выпуск, у нас дидлайн. Поэтому, чтобы работать быстро, нам приходится идти на компромиссы в области качества. Мы тестируем поверхностно, мы не пишем автоматические тесты, мы не продумываем глубоко наши технические решения, и в результате мы получаем посредственный результат большую часть времени.
- Второй причиной является незнание деталей технологии. Если мы используем что-то впервые, обладая лишь базовым пониманием, мы неизбежно используем это неправильно, хоть и с самыми лучшими намерениями.
- Третьей причиной является то, что несовершенное знание предметной области порождает странную архитектуру и модели данных.
- И, наконец, существует явление «деградации ПО» со временем. Система, которая могла считаться совершенной 15 лет назад, вроде EGB2.0, будет выглядеть устаревшей сегодня.
Я припоминаю, что Cуррей из Университета Токио(?) провел крайне интересное исследование в Финляндии. Среди финских разработчиков провели опрос: откуда, по их мнению, появляется технический долг. Неожиданно, но никто не назвал «давление сроков» в качестве причины! Также никто не жаловался на незнание технологии. Респонденты отвечали либо «Мы не до конца понимали требования, в общем-то, не понимали предметную область, так что технический долг происходит из плохого понимания требований», либо утверждали, что архитектура была плохой, или архитектурные идеи были плохо донесены до разработчиков, и это стало основной причиной технического долга.
Вольф: Это довольно интересно, поскольку когда-то я тоже думал, что технического долга следует избегать, но архитектура, прежде всего, приводит к возникновению технического долга. Потом я спросил себя: что, на практике, определяет трудность изменения ПО? И мой ответ был «тесты». Если представить, что мне надо выбрать между системой с плохой архитектурой, но множеством тестов и системой с хорошей архитектурой, но без тестов, я бы выбрал первый вариант.
Опять же, это один из тех вопросов, которые заставляют меня сомневаться в определении технологического долга. Я просто не знаю точного ответа. В принципе, можно было бы рассматривать архитектуру как его часть.
Йохан. Да, сложно сказать. Я недавно слышал, что Филипп Крачтен, изобретатель методологии RUP, известный множеством публикаций по архитектуре, утверждает: даже если у вас есть множество тестов, но посредственная архитектура, вы не можете надеяться, что рефакторинг повысит качество вашей системы. Поскольку, если архитектура ошибочна, рефакторинг вам не поможет. Вам требуется строить систему заново
Вольф. Этот вопрос может быть предметом долгой дискуссии.
(…)
Вольф: И следующий вопрос, конечно: реально ли создать систему, свободную от технического долга? Вы хотели рассказать об этом, верно, Свен?
Йохан: Возможно ли получить систему, свободную от технического долга? Я нередко вижу заголовки статей вроде «Покончим с техническим долгом!» и «Как стать свободным от технического долга за 10 шагов» (или сделав что-то ещё). Я думаю, что это просто невозможно – получить систему, лишённую технического долга. Мы должны смириться с его существованием, что технический долг будет всегда. Даже если предположить, что вы достигли этой цели и устранили весь технический долг – это будет означать, что вам пришлось инвестировать большой объём денег и времени в задачи, не связанные с успехом проекта.
Вольф: Главное, что мы можем вынести из этой ситуации – это то, что оригинальная реализация Твиттера и других продуктов, достигших выдающегося успеха, имела большой объём технического долга. Технический долг не имеет прямой связи с коммерческим успехом. (…) Быть может, технический долг – это не лучшая метафора именно потому, что выплатить его целиком невозможно. Также, в ряде случаев технический долг не является следствием сознательного компромисса, и в некоторых случаях он возникает из-за появления новых технологий. Felix Müller, в своей диссертации, пытался выработать замену этой концепции. Он предлагал использовать термин «Повышение качества».
Йохан: «Повышение качества» или «Инвестиции в качество»?
Вольф: Повышение. Хотя мы также можем говорить об инвестициях. Идея в том, что, раз уж технический долг присутствует всегда, и всегда есть что-то, что может быть улучшено с точки зрения внутреннего качества – почему бы не говорить об инвестициях в качество? Допустим, мы потратили 5 дней на переработку системы тестирования, — это инвестиция. Если нам это нам сэкономит день или два на каждый следующий спринт – это доход. Доход исчисляется, попросту говоря, как повышенная продуктивность минус затраты на повышение качества. Последнее, что я хочу отметить – это то, что известная модель качества SQALE построена вокруг примерно этих же идей. (…)
Основной аргумент критики, адресованной этому подходу, да и не только, заключается в том, что «Разработчики обязаны поддерживать высокое качество во всех случаях!». Я уверен, что усилиями одних только разработчиков качество поддерживать нельзя. Инвестиции в качество должны быть согласованы с управлением продуктом и многими другими процессами. К примеру, организация непрерывного развертывания – это большой объём работ, которые разработчик не может просто выполнить по своему желанию; он должен убедить руководство сделать это, и здесь метафора «Инвестиций в качество» выглядит вполне уместной: вместе с процессом непрерывного развертывания, мы будем иметь лучшее качество, меньше дефектов, лучшую проактивность и так далее. Уверен, что вы, как разработчик, вполне вправе обсуждать эти вопросы с менеджментом, и что это способно продвинуть вас в сторону решения.
(…)
Выявление технического долга
Вольф: Отлично. Мы не рассмотрели вопрос, каким образом возможно выявить технический долг. У вас, вроде бы, были идеи на эти темы?
Йохан:
- Технический долг может быть явно обозначенным, как, например, код, полный пометок TODO и FIXME. Такой код означает, что разработчики торопились поставить, к примеру, функциональность, и некий TODO мог означать: «Эй, нам следует вынести конфигурацию из кода!», или FIXME со смыслом «Это работает только в 95% случаев; если эта функциональность нам действительно нужна, в этом месте требуется доработка». Такие случаи, на мой взгляд – самые простые.
- Бывают более серьёзные ситуации. Например, вы хотите внести изменение в код, и один за разработчиков говорит: «О! Я не могу изменить этот код, так его написала Кэт!». Это означает, что у вас серьёзные неприятность, поскольку из-за вашего желания ускорить разработку оказалось, что только один разработчик имеет знания, необходимые для выполнения задачи. Они не были переданы команде; это остров в море; и если этот разработчик попадёт под автобус, никто не сможет продолжить развитие этого кода. Вообще, если кто-то говорит «Этот код может быть изменён только вот тем человеком», это ясный признак большого технического долга.
- Также, плохо, если вам случается слышать «О, у нас уже есть похожая функциональность в другом месте, давайте её скопипастим с небольшими изменениями» — вы, конечно, можете так делать, но если вы этим злоупотребляете, ваша кодовая база становится абсолютно непригодной для поддержки.
- Схожая ситуация – когда разработчик говорит «Ну, я совсем не хочу менять это место, поскольку у меня нет полной уверенности. Если я изменю код здесь, скорее всего, много чего сломается». Такая ситуация означает, что приложение спроектировано реально плохо, настолько, что вы не можете вносить локальные изменения, т.к. всё связано со всем и похоже на тарелку спагетти; и вы рискуете полностью потерять темп разработки, так как любое новое требование, по сути, будет вызывать появление новых дефектов ПО, которые можно побороть лишь интенсивным тестированием.
- У вас также могут быть количественные индикаторы, такие как Velocity в команде Scrum. Если индикатор скорости разработки безнадежно падает, при том что команда вполне стабильна, вам следует заняться анализом причин этого. Наиболее вероятной причиной падения также является технический долг.
- Cледует помнить о старении ПО. Старые библиотеки, старые технологии, что угодно старое – даже если вы построили совершенную систему, через 10 лет она будет устаревшей и от вас потребуются дополнительные усилия. Вы будете обновлять библиотеки, или даже заменять их другими, чтобы уметь делать то, что необходимо уметь в 2015, скажем, году.
- Также плохо, если вам случается слышать что-то вроде «Ой, мы не можем исправить этот баг немедленно. Да, это всего одна строчка, но передача системы в продакшн потребует неделю или две». Вам нужно стремиться к тому, чтобы иметь возможность развернуть исправление за десять минут, или может быть, за час. Двух-трёх недельные циклы развертывания — это проблема. И ещё (хоть это и менее важно): если ваши тесты выполняются реально долго, то это приводит к серьёзным временным затратам. И если ваши правила требуют фиксировать только код, прошедший все тесты (я уверен, что должно быть именно так), то это очень существенно: выполняются ли тесты за минуту, или вам нужно ждать десять минут, или двадцать.
Вольф: Если вы отслеживаете (или хотите отслеживать) качество вашего кода, вам стоит обзавестись утилитой, умеющей делать множество вещей: выполнять анализ кода, анализ покрытия и многое другое. Результаты такого анализа дают вам очень хорошее представление о качестве, а также создаёт массив исторических данных, так что вы можете понять, улучшается или ухудшается качество кода со временем. (…)
Что можно предпринять?
Вольф: Какие мероприятия в отношении технического долга вообще возможны?
- Один из способов, которым вы можете воспользоваться – это буферные задачи и пре-релизы. Вы говорите: «Давайте выделим время команды на работу над техническими вопросами, чтобы повысить качество». Это могут быть технические релизы, которые преследуют единственную цель – улучшить кодовую базу. Такой подход означает, что усилия, связанные с техническим долгом, не распределяются во времени равномерно, как «фоновая задача», длящаяся всю итерацию; напротив, эти усилия объединяются в отдельную итерацию, которая проводится, не знаю, раз в три или четыре раза.
- Другой способ. Вы можете вести «технический бэклог», в который заносить части проекта, нуждающиеся в технической доработке; либо, как альтернатива, вы можете сказать: «Отлично, у нас есть задача для добавления функциональности, и в её рамках мы инвестируем часть усилий в технический долг». Это выглядит так: к примеру, у вас есть задача «Мы хотим переработать процесс регистрации». Что мы делаем? Мы перерабатываем процесс регистрации, и попутно прилагаем усилия к повышению качества ПО таким образом, чтобы нам было проще дорабатывать функциональность. Таким образом, наши инвестиции в качество происходят в тех частях кода, которые мы должны были изменить в рамках задачи. И эти затраты оказываются связанными с прикладной задачей, что позволяет их представить руководству и позволить им принимать решение. Руководство имеет возможность отказаться: «Отлично, давайте не будем добавлять функциональность, так как это выглядит чересчур затруднительным из-за низкого внутреннего качества ПО».
Какой бы вариант вы не выбрали, в конечном счёте уровень качества и управление качеством должно быть решением, принятым на уровне бизнеса, поскольку это решение сводится к выбору между лучшим качеством и лучшей функциональностью. И это, как мы уже говорили, весьма важная дилемма. Вложение в качество приносят приносят прибыль в долгосрочной перспективе. Однако, если вам действительно нужно добавить функциональность – под угрозой серьёзных негативных последствий в области бизнеса – в этом случае качество кода, на самом деле, не имеет значения. Решение, инвестировать или нет в качество, на самом деле, это не техническое решение.
Технический долг и доверие
Вольф: И с этим всем связана ещё одна проблема – если вы предусматриваете выделенное время для повышения качества кода (или планируете для той же цели технические релизы), вы лишаете нетехническое руководство проекта возможности принимать решения в отношении качества. Вы делаете это чисто техническим вопросом, которым, на самом деле, это не должно быть.
Я думаю, что одна из сложностей в отношении технического долга заключается в вовлечении бизнеса в принятие решений, какие части системы должны иметь лучшее качество и во что следует производить инвестиции. Если вы практикуете подход «Команда понимает, как лучше всего повысить качество кода и как лучше всего инвестировать усилия», это означает, что решение принимает команда. И бывает так, что члены команды не могут принять этого решения, или же наилучшее решение им недоступно из-за того, что они не видят всей картины. Вовлечь в принятие этого решения представителей бизнеса – одна из сложнейших задач. Взаимопонимание с менеджментом также является ключевым фактором. Собственно, это и есть первая причина, по которой нам потребовалась метафора «технического долга». И в какой-то мере здесь возникает вопрос доверия. Если разработчики умеют отслеживать и поддерживать качество, им может быть предложено самостоятельно принять решение, как распределить усилия по повышению качества. В противном случае, вам требуется некий способ принятия решения, на что тратить эти усилия, и это решение может быть крайне трудным и трудозатратным.
Йохан: Да, доверие – это очень важный момент. Нередко можно видеть разработчиков, много жалующихся на плохое качество кода и используемого инструментария. Они говорят: «Нам следует улучшить то это, и нам надо доработать фреймворк, и сделать ещё множество вещей» — но руководство их не слышит. Руководство говорит: «Я знаю об этом, но это просто не так важно, чтобы этим заниматься». Но если, к примеру, в вашей команде есть очень хороший разработчик, понимающий предметную область, и нетехническое руководство доверяет этому человеку, или этим людям, тогда этот разработчик может сказать «Я думаю, нам действительно нужно решить такую-то проблему, иначе мы движемся в никуда; мы должны это устранить, и только тогда сможем делаться дальше» — тогда руководство, проявляя доверие, говорит: «Да! Если Фред, и Майк, убеждены что это действительно важно, и этого нельзя избежать – и они понимают суть бизнеса – возможно, нам стоит прислушаться к ним и позволить им принять решение».
Вольф: Да, вы отчасти правы. Но с другой стороны, только те, кто принимают бизнес-решения, могут действительно решить, есть ли смысл в настоящий момент инвестировать в качество. Поскольку, во многих случаях, требуется просто поставить определённую функциональность. К тому же, как мы уже говорили, технической долг зависит от изменяемости частей системы – и этот фактор может быть известен разработчикам лишь отчасти. Разработчики знают, каково будет развитие проекта на протяжении, быть может, нескольких релизов, но стратегическое видение доступно лишь тем, кто владеет бизнесом. Поэтому и ответственность за качество не может быть возложена целиком на разработчиков. Решение, как и в каких аспектах инвестировать в качество, требует совместных усилий людей, владеющих разными частями картинки.
Йохан: Я имел в виду, что существуют разработчики, являющиеся экспертами в предметной области, которые вполне понимают стратегию и направления развития проекта. И если они пользуются доверием руководства, и настаивают на необходимости инвестиций в качество – в большинстве случаев, они будут услышаны. Однако для тех, кто не понимает бизнеса, добиться такого уровня доверия практически невозможно.
Вольф: Ну, это огромное везение – иметь таких разработчиков и такую команду. Однако, это поднимает порог вхождения до уровня, когда едва ли вы будете иметь большое количество кандидатов, которых вы сможете взять на работу. Поскольку в этом случае вы ищите не просто превосходных технических специалистов, но также ожидаете от них обширных познаний в вашей предметной области. Стать хорошим специалистом и без того тяжело – это требует навыков и в области разработки, и в области развития проекта, и в области проектирования – и если вдобавок к этому требуется в совершенстве знать какую-то отрасль бизнеса, это становится на редкость высоким уровнем требований. Поэтому я думаю, что совместная работа технических специалистов и представителей бизнеса, как часто бывает, абсолютно необходима.
Платить или не платить?
Йохан: Хотелось бы упомянуть ещё один момент. Френк Бучман, автор статьи «Pattern-oriented software architecture» не так давно поставил вопрос так: «Технический долг: платить или не платить?». К слову, его работа мне показалась крайне интересной; к сожалению, её нет в свободном доступе. Вопрос ставится так: «Отлично. Пусть технический долг неизбежен. Какое решение мы можем принять в плане того, хотим ли мы его выплачивать?» Он назвал три возможных ответа.
- Вариант первый: «выплата» долга. Имея действительно проблемный модуль нашей системы, мы принимаем решение выполнить масштабный рефакторинг, либо, даже, выбросить старый код и написать с нуля компонент, фреймворк, платформу – то, что вызывает проблемы, и начать жизненный цикл этого кода заново. Или, может быть, мы предполагаем, что после доработок код будет хорошо устроен, но мало подвержен изменениям. Этот вариант следует выбирать только в том случае, если код действительно проблемный и вам неоднократно придётся строить новую функциональность на его основе.
- Второй вариант – это «реструктуризация» долга. Предположим, у вас есть компонент или программный модуль с очень большим техническим долгом, но полная его замена – за пределами ваших возможностей. Представим, что вашему приложению 30 лет. Вы не можете просто выбросить его, так как это связано с неприемлемыми рисками и неприемлемыми затратами. Зато, то что вы можете сделать – это начать реструктуризацию. Вы пытаетесь преобразовать систему к хорошему, пусть и не идеальному, состоянию. И это новое состояние отличается тем, что «процентная ставка» – затраты, связанные с низким внутренним качеством кода – существенно снижается.
- И, наконец, третий вариант – в моем представлении, довольно популярный – это решение смириться с наличием технического долга, в определённой степени. Мы просто миримся с накладными расходами, зная, что код не особо хорош – но с ним можно жить. Он имеет проблемы, но зато мы не тратим большое количество времени и денег на рефакторинг старой кодовой базы – поскольку такая операция оказалась бы намного дороже, чем фактический ущерб от низкого качества кода. Вообще говоря, мы всегда должны задаваться вопросом: должны ли мы доводить то, что мы делаем, до совершенства, или нам разумнее остановится на том, что мы уже сделали?
Я думаю, что эти размышления, которые представил Бучман, являются вполне достойным вкладом в эту тематику.
Вольф: Отлично. Я так думаю, на этом можно закончить?
Йохан: Конечно. Спасибо за то, что пригласили меня на передачу и за интересную дискуссию о техническом долге. Надеюсь, всем нашим слушателям она также понравилось. Если у вас есть вопросы, мы с удовольствием ответим на комментарии, которые вы можете оставлять на нашей странице. Благодарим за прослушивание!
Материалы
- Выпуск #224 Software Engineering Radio
- Использованный для перевода текст передачи
- Cтатья авторов программы «Managing Technical Dept»
Автор: Rumega