О вреде Test Driven Development

Artem Zakharchenko, специалист по тестированию и автор библиотеки для тестирования MSW с 15К звезд на GitHub, поделился мыслями о Test Driven Development.

Вот правда о TDD (Test Driven Development).

TDD - это неправильная практика. Она всегда была неправильной. Она неправильна по определению. Ее главная заслуга - поощрение тестирования, но на этом все и заканчивается.

TDD подразумевает написание тестов до написания кода. Так что же в этом неправильного? Вы пишете тесты, чтобы описать намерения, стоящие за системой - как вы ожидаете, что она будет себя вести. TDD в значительной степени подразумевает, что вы должны знать, как ведет себя система, еще до ее реализации. Вы должны знать, что вы делаете.

В большинстве случаев вы этого не знаете. Все разработчики, которых я знаю, не знают этого заранее. Я не знаю этого заранее. На самом деле, я могу потратить несколько дней на эксперименты, написание MVP, пока не начну немного понимать, какими должны быть части моей системы и чего я от них ожидаю.

Я не считаю TDD жизнеспособным подходом в быстро развивающихся системах, таких как веб. Он может иметь гораздо больше смысла при написании системного программного обеспечения, в котором очень мало что меняется от проекта к проекту. Это полная противоположность тому, что вы пишете в Интернете.

Негативный аспект TDD заключается в том, что я видел, как команды разочаровываются, если им не удается следовать ему. И тогда они отказываются от всей идеи тестирования, поскольку TDD так широко ассоциируется с ним. Вместо того чтобы поощрять людей к тестированию и показывать им, что тестирование программного обеспечения может быть интересным, эта практика запирает их в педантичных ограничениях, которым не может следовать ни один инженер.

Я не придерживаюсь TDD. Это не значит, что я не пишу тесты. Я пишу много тестов. Я занимаюсь разработкой прототипов, итераций и тестов.

Прототип. Я даю своим идеям простор и позволяю им дышать, не слишком заботясь о тестировании на первых порах. Я экспериментирую, меняю вещи, ломаю вещи, ставлю себя на место пользователя и разрабатываю API, поведение и ожидания. Как я уже сказал, это может занять некоторое время.

Итерация. Я трачу это время на то, чтобы убедиться, что моя система имеет смысл и удовлетворяет предъявляемым к ней требованиям (которые сами по себе могут развиваться и менять то, зачем я это делаю).

Тестировать. Наконец, я пишу тесты. Это стало неотъемлемой частью моего рабочего процесса. Я не могу представить себе, что не пишу тесты.

Конечно, бывают исключения. Если я пишу простую функцию ввода-вывода, то не нужно тратить день на то, чтобы понять, что она делает, потому что это все, что она будет делать. Я могу написать для нее несколько модульных тестов с самого начала. Но большинство моих (и, я уверен, ваших тоже) работ - это не простые функции. Это сложная логика, на отладку которой требуется время. Если я буду неукоснительно следовать TDD, я буду тратить время на написание тестов, которые в итоге выброшу. Это бесполезно и не поможет мне обрести уверенность в том, что я создаю.

Не отчаивайтесь. Применяйте те практики, которые работают для вас (даже если это TDD, лишь бы вы не лгали себе!). Главное, что тестирование имеет значение. Оно всегда имело значение. Разработчики тестируют программное обеспечение с 80-х годов, я полагаю. Вы тоже должны! Я сделаю все возможное, чтобы показать вам, что тестирование может быть доступным и увлекательным.

@gmtd
21.03.2024 12:29 UTC
Первоисточник

Комментарии

@nin-jin
21.03.2024 07:42 UTC
-4
@chaetal
25.06.2024 14:36 UTC
0

Что автор статьи, что автор этого ролика вообще не понимают смысл TDD.

@joffer
21.03.2024 07:49 UTC
+2

TDD всегда виделось как методология разработки, когда есть спецификация - тогда, если есть время, можно разрабатывать через TDD, а если времени немного - через "идеальные сценарии", чтобы в итоге получить рабочий скелет с основным функционалом, соответствующим спецификации, ну и затем уже некоторое сглаживание/рефакторинг во время тестирования/обкатывания.

