Для тех, кто не знаком, с методологией TDD, советую предварительно ознакомится с материалами: отличная статья про суть подхода, моя статья с небольшим практическим примером
Эта статья, в формате небольших тезисов, нацелена на открытие дискуссии на тему "Test Driven Development" – методологии разработки через тестирование. На моем текущем месте работы существует несколько мнений: начиная от полного принятия и стремления(к tdd), как к идеальному инструменту написания рабочего и лаконичного кода, вплоть до полного отвержения: TDD не работает, убивает время разработчиков, увеличивая при этом time-to-market.
К каждому тезису, которые я выделил, я буду оставлять свой комментарий, стараясь быть объективным и не транслировать какую-либо позицию.
Жду ваших комментариев, уверен, что во многом я могу быть не прав.
Рассмотрим основные аргументы ЗА:
TDD ведёт к увеличению процента покрытия кода тестами
Это действительно, факт, и с ним сложно спорить. Методология подразумевает написание тестов ДО написания кода, поэтому процент покрытия такого кода скорее всего будет стремиться к 100%.
TDD дает разработчикам большую уверенность в надежности и функциональности кода
Действительно, такое ощущение часто возникает, однако это скользкая тема. Само по себе наличие каких-либо тестов, как я выяснил на практике, не гарантирует ровным счетом ничего.
TDD избавляет разработчиков от страха внесения изменений в код
В целом тезис – продолжение предыдущего. Может все-таки стоит хоть немного бояться?) Страх иногда штука полезная.
Но оговорка: если твои тесты отменного качества, то несомненно. Если вы можете рассчитывать на тесты на все 100%, то тут даже и думать нечего, бегом рефакторить все налево и направо, и функционала нового побольше!
TDD подталкивает разработчиков к более прагматичным решениям
Я знаю N-ое количество разработчиков, которых в целом невозможно подтолкнуть к прагматичным решениям, поэтому этот тезис работает далеко не на всех. (А зачастую, те, кто и так склонен к глубокому анализу и прагматичным решениям, могут записывать это в преимущества TDD)
TDD позволяет разработчику быстро получить обратную связь от изменений в коде
Опять-таки, в идеальном мире – да. Но в реальном мире, у вас просто могут быть плохие тесты, которые не позволяют получить обратную связь в тех местах, где она действительно нужна.
TDD позволяет разработчику сосредоточиться на поставленной задаче
Опять же, факт. Что бы написать, пусть даже и плохой, тест, и впоследствии написать код, который проходит этот тест, необходимо сосредоточится. Хотя я не помню ни дня, когда я решал какую-либо задачу, не сосредоточившись на ней (пусть и ненадолго, но такой этап всегда присутствует)
TDD способствует четкому пониманию требований до начала написания кода
Да, абсолютно, но с оговоркой) Тех требований, которые показались тебе понятными. Система сыпется полностью, если требования неправильно донесли, тз было прочтено не в той формулировке, юзеркейсы оказались неверными – все это полностью уничтожает весь вклад TDD в разработку.
Я также не уверен, что на нашей планете существуют крупные проекты, где все требования были ясны с самого начала, и вам, как разработчику были представлены гарантии того, что эти требования не изменятся.
TDD = документированный код
Грамотные тесты достаточно четко документируют происходящее в коде, отвечая на вопрос: а что реально должно тут происходить? Огромное количество тестов, с которыми сталкивался я, не были в состоянии ответить ни на подобный, ни на прочего рода вопросы.
Рассмотрим основные аргументы ПРОТИВ:
TDD отнимает время
Действительно, с этим фактом не спорит никто, ни сторонники, ни противники TDD. Разброс прироста к длительности процесса разработки составляет 10-35%, в зависимости от квалификации и опыта команды.
TDD не гарантирует качество тестов
Отмечу, что, по сути, не существует такой методологии, которая могла бы гарантировать их качество. Мы можем только стремиться к этому, улучшая процент покрытия кода с использованием, например, мутационного тестирования. Тык
TDD ставит перед разработчиком нереалистичные цели
Позволю цитату:
«в реальной жизни фичи устроены немного сложнее, чем «функция X должна принять имя и вывести приветствие с этим именем». Часто требования к продукту меняются посреди работы или вы вдруг осознаёте, что фича не может работать согласно требованиям. Или вы изначально всё не так поняли, и вам нужно начинать работу с нуля» - тык
Таким образом, ставить перед разработчиком цель написать тест, удовлетворяющий реальному изменению продукта, зачастую оказывается бессмысленным и пагубным занятием.
Изначальные требования могут быть поняты или сформулированы неверно
Да, сто процентов, такое может быть. Я уже озвучивал такую проблему выше, в противовес «четкому пониманию требований до начала написания кода»
Тесты необходимо поддерживать при изменении требований
Я думаю, каждому, кто работал на крупных проектах, приходилось видеть unit тесты низкого качества. Мало кто думает над парадигмой гибкости и переиспользуемости кода, при их написании, в результате чего тесты превращаются в полотно копипаста, которые при изменении поведений системы легче переписать с нуля, чем отрефакторить. Поддерживать тестовую базу возможно лишь при грамотном подходе к ее созданию, чего TDD не гарантирует.
TDD зависит от конкретного разработчика
Действительно, сложно спорить, что если разработчик размышляет, планирует и умеет писать хороший код, то он сделает это и без TDD.
Заставь дурака богу молиться – он себе и лоб расшибет. Тот, кто пишет код бездумно, лишь засорит проект ненужными, не проверяющими ничего тестами, что в последствии будет лишь тормозить разработку.
В умелых руках TDD превращается в мощный инструмент, я лично знаю очень хороших разработчиков, для которых эта методология – способ сосредоточится и обдумать предстоящие изменения. При этом я знаю не меньшее количество профессионалов, отказавшихся от TDD, и пишущих при этом качественный код.
На этом, наверное, все. Вывода не будет, решайте все сами.
А как вы относитесь к TDD?
Источники:
https://habr.com/ru/articles/334394/ -мутационное тестирование на примере php
https://habr.com/ru/companies/otus/articles/580772/ - мутационное тестирование в java
https://en.wikipedia.org/wiki/Test-driven_development - TDD, википедия
https://fortegrp.com/insights/test-driven-development-benefits/ - про TDD в целом
https://www.geeksforgeeks.org/advantages-and-disadvantages-of-test-driven-development-tdd/ - плюсы и минусы TDD
https://tproger.ru/translations/test-driven-development-is-dumb - яркий пример статьи против TDD
https://habr.com/ru/companies/ruvds/articles/450316/ - яркий пример статьи в пользу TDD
Комментарии (14)
powerman
29.08.2024 18:48+1То, что ставится на первое место, чему уделяется основное внимание - то и получается качественнее. Практикуя TDD мы получаем качество тестов выше качества кода. Ещё бывает Documentation-driven development - там та же проблема. Вряд ли это то, к чему стоит стремиться.
AnROm
29.08.2024 18:48По-моему TDD многие попробовали лет семь назад и отказались от этого подхода. Возможно потому, что неправильно его применили, не знаю. Бывает такое, что пишут тесты, потом код, и осознают, что тесты нужно переделывать. Получается, в этом случае тесты пишутся дважды. Концепция BDD(Behavior-driven development) выглядит более привлекательной и на практике даёт лучше результат. Она как-то лучше прижилась.
Sadler
29.08.2024 18:48TDD очень хорош в "задачах в себе", которые понятно, как тестировать без накручивания тонн моков и прочих симуляторов железа, делающих тесты менее репрезентативными. Я пробовал так писать, действительно, даёт какую-то уверенность в коде. Но чертовски долго и муторно.
На текущем проекте перебиваюсь valgrind, gcc с максимально выкрученными warning'ами, cppcheck, clang-tidy, фаззингом и автогенерируемыми тестами (chatgpt). Это всё тоже даёт какую-то уверенность, хотя и не непробиваемую.
voidinvader
29.08.2024 18:48Разработка через тестирование это примерно как трусы через голову надевать.
dyadyaSerezha
29.08.2024 18:48Классчиеский спор остро- и тупо- конечников. С какого конца начинать, зависит от ситуации. А иногда надо и с обоих. А иногда и ещё с другого, третьего, четвёртого конца. Наука умеет много гитик.
0xC0CAC01A
29.08.2024 18:48А вот почему не пытаются ИИ заставить писать код, прогоняя ответы через TDD? Вот где TDD действительно был бы полезен.
Sadler
29.08.2024 18:48Не знаю, как на уровне индустрии, а я таким занимался ещё на заре chatgpt: заставляем писать код с тестами, затем скармливаем результаты тестов и заставляем править код. Проблема лишь в том, что без программиста всё равно не получается: у LLM очень быстро возникает кризис идей, и нужно подсказывать и направлять, куда развивать дальше. Или иногда он упирается рогом, доказывая, что его код истинно верный, а весь остальной мир ошибается. Проще ли эта возня, чем самому написать? А вот фиг его знает, зависит от задачи. Ну, и контекста всегда катастрофически не хватает, каким бы большим он ни был :D
i360u
29.08.2024 18:48Хороший разработчик пишет тест до решения основной задачи, только когда это ему действительно нужно. И не пишет, когда не нужно. Когда эта практика навязывается извне, в рамках "эффективного менеджмента" - получается полная ерунда. Всегда.
Hardcoin
29.08.2024 18:48Далеко не все разработчики хорошие. 95% скорее средние и практика извне - чуть ли не единственный способ поднять качество проекта.
heart
29.08.2024 18:48Настроение автора и выводы понятны без их письменного документирования. Статья попытка оправдаться перед собой и возможно перед коллегами. Но действительность такова что TDD надо внедрять. Конечно нужен опыт.
«TDD подталкивает разработчиков к более прагматичным решениям»: В рамках ООП- шного языка программирования TDD тесно сотрудничает с SOLID и со всеми соседними прагдигмами. Требует знаний паттернов проектирования. Да и вообще ставит мысли на место.
Рефакторинг рано или поздно нужен всем. Как быть уверенным в том, что после рефакторинга можно вообще что то отдавать в прод? Трата времени на тесты после этого - отсутствие седых волос при внедрении. А если приходят новички? Как до них донести крайние тест-кейсы кроме как заранее не занести их все в UT?
«TDD способствует четкому пониманию требований до начала написания кода»: не понятно о чем речь. Не знаешь что писать, не начинай пока не разберешься
«Само по себе наличие каких-либо тестов, как я выяснил на практике, не гарантирует ровным счетом ничего.» Просто писать тесты ради тестов? Зачем? Если не понимаете сути то, конечно, лучше их не писать до тех пор пока в этом не разберетесь.
«Огромное количество тестов, с которыми сталкивался я, не были в состоянии ответить ни на подобный, ни на прочего рода вопросы.» Ну так это не аргумент, а просто факт что те тесты что вы смотрели были ужасными. Мотивировать их не писать он не может. Только наоборот.
«TDD отнимает время»: так в любой сфере. Вопрос: чье время и сколько оно стоит? Из опыта: «затраты» потраченное на тесты потенциально меньше разного рода суммы «затрат» на разных следующих этапах включая внедрение.
«Тесты необходимо поддерживать при изменении требований»: это преимущество при хороших тестах и минус при плохих. Не более не менее.
«TDD зависит от конкретного разработчика»: Исхода два. Помучается, попишет плохие тесты вначале, потом либо научится писать хорошие тесты либо нет. Некоторые сходу сразу схватывают прагдигму, некоторым и жизни не хватит, действительно. Но в целом этот факт тоже не отрицает пользы TDD
segment
Есть ли кардинальная разница между "написать тест -> спроектировать модуль -> довести модуль -> изменить тест" и "спроектировать модуль -> проверить прототип -> довести модуль до рабочего состояния с учетом всех новых данных -> написать тест"?
YegorP
Кардинальной - нет. На выходе в обоих случаях возможен один и тот же код, покрытый одними и теми же (плюс-минус) тестами.
youngmyn Автор
Есть мнение, что тесты, написанные после модуля, будут проходить с большей вероятностью, чем тесты написанные заранее.
Да и я склонен верить, что самостоятельное тестирование собственного приложения после его написания, выявит меньше потенциальных багов, чем обратная ситуация.
9982th
Тесты, написанные после модуля, имеют меньшую вероятность оказаться выброшенными в мусорную корзину из-за того, что модуль в текущем виде оказался нефункционален из-за неправильно понятого требования или неочевидной особенности библиотеки/протокола/интеграции и нужно кардинально менять интерфейс.