В ходе недавнего интервью для JUG.RU я отвечал на один из вопросов в примерно такой формулировке: “TDD – это замечательный подход и все об этом говорят, но на практике оказывается, что тестов пишется мало и далеко не все следуют данному подходу. Дело тут в лени разработчиков?”. Полная версия интервью еще готовится к публикации, но я для затравки решил опубликовать ответ на этот вопрос.
Тут дело не в лени разработчика. Тут дело в двух причинах, на мой взгляд.
Первая – это то, что люди не умеют этого делать. Для того, чтобы разрабатывать по TDD, необходима подготовка. И мало этого, необходимо понимание инструментария, как им пользоваться и какое он дает преимущество. Человек, который проходит курсы, или сам изучает TDD, или садится работать с кем-то грамотным, кто уже работает по TDD, видит столько преимуществ в работе, что после этого ему становится понятно, что глупо так не делать.
А вторая причина – это то, что многие из разработчиков, особенно с завышенной самооценкой, «включают режим архитектора». Это когда человек посмотрел на задачку одним глазком и говорит: «Окей, все, я вижу. Вот здесь у меня будет фабрика, здесь будет такой-то паттерн, здесь – такой-то». И он сразу эти мысли выплескивает в код. Потом наступает момент, когда надо интегрировать всё то, что он «напроектировал», с остальным кодом. И становится ясно, что оно не интегрируется. Или же кто-то смотрит код на code review, и становится видно, что все методы гигантские, ничего не понятно, пятой вложенности if-ы. Наверняка все видели примеры, когда «Hello, world!» при помощи дизайн-паттернов можно изобразить так, что не разберешься, что перед тобой «Hello, world!».
Когда ты работаешь по TDD, то ты написал тест, и теперь твоя задача просто в том, чтобы он заработал. Твоя задача не сделать суперклассный дизайн. Задача сделать суперклассный дизайн возникает уже после того, как код заработал. Ты потом смотришь на него и говоришь: «Вот я простое решение написал. А можно его как-то сделать красивее? Можно сделать его как-то более элегантным? Или reusable?» И если нет — ну окей. Оно работает и работает, поехали дальше. То есть вот причины: «режим архитектора» и неумение писать тесты, работать с правильным инструментарием.
Причем, если ты работаешь по TDD, то перед тобой не стоит задача писать тестируемый код, потому что у тебя нету шансов написать его нетестируемым. Если ты работаешь по TDD, то происходит так: пишешь-пишешь ты тест, наконец смотришь: «О, вот красивый API получился! Именно так и должно выглядеть, так оно и надо!» И сгенерировал быстренько весь API. Потому что благо, если мы говорим про Java-разработку, очень много всего генерируется с помощью IDE из теста и не надо писать руками. В итоге тот человек, который работает по TDD, работает чуть быстрее за счет этого фактора. Он не пишет руками ни одной сигнатуры метода, ни одного конструктора, ни одного поля. Это все генерируется. Причем мегабыстро. Все, что пишет человек, который работает по TDD – это реализации методов. IDE берет на себя создание классов, конструкторов, геттеры, сеттеры, декларации методов, очень сильно в этом помогает и экономит огромное количество времени.
В заключение, стоит упомянуть еще одну проблему с использованием TDD: TDD – это подход к разработке, который требует достаточно высокого уровня навыков дизайна кода и написания тестов. Если у вас их нет, то TDD их магически в вас не воспитает и не научит вас главному феерическому принципу любого программиста: “пиши только хороший код, а плохой не пиши вовсе”. Только тренировки могут помочь в этом вопросе, а это, в свою очередь, требует дисциплины. С дисциплиной у разработчиков, как известно, не все всегда хорошо. Вот и делаем как получается…
Если разработчик с джунских лет не приучен писать тесты, его можно убедить в том что тесты нужны и важны, экономят время и т.д. и т.п,. но он скорее всего все равно не начнет их писать, т.к. не знает как. Инструментарий есть, а как и что тестировать – не понятно.
Меня изначально учили: если у тебя нет тестов значит твой код не работает, поэтому у меня 1я реакция на проект без юнитов – “Как так без тестов то?” Начинаешь объяснять, бороться с возражениями, но в итоге даже те, кого удалось убедить в лучшем случае могут написать пару тестов проверяющих, что код работает в идеальном случае.
Я считаю ТДД отличной практикой. Я люблю писать тесты и разрабатывать через тесты. Однако чаще, чем хотелось бы у меня ТДД вызывает раздражение. Происходит это тогда, когда я не доконца понимаю интерфейс через который с моим кодом будут взаимодействовать другие компоненты, в том числе и юнит тесты. В таком случае в ходе разработки мне необходимо изменить интерфейс, а тесты мешают, увеличивая стоимость разработки. Например сегодня я разрабатывал Angular контроллер. Делаю тесты, пишу код, все здорово. Но вот я понимаю что набор свойств и методов контролера (интерфейс через который контроллер взаимодействует со вьюхой) можно значительно упростить. Упрощаю, и большинство тестов становятся непригодными. Удаляю их и раздражаюсь, что зря потратил на них время. Если во время жизненного цикла оставшиеся тесты не поймают ни одной регрессии (а так восновном бывает с относительно несложным кодом) то какой тогода ROI от этих тестов? Вот и кажется мне, что не все так просто и однозначно: разработчики либо неквалифицированные либо находятся в режиме архитектора 🙂
Стоить добавить что ТДД работает, только когда есть четкие требование к функционалу. Поскольку переписывания тестов и кода, под частые изменения требований к одному и тому ж функционалу, демотивирует разработчика и в результате он отказывается от ТДД.