Но чаще всего спецификаций нету, либо то, что есть под этим названием - в лучшем случае описание, что мы хотим, чтобы у нас было/работало/делалось, а при наличии сверок и корректировок "пути" с клиентом, да ещё и когда тоже толком нету ясности - что должно получиться, tdd здесь малополезен и затратен. Он не бесполезен, но по итогам затраты времени на адаптацию тестов к новым требованиям усложняют и затягивают разработку

@Anarchist
23.03.2024 23:50 UTC
+1

Даже со спецификацией писать тесты впереди кода имеет смысл только для самого верхнего уровня (и лучше это сделать заказчику). Тесты на подкапотную реализацию писать имеет смысл только с частично готовым кодом.

25.06.2024 14:44 UTC
0

Ну, откуда берутся эти суждения?!?

@chaetal
25.06.2024 14:41 UTC
+1

методология разработки, когда есть спецификация - тогда, если есть время, можно разрабатывать через TDD, а если времени немного - через "идеальные сценарии"

TDD как раз и есть способ получить спецификации. Именно в виде сценариев. Причём сразу в формальном виде — готовом к автоматическому выполнению.

И именно когда требования не ясны и могут меняться — именно тогда TDD максимально полезен и эффективен.

@andrejbestuzhev
21.03.2024 13:17 UTC
-3

В большинстве случаев вы этого не знаете. Все разработчики, которых я знаю, не знают этого заранее.

А что вы тогда делаете? Кто вам за это платит? Я тоже так хочу.

@onegreyonewhite
22.03.2024 04:59 UTC
+6

TDD в значительной степени подразумевает, что вы должны знать, как ведет себя система, еще до ее реализации. Вы должны знать, что вы делаете.

В большинстве случаев вы этого не знаете. Все разработчики, которых я знаю, не знают этого заранее. Я не знаю этого заранее.

Ужас. Я не хотел бы переходить на личности, но это прям даже звучит дико. Если вы не знаете что пишите, то как пишите? Методом научно-ненаучного тыка? По вдохновению правой пятки? Возможно с таким подходом TDD и правда мешать будет. Возможно проблема не в методологии.

Смысл написания тестов до кода, что тесты проверяют функциональность, которая требуется. Если нет требований, то что конечно тесты не написать. Но говорить о вреде TDD просто потому что у вас процессы... ну мягко скажем не очень, как минимум глупо.

@eertree
24.03.2024 11:58 UTC
0

Плюсую, обычно ведь есть ТЗшки, а если функциональные требования постоянно меняются.. то даже не знаю что делать: наверно стоит начинать с процессов :)

26.03.2024 17:31 UTC
+1

Когда требования постоянно меняются комплексно (т.е. "нам нужен белый автомобиль" поменялось на "нам нужно рыть землю") это смена задачи, а не направления. Здесь скорее gitflow нужен, чтоб спокойно оставить наработки и пойти в другую задачу.

А если в задаче уточнились детали, то тесты вперёд обычно выигрывают, потому что сразу всплывают все места, где нужно внести изменения, при этом не нужно искать что сломалось - оно всё вылазит на поверхность. Более того, при реализации тестов, быстрее возникают вопросы к задаче для уточнения, особенно если задача комплексная. Например, какие заголовки использовать, требования к протоколу передачи данных, формат полей и т.п.

Единственное место, где не нужно и вредно TDD - вёрстка.

25.06.2024 15:03 UTC
0

Контролировать требования. То есть фиксировать их, а затем при необходимости вносить изменения.

Фиксировать желательно максимально формально — чтобы не было неоднозначностей. В идеале настолько формально, чтобы можно было проверить, соответствует ли уже написанный код текущим требованиям, увидеть, где именно не соответствует и максимально быстро исправить. "Зафиксировать требования формально" в TDD называется "написать тесты".

@GulDmitry
22.03.2024 05:45 UTC
+4

В конце концов код и тесты должны быть написаны, последовательность тут не важна, это правда. Главное понимать, что тесты не менее важны чем код:

  • В вебе, энтерпрайзах чаще всего тесты важнее кода. Цельность фичи, интеграция разработчиков, бизнес инварианты это про тесты, а не про реализацию.

  • Если код тяжело тестировать = плохой код. Не всегда наоборот.

  • Тесты это тоже код, его надо уметь писать, изолировать тест кейсы, декомпозировать части логики.

