После статьи «TDD для начинающих. Ответы на популярные вопросы» мне на почту прислали довольно много разных вопросов. Большинство из них было про границы применимости TDD и о том, когда мы начинаем получать плюсы от использования этой практики. Вот один из типичных вопросов:
Насколько оправданно использовать этот подход [TDD] в небольших проектах в плане скорости?
Сейчас читаю книгу «Applying Domain-Driven Design and Patterns» Jimmy Nilsson. Автор книги пишет, что применение TDD по сравнению с обычными подходами приводит к более скорому завершению проекта. Но скорость разработки растет не сразу, а даже изначально проект будет продвигаться медленнее. (Понятно, что написание тестов и постоянный рефакторинг отнимает много времени). Вот мне интересно наступит ли в небольшом проекте этот момент, когда подход TDD начнет выигрывать по времени по сравнению с обычными подходами разработки?
Ответ на этот вопрос очень сильно переплетён с темой технических долгов. В разделе "Когда начинаем платить?" говорится именно про то, когда мы начинаем выигрывать по времени, если пишем тесты.
На графике показана скорость развития двух проектов. Синие забыли про дизайн и тесты, они решили написать как можно больше функциональности за меньшее время. Красные напротив, уделяют большое внимание дизайну системы и её тестированию.
Очевидно, что синие оставляют в коде много технических долгов, чем обрекают себя на трудности при расширении системы в будущем и проблемы с её поддержкой. Но за счёт чего красные умудряются держать систему гибкой и двигаться со стабильной скорость? Одна из причин - это использование TDD.
Написание проекта с помощью TDD дает нам ряд преимуществ:
- Самое простое – в таком проекте больше тестов, по сравнению с обычным подходом. На эту тему даже были проведены исследования. С одной стороны, само по себе количество тестов не гарантирует более высокого качества проекта и отсутствия ошибок. С другой, всё зависит от того, на сколько хорошо вы умеете писать эти тесты. Много хороших тестов сэкономят вам много времени.
- Код становится более качественным. Это связано с тем, что модульное тестирование подразумевает слабую связанность различных модулей системы, иначе будет очень сложно написать эти модульные тесты. Поэтому приходится постоянно применять принципы проектирования. TDD заставит вас всегда использовать принцип инверсии зависимости. В конечном счёте, это даст всей системе большую мобильность и гибкость.
- Мы можем перестраивать наш проект сколько угодно, адаптировать его к новым требованиям и не боятся, что после очередного рефакторинга мы потеряем какую-то уже работающую функциональность. Почему мы можем себе это позволить? Потому что после рефакторинга запустим все тесты и они нам покажут (зеленой полоской), что все бизнес-функции до сих пор работают.
Итак, TDD вынуждает писать более качественный код и лучше его тестировать. А это значит мы оставляем в коде меньше технических долгов.
Когда же TDD начинает обгонять? Тогда, когда синяя и красная линия пересекаются. В это время команда синих вовсю начинает платить за долги. Отсюда вывод о границах применимости TDD. Вы можете писать код без TDD, если уверены, что до пунктирной линии дело не дойдет. Например, вы пишете небольшой проект для автоматизации внутренней работы, или создаете сайт-визитку.
Надо понимать, что TDD – не гарантия качества вашего кода, но с ним проще держать систему в тонусе.
...Понятно, что написание тестов и постоянный рефакторинг отнимает много времени.
Это довольно популярное заблуждение. Давайте посмотрим в перспективе на несколько месяцев вперед. На самом деле, если мы тратим 1 ед. времени на тесты и рефакторинг, то при этом экономим 5 ед. времени на отладку в дебагере и разбор чужого кода. Так что TDD скорее экономит время, а не отнимает его.
Значит TDD нужно применять только для долгосрочных проектов или проектов, где нужно будет постоянное наращивание функциональности?
ОтветитьУдалить@M
ОтветитьУдалитьА ты знаешь проекты, в которых не требуется расширение функций или их изменение?
Конечно такие есть, но это либо совсем мелкие, либо какие-то очень специфические, например, автоматизация внутренней работы
Тайд или кипечение =)
ОтветитьУдалить@Алексей
ОтветитьУдалитьЛеха, для шёлка, только вручную!
Александр, любопытно, по вашим оценкам, пусть даже интуитивным - когда достигается этот breakeven point (названный на вашей диаграмме design payoff)?
ОтветитьУдалить@Dmytro Lapshyn
ОтветитьУдалитьПо времени оценивать бесполезно, т.к. это будет индивидуально для каждого проекта. Но вот есть один хороший ориентир.
Сначала система наращивает функциональность. За 2-3 месяца она может увеличится значительно. При этом новые функции практически никак не пересекаются со старыми.
Дак вот, когда наращивание замедляется или вовсе прекращается и начинается изменение этих функций (например, изменились некоторые требования или открылась проблема, которой раньше не видели), тогда и достигается эта точка. В это время программистам приходится платить за бездумный копипаст и ошибки в проектировании.
Получается, проект синих - этакая сборная из отсутствия дизайна, отсутствия TDD, с техническими долгами и без возможности расширения. Да, с таким проектом сравнивать удобно. Только непонятно, что именно из этого затрудняет накапливание функциональности. Я думал, публикация охватывает только TDD.
ОтветитьУдалить@Мурадов Мурад
ОтветитьУдалитьТ.к. TDD влияет и на дизайн, и на тех. долги, то получается, что применение TDD уменьшает все эти проблемы.
я бы вообще никому не советовал читать книгу Джимми Нильсона. Не удивительно, что возникли вопросы на тему того, когда возникает эффективность.
ОтветитьУдалитьПонятно, что если необходимо набросать за пару часов небольшую прогу для автоматизации одноразового процесса использовать TDD - смешно. Но, по своему опыту знаю, что даже их таких Q&D прог , часто вырастают большие и долгосточные проекты , которые как лоскутное одеяло состоят из кусков кода наспех "пришитыми" к предидущей версии
ОтветитьУдалить