Чистый код, который работает, - вот цель, к которой надо стремиться. Рон Джеффриз
Введение
Разработка через тестирование (test driven development, TDD) - это подход, позволяющий писать чистый и рабочий код, небольшими кусочками наращивая функциональность, для которой были предварительно написаны небольшие тесты. По крайней мере, именно так говорят об этой методологии.
Так уж вышло, что мне на руки попалась книга Кента Бека "Экстремальное программирование. Разработка через тестирование". Поэтому я решил узнать больше об этой методике написания кода, чтобы выяснить для себя, насколько она действительно эффективна.В данной статье приводятся краткое описание методологии TDD, ее положительные и отрицательный стороны, мой опыт ее использования. Также в статье я ссылаюсь на собственный код, который в качестве эксперимента написал с использованием TDD. Кто хочет посмотреть на него сейчас, вот ссылка.
Описание TDD
Суть методологии проста. Сначала пишется тест для еще не существующей функциональности, который, конечно, не проходит. Потом вносятся изменения в код настолько минимальные, чтобы тест сначала хотя бы компилировался, а потом и проходил. Далее код рефакторится, чтобы он был больше поход на "чистый", тесты перезапускаются. Все это повторяется до тех пор, пока разработчик не будет доволен получившейся реализацией.
Если короче, то существует понятие цикла TDD, который неоднократно выполняется разработчиком для получения желаемого результата:
- Добавить тест. Убедиться, что он не работает
- Внести изменения в код. Убедиться, что тест работает
- Провести рефакторинг
TDD - это про мировоззрение
Чтобы использовать TDD, необходимо начать иначе мыслить. Если перед вами стоит задача, например, написать операцию добавления элемента в конец связного списка, то сначала необходимо думать не о том, как реализовать сам алгоритм, а о том, как протестировать поведение операции.
Также довольно тяжело тестировать весь код. Очень часто появляется соблазн написать небольшую вспомогательную функцию без тестов, так как ее реализация уже есть в вашей голове. Но тут необходимо справляться с подобными соблазнами. Ведь велика вероятность, что при написании этой функции вы допустите ошибку. Также велика вероятность, что от этой функции будет в дальнейшем зависеть большое количество кода, и если она не будет протестирована, то вы не будете уверены в этом коде.
Последнее, к чему необходимо привыкнуть, - это движение с переменной, но все равно достаточно низкой, скоростью. Дело в том, что вышеупомянутый цикл TDD должен быть максимально быстрым, а интервалы между циклами - максимально короткими. Это значит, что за один такой цикл придется писать достаточно мало кода. Это минимизирует вероятность ошибки, однако замедляет работу (но тут стоит вспомнить про время, которое уходит на отладку и тестирование и которое может сократиться с использованием TDD).
Стоит заметить, что скорость разработки напрямую зависит от сложности решаемой задачи. Если все идет хорошо, то необязательно добавлять по одной строчки кода за один цикл TDD. Однако если совсем тяжело придумать решение, то TDD с ее небольшими циклами позволит двигаться вперед всегда, пускай и небольшими шагами.
Преимущества TDD
У TDD есть преимущества, которые я прочувствовал, написав небольшую реализацию связного списка:
- Появляется уверенность в коде и в своих действиях. Если у вас есть протестированный код X, то вы можете уверенно, во-первых, менять код X, и, во-вторых, писать код, зависящий от X.
- Решение всегда находится в готовом, рабочем и протестированном состоянии. Переходы между рабочими состояниями короткие и относительно простые. Поэтому разработка становится более простой, приносит меньше стресса. В этом отношении разработка через тестирование напоминает мне скалолазание со страховкой - вы всегда можете сделать шаг вверх, не боясь упасть на самое дно.
- TDD ведет к лучшему дизайну. Так как сначала пишется тест, а потом код, который его реализует, то появляется возможность сначала продумать способ использования компонента. А если постоянно думать о том, как сделать компонент более удобным в использовании (как другими компонентами, так и людьми), то итоговое решение окажется лучше спроектированно.
TDD - не панацея
Конечно, не бывает идеального решения всех проблем. TDD не является исключением здесь. Данная методология имеет следующие недостатки:
- Так как тестирование, применяемое, в данной методологии, является модульным, то тестирование асинхронного кода крайне затруднено.
- Применять методологию к плохо спроектированному существующему коду довольно тяжело.
- Наличие тестов не гарантирует отсутствие дефектов (это относится к тестированию любого типа).
Вывод
Это было интересное приключение. Мне понравилось писать код с использованием TDD. Мне понравилось видеть зеленые индикаторы после запуска тестов. Мне понравилось чувствовать уверенность в написанном мной коде. Однако код был написан с нуля, да еще и в экспериментальных целях. Сейчас попробую применить данную методологию в коммерческой разработке и посмотреть, насколько хорошо она себя там проявит.