TDD отлично помогает против таких разработчиков "я могу потратить несколько дней на эксперименты, написание MVP, пока не начну немного понимать, какими должны быть части моей системы и чего я от них ожидаю", а может экспериментировать и неделю, и может никогда не понять, чего ожидает от своего же кода. Если есть задача и в ней есть инварианты, то уже можно писать интерфейсы, абстрактные классы и тесты. Если человек может в ТДД, то он способен сперва понять, что надо делать, а не писать по-приборам. В таком случае тесты можно ревьювить до реализации.

Если резюмировать, то TDD для меня имеет скорее образовательный потенциал:

  • Научить, что разработка быстрее через тесты, чем проверку работоспособность того-же веба через страницу и мануальный ввод.

  • Заставить заработчика продумать систему, а не экспериментировать и переписывать MVP.

  • Когда не уверен в команде\разработчике и хочешь посмотреть правильно ли он понимает задачу.

  • Научить писать тесты, понимать баланс между интеграционными, юнит и функциональными. И что тесты это не про один метод execute вызывает другой execute .

Для разработчиков, которые умеют в понимание задачи, код и в тесты, заставлять точно не нужно.

@chaetal
25.06.2024 15:09 UTC
0

То есть TDD предоставляет программисту некий способ понять, что нужно запрограммировать до того, как начинать программировать. Отлично.

А какие ещё есть методологии для программистов, предоставляющие такие же возможности?

@barancev
22.03.2024 09:55 UTC
0

большинство моих (и, я уверен, ваших тоже) работ - это не простые функции. Это сложная логика, на отладку которой требуется время. Если я буду неукоснительно следовать TDD, я буду тратить время на написание тестов, которые в итоге выброшу

Разве те "примеры", которые используются для отладки, не выполняют роль тестов? Просто вы их почему-то не хотите так называть. Вы как бы делите тесты на "первый" и "второй" сорт. Ну да, часть из них, действительно, будет выброшена в итоге, но это нормально, любые тесты эволюционируют вместе с программой и с требованиями к ней, новые тесты появляются, существующие изменяются по мере уточнения требований, какие-то тесты становятся ненужными и исчезают.

@Suor
23.03.2024 07:05 UTC
+1

Для серьезной системы можно пару дней писать код, вообще его не запуская. И даже если запускать, то повторяемость, как правило, на этом этапе не нужна, а потому более оправдано тестировать вручную.

23.03.2024 23:46 UTC
0

Вот в этом не уверен. Если вы пишете несколько дней только код без тестов, либо вы гений, либо вас ждёт много мучительной отладки. Хоть на мелкие детали стоит писать тесты.

25.06.2024 15:21 UTC
0

Можно писать код вообще его не запуская. Не так давно — каких-то 50 лет назад — только такая возможность у многих и была: код писался на листочке одними людьми, совсем другие его "набивали", а третьи запускали, а автор получал распечатки. Но прошедшие десятилетия, кажется, довольно чётко показали, что хотя так можно, но лучше не надо ;)

@chaetal
25.06.2024 15:15 UTC
0

Выброшенный код, видимо, напрягает автора меньше :)

Тест представляет собой сценарий, в котором описывается поведение тестируемой (точнее, разрабатываемой) системы. Тест может быть "выброшен" только в том случае, если описанная в нём ситуация вдруг окажется невозможной в принципе. В противном случае тест останется, но будет изменён.

Причин выбросить код существенно больше.

@manyakRus
22.03.2024 10:54 UTC
+2

Наконец-то хоть кто-то не побоялся говорить правду :-)

ито статья похожа больше на чей-то перевод с другого языка

@hooy
22.03.2024 11:13 UTC
0

Странно, никогда не видел чтобы TDD воспринимался буквально — сначала тест, потом все остальное. Зачем писать тесты для PoC и экспериментов?

