Технологический долг что такое
Технический долг
Будь вы простым программистом, матерым лидом, архитектором или даже ПМ-ом, вы наверняка в своей нелегкой работе сталкивались с проблемой выбора при добавлении в систему новой возможности. Одно решение гораздо проще реализовать в сжатые сроки и успеть к очередному очень важному релизу, однако оно будет более затратное в сопровождении, менее расширяемое или менее надежное. Другое решение может не обладать всеми этими недостатками, однако обладать другим, в некоторых случаях более важным недостатком – на его реализацию потребуется значительно больше времени.
При этом самым сложным при выборе того или иного решения является «коммуникация» своего выбора непосредственному руководителю, чтобы он смог принять взвешенное решение. А поскольку с точки зрения большинства руководителей «взвешивание» заканчивается сразу же после того, как он услышит сроки реализации, то «коммуникация» заканчиваются примерно через 37 секунд после ее начала (обычно именно столько времени нужно руководителю, чтобы узнать ответ на очень простой вопрос, выражаемый одним словом: «Когда?»)
Не удивительно, что многие простые программисты, матерые лиды и архитекторы, а иногда даже ПМ-ы, которые понимают, что им самим придется расхлебывать проблемы «близоруких» решений, с таким подходом не согласны. И совершенно не удивительно, что с подобной проблемой сталкивались и другие известные и не очень люди, которые придумали типовые «паттерны», описывающие подобную ситуацию. Одним из таких паттернов, является метафора технического долга, впервые описанная Вардом Каннингемом (Ward Cunningham) (*) без малого двадцать лет назад.
Технический долг в классическом понимании
В классическом понимании, т.е. в том виде, в котором эта метафора была описана Вардом Каннингемом, под техническим долгом понимается осознанное компромиссное решение, когда заказчик и ключевые разработчики четко понимают все преимущества от быстрого, пусть и не идеального технического решения, за которое придется расплатиться позднее. И хотя с точки зрения многих разработчиков ситуация, когда плохое решение может быть хорошим, может показаться безумной, на самом деле, это вполне возможно: если краткосрочное решение позволит компании получить видимые преимущества, выпустить продукт раньше конкурентов, удовлетворить ключевого заказчика или каким-то другим образом получить преимущества перед конкурентами, тогда такое решение совершенно оправданно. Иногда это может быть единственным способом, чтобы долгосрочная перспектива вообще существовала.
Можно провести параллель между техническим долгом и долгом финансовым. Финансовый долг означает, что вы получаете дополнительные средства сейчас, однако каждый месяц (или каждые пол года) вам придется выплачивать фиксированную процентную ставку, а в конце срока вернуть весь долг кредитору. Аналогичная ситуация происходит и в случае принятия неоптимального технического решения: вы получили готовую систему или новую возможность уже сегодня, однако при добавлении новой возможности вам придется платить «проценты», либо погасить ваш долг путем рефакторинга системы или части системы.
Именно такой подход к построению приложений является наиболее оптимальным с архитектурной точки зрения. Если принимая архитектурное решение вы не чувствуете компромисса между краткосрочными и долгосрочными выгодами, то в любом случае не стоит вырубать его в камне. Вполне возможно, что вы приняли неправильное решение неосознанно, а из-за своего непонимания предметной области, или из-за будущего изменения требований заказчиком. Значительно проще снизить стоимость будущих изменений путем инкапусуляции важных решений в наименьшее число модулей, нежели стараться продумать архитектуру до мельчайших подробностей, в надежде учесть все возможные и невозможные сценарии. Для определенного круга задач идеальная продуманная архитектура возможна, а иногда просто необходима, но в большинстве случаев – это не так; рано или поздно придет момент, когда ваше видение системы или видинение системы заказчиком изменится, что потребует внесения в нее существенных изменений.
Однако даже при разумном накоплении технического долга существует большая вероятность, что команда (или заказчики) пойдут по старому принципу – работает – не трогай, и никогда не вернутся к этому решению снова, чтобы расплатиться за свой технический долг. Кроме того, существует множество случаев, когда технический долг накапливается постепенно и неосознанно, и если разработчики не будут об этом задумываться, то придут к старой как мир ситуации, когда стоимость добавления новой возможности становится невероятно дорогой, все работают, устают, злятся друг на друга, не получив при этом никаких преимуществ перед конкурентами. Это приводит нас ко второму источнику технического долга – грязному коду (***)
Грязный код, как источник технического долга
Технический долг в классическом понимании является преднамеренным и в основном касается стратегических решений, поэтому и ответственность за него лежит на заказчиках матерых лидах, архитекторах и даже ПМ-ах, но вот все, что связано с грязным кодом касается по большей части простых разработчиков. На самом деле, разница между грязным кодом и неоптимальным стратегическим решением, по сути, не такая уж и большая: при добавлении новой возможности в систему вам приходится расплачиваться за недальновидность в прошлом.
Во время кодирования, как и во время принятия любых других решений, разработчик должен рассматривать краткосрочные и долгосрочные выгоды. Давайте рассмотрим юнит-тесты. Если спросить адепта TDD о необходимости юнит-тестов, то он скажет: «г@#но-вопрос, юнит-тесты должны быть для каждого класса, модуля или функции, и, конечно же, они должны писаться до написания кода». Однако если послушать Кента Бека (****), автора TDD, то его отношение к юнит-тестам более прагматичное. Принимая решение об использовании TDD или серьезном покрытии кода юнит-тестами точно так же нужно принимать во внимание краткосрочные и долгосрочные выгоды. Безусловно, юнит-тесты очень полезны, но они полезны, прежде всего, в долгосрочной перспективе, а что если вы осознаете, что существует высокая вероятность того, что этих долгосрочных перспектив не будет вовсе? Вы можете разрабатывать прототип или что-то типа proof of concepts, и пытаетесь выяснить, будет ли вообще это решение работать или нет. С аналогичной ситуацией неэкономичности юнит тестов можно столкнуться во многих реальных приложениях, когда при добавлении новой возможности стоимость написания юнит-теста может в несколько раз превышать стоимость самой реализации.
Однако это скорее исключение из правил, нежели типовая ситуация. Обычно в процессе развития приложения накапливается как груз крупных стратегических ошибок или непониманий требований, так и масса мелких тактических ошибок, типа длинных функций с неочевидными обязанностями и сложными побочными эффектами; расплывчатых классов, с нечеткими границами и обязанностями; отсутствие идиом именования и документации и т.п… Все это приводит к классическому синдрому разбитых окон, когда ни у кого не возникает идеи поступать по другому, а у кого и возникает, то она быстро пропадает из-за того, что плыть против подобного течения очень и очень сложно.
И если команда не отдает свои долги путем переосмысливания существующих решений и их последующего рефакторинга, если она не старается держать качество кода на высоком уровне, то рано или поздно это повысит стоимость развития и сопровождения кода настолько, что все существующие средства будут уходить на оплату процентов по техническому долгу. Что в свою очередь приведет к низкой продуктивности разработчиков (еще бы, ведь они только и делают, что борются с ветряными мельницами), и взаимной неудовлетворенности команды разработчиков и заказчика.
Выводы
Измерение продуктивности программиста или команды программистов дело сложное, и именно из-за этого возникают многие сложности при выборе того или иного технического решения: руководители или заказчики просто не понимают, какие последствия ждут их при выборе одного и отказе от другого решения. Использование метафоры технического долга не является панацеей и вряд ли обеспечит решающий перевес при выборе того или иного подхода, однако, как минимум, позволит понять ключевым заинтересованным людям проблему в терминах, доступных простому смертному, и покажет проблему пусть и в абстрактных, но все же в финансовых единицах.
Кроме того, даже если вам приходится идти на компромисс и влезать в долговую яму осознанно или не осознанно, старайтесь проектировать ваши системы так, чтобы влияние неоднозначных решений было минимальным, а качество кода реализации – на высоком уровне.
(*) Вард Каннингем – это известный дядька, оказавший невероятный вклад в развитие компьютерного сообщества; он «папа» wiki, а также один из авторов «паттернов» и «экстремального программирования». Информацию по поводу первого вклада можно найти в Википедии, а по поводу второго – в статье «Шаблоны проектирования. История успеха».
(**) Конечно же, речь идет только о тех случаях, когда каждое из приведенных решений кажется более оптимальным, но стоимость его применения именно сейчас кажется неоправданно высокой.
(***) Некоторые авторы, включая Боба Мартина не считают, грязный код (messy code) техническим долгом, однако подобный код увеличивает стоимость добавления новой возможности, так что мне кажется, что его тоже можно рассматривать, как один из видов технического долга.
(****) Здесь речь идет о подкасте Software Engineering Radio Episode 167: The History of JUnit and the Future of Testing with Kent Beck, в котором Кент Бек как раз и высказал эту заветную мысль.
Технический долг: что это такое и как с ним жить
Быть или не быть регулярному рефакторингу? Мы попытались разобраться с этой холиварной темой — не без помощи людей, которые знают врага в лицо.
Технический долг — это модули, написанные на старых фреймворках, «костыли», мелкие недоработки, нарушенные стандарты и прочий мусор в коде, который в будущем усложняет жизнь. То самое чувство, когда читаешь код и думаешь: «Ну что за нехороший человек это всё писал». А потом оказывается, что этот «редиска» — ты сам из прошлого. Сам термин — метафора пионера паттернов и изобретателя технологии Wiki Уорда Каннингема.
Недоработки постоянно накапливаются. Чем их больше, тем сложнее добавить в код новую классную функцию. Необходимые усилия, которые придётся приложить в будущем, — как проценты по кредиту. Расплаты всё равно не избежать, а долг со временем всё растёт и растёт.
Согласно исследованию Stripe, разработчики тратят на технический долг треть своего времени, а компании «сливают» на это примерно 85 млрд долларов ежегодно. Быстро вывести на рынок жизнеспособный продукт, приносящий пользу бизнесу, — неплохое решение. Но надо помнить, что технический долг рано или поздно начнёт вредить проекту.
«Нельзя прийти и создать сразу идеальный проект. Каждый день мы будем что-то узнавать о предметной области, и эти новые знания нужно сразу внедрять. Вначале это будут костыли, из которых копится технический долг, — и это нормально. Ведь мы не можем, получая новую информацию, каждый раз переписывать продукт заново. Бизнес нас не поймёт».
Алексей Некрасов,
лидер направления Python в МТС, программный директор направления Python в Skillbox
Пишет про технологии и бизнес.
Технический долг в жизни: два примера
Если вовремя не подумать о техническом долге, приложение может подхватить хроническую болезнь: многочисленные уступки «надо прямо сейчас» так въедаются в код, что рефакторинг провести просто невозможно. Вот две истории — одна об успешной оплате долга, вторая — о запущенной «болезни», справиться с которой так и не получилось.
Локализация приложения
Канадская компания разработала хороший продукт для местных клиентов и решила повторить успех, расширив рынок сбыта на ту часть страны, где говорят в основном по-французски. Разработчики управились за неделю, добавив кучу if-then-else. Решение с оператором условий было быстрым и грязным, но на тот момент — оправданным. Продукт смог заработать ещё денег.
Месяц спустя в Японии фаундер похвастался, что поддержку японского они могут добавить за неделю. Но одно дело — по-быстрому накодить один дополнительный язык, и совсем другое — добавлять так же криво все последующие. Тем более что для японского решение с новым слоем if-then-else вообще не подходило — мешали иероглифы, да и текст японцы пишут вертикально. В итоге разработчикам пришлось писать нормальную систему локализации.
Бесконечные «если» и неудавшийся рефакторинг
Разработчики написали приложение на устаревших версиях Python, PHP и Java с жёсткой структурой из бесконечных операторов if. В какой-то момент они решили полностью переписать ядро на свежих версиях языков, но на каждом шагу объёмы работы возрастали — постоянно обнаруживались какие-то новые зависимости. Да и бизнес не хотел ждать — требовал новые функции, чтобы оставаться конкурентоспособным. В итоге за год рефакторинга команда практически не продвинулась вперёд.
Как оценить технический долг
Американский программист, автор книг и статей по архитектуре ПО Мартин Фаулер определял размер техдолга простой формулой: чем больше усилий программистов тратится на какой-то недоработанный в прошлом фрагмент кода, тем больше наш технический долг. При этом консультант по разработке ПО Роберт Мартин считает, что технический долг в прототипах и краткосрочных проектах можно и нужно игнорировать.
Есть разные классификации технического долга.
Например, CTO производителя весов для угарного газа Tapad Даг Лиодден выделяет три его типа:
Как правило, самый неприятный техдолг связан с архитектурными проблемами: отсутствием инкапсуляции и модульности, плохим применением шаблонов, несоответствием типов данных модели данных. Из-за этого тормозится разработка, трудно вносить изменения в код, исправлять ошибки. Такой долг трудно или вообще невозможно обнаружить инструментами вроде IDE, PMD или Checkstyle.
Чтобы понять, как победить техдолг, нужно тщательно его проанализировать.
Как объяснить бизнесу, что рефакторинг необходим
Владельцам софта нужна прибыль, поэтому они не хотят затягивать процесс разработки и бороться с техдолгом — особенно если близок старт продаж. Однако долг всегда приходится возвращать — иначе он создаёт проблемы в будущем продукте.
Конфликт разработчиков и бизнеса из-за рефакторинга — один из самых запутанных и сложных. Если игнорировать и копить техдолг, то разработчики потеряют мотивацию, а компания станет «техническим банкротом». Если же включить режим перфекциониста и слишком сильно фокусироваться на долге, конкуренты получат преимущество в скорости, быстрее выпустят новые фичи и захватят рынок. А полученную в ходе экспансии прибыль они вложат в погашение критичного долга — и останутся в выигрыше.
Вообще, Уорд Каннингем придумал концепцию техдолга именно для того, чтобы в понятных для бизнеса терминах аргументировать необходимость рефакторинга. Метафора простая: первая версия программы — как заём в банке. А каждая минута, которая тратится на исправление «костылей» в коде, — как проценты по кредиту. Если проценты долго не гасить, банк истребует весь долг и компания может закрыться. Однако небольшой долг, как и разумно взятый кредит, ускоряет разработку и помогает расти, главное — выплачивать его вовремя.
«Представьте платформу для нескольких независимых друг от друга клиентов ( из терминологии «клиент — сервер». — Прим. ред.). У каждого есть собственный сервис, весьма требовательный к аппаратным ресурсам. Пока клиентов мало, эта схема работает. Когда же количество клиентов резко увеличивается, возникает необходимость менять архитектуру и запускать один сервис, который будет обслуживать всех, вместо нескольких копий, работающих параллельно. А это уже экономия в чистом виде и вполне убедительный аргумент для бизнеса.
Пока критической ситуации не возникло, многие воспринимают технический долг как нечто абстрактное. К сожалению, часто осознание приходит, только когда бизнес теряет деньги или несёт репутационные потери. Но после этого он сразу понимает важность рефакторинга».
Николай Мельников,
руководитель компании Sebbia
Важный момент: договариваться о ресурсах и времени команды, которые будут тратиться на рефакторинг, лучше до начала работ. Потому что вовремя гасить технический долг — критично для любого программного продукта. С заказчиком необходимо говорить на его языке: объяснять финансовые риски и приводить примеры из жизни.
«У нас в BestDoctor есть договорённость, что один день в неделю каждый программист выделяет на работу с техническим долгом и автоматизацию, которая улучшает жизнь всей команде разработки. Этот день полностью посвящён не продуктовым, а инженерным задачам. Я рекомендую ввести обязательный процесс отдачи технического долга раз в неделю или раз в две недели. Это позволит не запускать его».
Михаил Корнеев,
тимлид в BestDoctor, автор YouTube-канала «Хитрый питон»
Качественный рефакторинг возможен, только если вы «брали» техдолг осознанно, понимали, что перфекционизм в этот момент навредил бы бизнесу, и фиксировали момент создания долга. Поэтому небрежно писать код и думать, что исправишь всё когда-нибудь потом, — плохая идея.
«Если уже сложилась ситуация, когда надо немедленно реагировать и что-то делать с техдолгом, значит, что-то не так с процессами. Нужно сразу планировать работу так, чтобы оставалось время на рефакторинг — от 5% до 33% рабочей недели. Команда должна знать, что у неё есть выделенное время для таких задач».
Николай Мельников,
руководитель компании Sebbia
Чек-лист: как не накапливать технический долг
Хотите изучить новый язык программирования или неизвестный фреймворк? Выбирайте подходящий среди курсов Skillbox.
Технический долг и места его обитания
Эта статья — вольный пересказ доклада, который я посетил на конференции GOTO Berlin 2017: A Crystal Ball to Prioritize Technical Debt.
Изображения из доклада и права на них принадлежат автору @AdamTornhill.
Каждый разработчик в принципе понимает, что такое технический долг. Что в его проекте этот долг наверняка присутствует. Если повезет, он вспомнит несколько кусков кода, которые давно просятся быть переписанными.
Но как формализовать понятие технического долга, чтобы объяснить его другим? И, тем более, объяснить это менеджеру так, чтобы получить одобрение на рефакторинг? Как найти все места в проекте, которые нужно по-хорошему переписать, и как определить, какие из них должны быть переписаны в первую очередь?
Если эти вопросы неоднократно у вас возникали, прошу под кат.
Не весь коряво написанный код по определению является техническим долгом. Конечно, если есть такой код, то его лучше рано или поздно переписать. Но все мы знаем, что полировать код можно чуть ли не до бесконечности. Как же определить, какой код является техническим долгом?
Довольно хорошее описание технического долга дал Мартин Фаулер:
Like a financial debt, the technical debt incurs interest payments, which come in the form of the extra effort that we have to do in future development because of the quick and dirty design choice.
То есть, чем больше усилий во время разработки мы затрачиваем из-за какого-то куска кода, тем большим техническим долгом он является. С этим сложно не согласиться, но все же этого недостаточно для того, чтобы четко определить, какие места должны быть переписаны.
Для того, чтобы оценить, насколько каждый конкретно файл/класс/функция затрачивает наши усилия при разработке, Адам вводит такое понятие, как горячие точки, Hotspots. И для поиска этих хотспотов нужен только один инструмент, который есть практически у каждого разработчика — система контроля версий.
Оценить количество усилий на поддержку файла с кодом можно, взглянув на то, как часто этот файл меняется, и на то, какая сложность у этого файла. С оценкой частоты изменений все однозначно и понятно. Сложность можно оценить разными способами, в зависимости от ваших предпочтений. В простейшем случае это может быть размер файла или количество строк кода. При прочих равных условиях поддерживать файл на 100 строк кода сильно проще, чем файл на 1000 строк кода. Если же размер файла в вашем случае не является критерием оценки сложности, можно воспользоваться различными утилитами для статической оценки сложности (например, цикломатической).
Тогда хотспоты можно будет выявить следующим образом:
Вот пример поиска горячих точек в проекте Tomcat:
Большие синие круги — это папки. Маленькие — файлы.
При всем этом, наличие хотспота совсем не означает, что этот файл проблемный (но чаще всего так и есть). Это означает, что в этих файлах вы проводите больше всего времени. И что при рефакторинге эти файлы должны быть первыми в списке, чтобы убедиться, что код там чистый, легко поддерживаемый и расширяемый.
Также в качестве примера приводятся графики анализа кода нескольких проектов, разных насколько это возможно. Разные языки, разное время жизни, разные компании-разработчики. По оси X у нас расположены файлы, по оси Y — частота их изменений.
У всех проектов наблюдается один и тот же паттерн. Большая часть кода расположено в «хвосте» графика. И соответственно, есть очень небольшая часть файлов, которые изменяются очень часто. Эти файлы тоже являются первыми кандидатами для рефакторинга.
При поиске хотспотов можно пойти глубже. И в проблемных файлах искать хотспоты уже на уровне отдельных функций:
Инструмент, который был использован для поиска таких хотспотов — codescene.io
Также полезной практикой будет регулярной отслеживание сложности вашего кода. Анализ таких данных в виде графиков будет очень наглядно показывать, в какие моменты вы сбились с верного пути.
Итоги
Мне этот доклад показался полезным в первую очередь из-за четкого определения технического долга и его размера.
Понятно, что чтобы заниматься таким серьезным анализом кода с выявлением хотспотов, это нужно очень сильно увязнуть в технических долгах. Но даже на базовом уровне, в повседневной работе, я стал обращать внимание на классы, которые чаще всего затрагиваю, и стараюсь такие классы потихоньку рефакторить.
Также, в качестве бонуса (был вопрос из зала на докладе), Адам рассказал, как правильно доносить до менеджмента необходимость в рефакторинге. Чаще всего менеджеры — не технические люди, довольно далекие от кода, иначе бы проблем не возникло. Но что эти люди хорошо понимают — это цифры и графики. Чтобы правильно донести до них информацию, нужно говорить с ними на одном языке. И как раз графики с хотспотами и временной зависимостью сложности кода могут тут помочь. На графиках можно показать, что вот такой-то функционал, который мы добавили недавно, сильно усложнил добавление новых фич. Следовательно, если мы в дальнейшем хотим ускорить темпы разработки, нужно потратить сколько-то времени на рефакторинг.
Как технический долг и лже-Agile убивают ваши проекты
Каждый проект требует жертвы. Главное, чтобы не слишком большой. Мы перевели статью Алекса Стейвли про минусы технического долга и его способность уничтожить даже самый успешный проект. Предупреждение автора: в этой статье не так много практики, как хотелось бы, но она может натолкнуть на размышления.
Не путайте технический долг с плохими инженерными решениями
Понятие технического долга используют в разработке программного обеспечения для выражения дополнительной сложности, которая добавляется к проекту из-за выбора худших, но более быстрых решений. Он аналогичен финансовому долгу. Берете кредит для быстрого достижения какой-то цели, но потом обязательно его гасите. Иначе кредит с процентами будет расти — и в итоге вы рискуете обанкротиться.
В то же время, если вы берете слишком много технических долгов и не выплачиваете их, то софтверная энтропия растет со временем — также происходит и с процентами по кредиту. В конечном счете ваш продукт начнет стагнировать. Какая-то новая задача, которая должна решаться всего за месяц, вдруг занимает три месяца, затем шесть месяцев, затем лишь несколько человек во всей компании могут сделать ее за шесть месяцев, затем некоторые из них уходят, затем…
Аналогия не срабатывает лишь в том, что технический долг слишком часто приравнивают к плохой инженерии. Но плохие инженерные решения относятся к другой категории.
В случае технического долга приняты хорошие тактические решения с полным пониманием того, что краткосрочные приоритеты стоят такой жертвы.
Когда становится ясно, что такое решение в свое время было хорошей тактикой, гораздо легче понять, что нужно провести рефакторинг и погасить технический долг.
Когда этот термин используют в качестве вежливого синонима плохой инженерии, то стратегия возврата долга становится затруднительной. И ее еще труднее создать, потому что сначала нужно убедить людей, что есть какая-то «плохая инженерия». Затем нужно убедить людей, что это вызывает проблемы. Затем вы должны продумать лучший подход к рефакторингу и затратам на его проведение.
Как понять, что ваш технический долг уже слишком велик
Итак, каковы признаки того, что ваш технический долг (преднамеренный или случайный) слишком высок — и не за горами заявление о банкротстве?
Давайте порассуждаем. В мире Agile мы хотим разрабатывать и выпускать обновления продукта короткими циклами, получая от клиентов быструю обратную связь, и повторяя циклы снова. Это возможно только при наличии большого количества высококачественных и хорошо спроектированных автоматизированных тестов, которые работают быстро и дают уверенность, что никакое изменение ничего не поломало.
Не имеет значения, какова разбивка тестов по категориям: 68% модульных и 32% интеграционных или 91% модульных и 9% интеграционных, тесты должны выполняться быстро и надежно. В противном случае релизы станут проблематичными и не получится делать их регулярно.
Это означает, что работать по методологии Agile будет очень трудно, даже с самыми качественными сессиями backlog grooming, на которых анализируется набор требований, полученных от бизнеса, и формулируются задачи для разработки.
Сейчас есть много инструментов для измерения технического долга и его интеграции на красивую панель SonarQube, но обычно они учитывают только тривиальные вещи — неиспользуемый импортированный код и тому подобное. Кому до этого дело? Такие тривиальные вещи никому не помешают.
99Технический долг в информационной панели SonarQube
Настоящие технические проблемы с долгом — это когда замедляется разработка, затрудняется внесение изменений, исправление ошибок, добавление функциональности, потому что значительно усложняется тестирование. К сожалению, эти технические проблемы вряд ли вам автоматически покажут такие инструменты, как IDE, PMD или Checkstyle. Как правило, они гораздо глубже по своей природе — ближе к архитектурным проблемам.
Несколько примеров:
Именно здесь нарушается аналогия технического и финансового долга. Если у вас архитектурный долг, у вас большие проблемы. Если он более поверхностный, то проблема не так велика.
Технический долг есть. Что же делать?
Итак, вы приближаетесь к кредитному лимиту, что делать? Сначала следует обеспечить надежность тестов. Они должны тестировать ключевые функциональные возможности и быть ремонтопригодными. Это важнее скорости. Если нет надежности, вы не можете выпускать обновления продукта. Какой толк от пятиминутных тестов, если никто не уверен, что протестированные функции действительно будут работать.
Затем, когда вы уверены в тестах (даже если это уродливые сквозные тесты), нужно заставить тесты работать быстро. Потом начинайте рефакторинг. Сквозные тесты должны облегчить изменение путей вызова; например, для разбиения монолитной структуры можно применить Sprout method\class. Это поможет перейти к классической пирамиде тестов.
Теперь нужно понять, почему так сложно сделать качественные тесты. Слишком сильное сцепление компонентов программы, плохая обработка исключений, плохое разделение программы на части (слабая декомпозиция) — вероятно, список можно продолжать и продолжать.
Понимание причин, почему ваш код трудно покрыть тестами — ключевой архитектурный и инженерный навык, поскольку он требует не просто понимания сложности программы, но и знания, как уменьшить эту сложность. Тогда уменьшение технического долга поможет упростить код для тестирования и так сделать хорошие и быстрые тесты. В итоге мы начинаем побеждать в битве с возможной стагнацией проекта.