Иногда тест помогает отладке — тогда проще сращу его написать и им уже дергать свой сервис/функцию/вотэвер, но common sense подсказывает что есть куча исключений, как раз о том, о чем пишет автор. Вот только это не проблема TDD, это проблема в том, как кто-то его слишком буквоедственно воспринимает. Судя по тому что написал автор (всегда потом пишет тест) — он как раз таки следует TDD, оно про результат — все покрыто тестами, а не про буквальное — «блииин не могу тест написать сначала, все, у меня лапки, нафиг вообще эти тесты».

@Suor
23.03.2024 07:07 UTC
+1

TDD именно так люди понимают, что надо писать тесты до кода. Если в вашем окружении люди понимают иначе, то просто смягчили до чего то разумного.

@chaetal
25.06.2024 15:27 UTC
0

Потому что пишутся не тесты, а спецификация на поведение системы. PoC же не висит в воздухе, а показывает-доказывает реализуемость идеи. И наверняка полноценная система будет вести себя в уже реализованных аспектах если не так же, то "примерно так же". А раз PoC вообще начали, значит достаточно высока вероятность, что реализация таки будет. И тесты — представляющие собой построенную по требованиям спецификацию поведения системы в конкретных случаях — пригодятся.

@noodles
23.03.2024 16:43 UTC
+2

Тесты по TDD обычно пишутся теми же, кто пишет код. Если разработчик неправильно истолковал требования - то и тест, и тестируемый модуль будут содержать ошибку.

Вот если бы тесты писали постановщики задач перед тем как передавать задачу в разработку!.)

@Anarchist
23.03.2024 23:19 UTC
+1

Они часто не то, что тесты, требования сформулировать не могут. Как террористы, захватившие погреба Массандры.

@chaetal
25.06.2024 18:14 UTC
0

Первое разумное замечание в обсуждении! Жаль, поздно пришёл — плюсануть уже не дают.

@eertree
24.03.2024 02:30 UTC
0

Мне кажется вы неправы уже с начала статьи: "TDD - это неправильная практика. Она всегда была неправильной. Она неправильна по определению. Ее главная заслуга - поощрение тестирования, но на этом все и заканчивается."

TDD -- это концепция с своей границей применимости. Писать на все TDD не имеет смысла если у вас постоянно меняются функциональные требования.

TDD больше всего подходит для проектов с ясными функциональными требованиями, в идеале с Техническими Заданиями. Не рационально использовать TDD на участке где функциональные требования меняются каждый день.

Также не рационально пихать TDD на среды где затруднено писать тесты: это будет доставлять больше неудобства чем business value в виде качества продукта. Тем более если нет автоматизации тестирования

Тем более если код меняется очень часто, то тесты не становятся такими легкими в поддержании и вместо обеспечения качества они начинают мешать разработке.

Лучше всего использовать TDD на проектах с ясными функциональными требованиями (такое редко, но все же случается), с высокой степенью автоматизации и в основном на core domain часть, которая зафиксирована и меняется крайне редко: процессинги, шедулеры etc

Поэтому утверждать "TDD - это неправильная практика" -- это популизм, оправдывающий плохие практики и некомпетентность техлидов

@nin-jin
24.03.2024 04:12 UTC
0

- Эти часы полностью бесполезны, они стоят!

- Вот не правда, раз в сутки они показывают идеально точное время! Так что говорить, что они полностью бесполезны - популизм, оправдывающий вашу некомпетентность!

24.03.2024 11:39 UTC
+2

У меня тоже есть:

- Официант, яйца
- Вареные или жареные?
- Почесать
(с) Стетхем

К чему это я написал, это к тому вы написали не корректное ироничное замечание, потому что часы -- это предмет и их функциональные требования для часов -- это показывать корректное время в любой момент времени

В статье идет речь о методологии, у которой есть границы применимости

Сравнивать теплое с мягким неправильно ж-)

@chaetal
25.06.2024 18:07 UTC
0

TDD как раз нужно там, где требования меняются часто или не ясны. И да, тесты могут, будут и должны меняться — вместе с требованиями. Как и код, который эти требования реализует. Вы боитесь изменений? Попробуйте TDD ;)

@vsting
24.03.2024 14:29 UTC
0

Сложно написать надёжный код, если ты не знаешь заранее, чего от него ждешь.

Поэтому есть TDD, но это сложно, проще сначала написать какой-код(а потом ещё и прийти к выводу что он не нужен) и только потом покрывать авто тестами.