Как стать автором
Обновить

Комментарии 27

«Написав одно и то же приложение, используя разные техники, я могу оценить их различия. На своей практике я увидел, как TDD помогает выстроить архитектуру, как мне кажется, более правильно. „
А не приходило в голову, что с ТДД ты выстроил архитектуру более правильно, потому что ты уже выстроил ее один раз до того? :)
Хм…
Новый способ разработки: разработка через повторную разработку.
ДеньСуркаДрайвенДевелопмент? =)
Временная разница между несколькими итерациями была полгода. Я уже не особо помнил, что было в первый раз, так как погрузился в другие задачи. Также, пока я не написал приложение второй раз, довольно тяжело было оценить качество первой итерации. После первого написания я считал, что архитектура, в общем-то, не так уж и плоха.
Давайте проведем еще один эксперимент :) Напишите какой-нибудь сервис, используя ТДД, а потом через полгода еще раз его же, но уже без ТДД. Если второй раз получится хуже, будем считать исходный тезис доказанным :)

Так себе аналогия. Если сначала без, а потом с ТДД, тогда еще можно притянуть.

Почитайте внимательно, вы потеряли контекст
Мои пять копеек на счет TDD.

1) TDD никак не влияет на архитектуру, ее определяет лишь полнота требований к продукту.
2) TDD замедляет разработку. Можно придумать сотни разных сценариев тестирования на одну небольшую функциональность. Причем процентов 80 будет абсолютно бесполезными.
3) Самое главное. TDD создает иллюзию хорошего кода. Это как ЕГЭ, главное тесты пройти.

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

Нет, это не так. Совсем не так. Скажите, если вы сначала вызовете ToList(), а потом отфильтруете, тест упадет? Нет, и вряд ли для тестов вы инжектите миллион записей, чтобы оценить реальное падение производительности. Конечно, существует еще и код-ревью, скажете вы. А не проще ли найти людей, которые умеют работать, чем неумех покрывать миллионом тест-кейсов и часами код-ревью?

Почему при таком количестве фреймворков, отличных инструментов, скрамов и код-ревью качество кода не растет год от года? Сложность растет? Что-то я думаю COM+ в 2000 году писать было куда сложнее, чем очередной REST API в 2019. Может быть, просто начнем думать над тем кодом, что пишем, а не надеяться на 50 проверок?
«1) TDD никак не влияет на архитектуру, ее определяет лишь полнота требований к продукту.»

Согласен, однако, если мы говорим о продукте, одни и те же бизнес-требования можно реализовать как монолитом так и микросервисами. Плюс, если мы говорим об одном сервисе, то требования к нему не расскажут Вам о разделении кода по слоям, принципам single responsibility и т.д. — с точки зрения требований абсолютно не важно каким образом Вы их реализовали.

«3) Самое главное. TDD создает иллюзию хорошего кода. Это как ЕГЭ, главное тесты пройти.»

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

«TDD пытается поставить с ног на голову и говорит, что именно проверка на ошибки и есть способ написания кода.»

В этой статье, я бы хотел предложить как способ написания кода первоначальный вопрос: «Что я от этого кода, собственно говоря, хочу?». Я не использую термин «проверки на ошибки». По моему мнению, покрытие кода тестами — это всего лишь дополнительная плюшка сверху.

«Может быть, просто начнем думать над тем кодом, что пишем, а не надеяться на 50 проверок?»

Вы абсолютно правы, я именно к этому и призываю). Абсолютно бесполезно писать тесты ради тестов.
1) Плюс, если мы говорим об одном сервисе, то требования к нему не расскажут Вам о разделении кода по слоям, принципам single responsibility

Не согласен. Требования они разные бывают. Требования к расширяемости, например, тоже требование. И разделение кода по пяти слоям и создание 100500 фабрик это не всегда нужные вещи. Иногда и монолит вполне себе нормально.

2) Вопрос «Что я от этого кода, собственно говоря, хочу?»

Этот вопрос и есть не про TDD. Этот вопрос про бизнес-требования к продукту. Они просто должны быть описаны в ТЗ, и разработчик сможет это реализовать.

Я просто еще раз хочу повторить, что не нужно добиваться 100% покрытия кода тестами. Нужно добиваться качественного кода, который отвечает поставленной задаче с минимальными затратами времени.

У вас как-то юнит-тесты с перфоманс-тестами смешались. :)

>Почему при таком количестве фреймворков, отличных инструментов, скрамов и код-ревью качество кода не растет год от года?
1) неумение выбросить прототип
2) аутсорс без контроля
3) отстуствие адекватных разработчиков, которые будут поддерживать код качественным

>Конечно, существует еще и код-ревью, скажете вы. А не проще ли найти людей, которые умеют работать, чем неумех покрывать миллионом тест-кейсов и часами код-ревью?
Ага, программирование это же просто по кнопкам тыкать
А не проще ли найти людей, которые умеют работать, чем неумех покрывать миллионом тест-кейсов и часами код-ревью?

А сколько такие люди запросят денег и нервов за свои умения и работу, в сравнении с теми что покрыты тестами и ревью?

В идеальном мире тесты нужны, так как изначально это не то что сейчас под ними подразумевается.
Изначально тесты это просто автоматизация рутины, например пишешь авторизацию и чтобы каждый раз вручную в браузере не ф5ячить и вбивать, программист пишет код который делает это за него. Так покрытие было например 25-35% и на основе цифр уже возник культ, а давайте всё вообще покроем, и чем больше тем лучше.
Разделение писать до или после бредовое изначально, зачем вообще возводить в абсолют и тем более давать этому отдельный термин «ттд», просто пиши как удобно, хочешь до хочешь после, а лучше и так и так по ситуации.
По поводу замедления ну тут опять таки все просто, они ускоряют когда ты их пишешь для ускорения, а как только начинаешь писать чтобы было, начинает тормозить
1) TDD никак не влияет на архитектуру, ее определяет лишь полнота требований к продукту.

Таки влияет. ;)
Очевидно, это происходит при условии TDD + голова.
При наличии только TDD, или только головы, вероятность сделать хуже — выше.

2) TDD замедляет разработку. Можно придумать сотни разных сценариев тестирования на одну небольшую функциональность. Причем процентов 80 будет абсолютно бесполезными.

Зачем придумывать и реализовывать бесполезные сценарии тестирования? Кто и что заставляет делать бесполезное?
Создавайте ровно те тесты, которые очевидно полезны.

Зачем придумывать и реализовывать бесполезные сценарии тестирования? Кто и что заставляет делать бесполезное? Создавайте ровно те тесты, которые очевидно полезны.

Такова философия TDD:


  1. Написать один минимальный тест, который код не будет проходить. И нет, нельзя написать сразу все тесты.


  2. Написать минимальный кусок кода, после которого будут проходить все тесты. При этом нельзя думать на несколько шагов вперёд, нельзя заранее продумывать архитектуру, нельзя реализовывать функционал, выходящий за рамки написанных тестов.


  3. Перейти к п.1, если требуемый функционал ещё не достигнут.


  4. Все тесты проходят? Отлично. Вот только теперь можно заняться рефакторингом и, наконец, переписать код нормально. И именно рефакторингом — функционал кода меняться не должен! Хочется добавить функционал? Начинай с п.1.



Если создавать только те тесты, которые очевидно полезны, тогда при чётком следовании TDD на выходе должен получиться недописанный говнокод. Поэтому на практике от TDD приходится отходить и следовать принципу "сначала пишем тесты — потом функционал" в общих чертах.

Можно ссылку на источник где именно 1,2,3,4 а не 1,2,4,3?

Да, верно. Рефакторинг можно делать после каждого из тестов. Ну суть понятна: код поначалу пишется кое-как, а зачем тратится время на его переписывание.

Насколько я помню, не можно, а нужно, кроме разве что самых тривиальных случаев… И об архитектуре никто не только думать не мешает, но и формировать требования к ней во врем янаписания теста и имплементировать её заставляя тесты проходить.

1) TDD никак не влияет на архитектуру, ее определяет лишь полнота требований к продукту.

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


2) TDD замедляет разработку.

Верно. TDD действительно замедляет разработку. Но фишка TDD не в разработке, а в поддержке. Если вы пишете код по принципу "написать и забыть", то TDD вам действительно не нужен. Положительный эффект от TDD проявляется на длинных дистанциях.


Можно придумать сотни разных сценариев тестирования на одну небольшую функциональность. Причем процентов 80 будет абсолютно бесполезными.

Написание нормальных тестов — тоже искусство. А тесты ради 100% покрытия не имеют никакого смысла.


3) Самое главное. TDD создает иллюзию хорошего кода. Это как ЕГЭ, главное тесты пройти.

Это верно для любых тестов. Прохождение тестов совершенно не гарантирует правильность работы кода.


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

Нет. Тест — это не проверка на ошибки. Это фиксация поведения кода при определённых входных данных. Тесты помогают программисту не сломать код при рефакторинге и добавлении функционала — вот их основная задача.

TDD не нуждается в сотнях тестовых кейсов "а проверим как код себя поведёт в таких-то условиях". TDD про исправление "ошибок" особого вида 'not implemented yet". Если вы написали тест и он не упал — это ошибочный тест по TDD.

Или это значит, что вы реализовали функционал до написания теста, что тоже противоречит TDD.

Именно это я имел в виду — тест ошибочный.

Есть хоть одно исследование как TDD влияет на метрики?
Я вот нашел https://arxiv.org/ftp/arxiv/papers/1711/1711.05082.pdf


Судя по метрикам TDD архитектуру и дизайн кода УХУДШАЮТ, причем по вполне очевидной причине. Попытка покрыть тестами весь код приводит к дроблению классов на все более мелкие, что приводит к снижению согласованности и увеличению связности классов.


Но есть и другое исследование https://people.engr.ncsu.edu/gjin2/Classes/591/Spring2017/case-tdd-b.pdf


Там приводятся тоже вполне очевидные выводы:
TDD увеличивает время разработки на 15%-20%, но снижает плотность багов в 1,5-2 раза. Только непонятно плотность учитывает увеличенный объем кода от TDD или нет.


И еще одно исследование, большое https://www.nomachetejuggling.com/files/tdd_thesis.pdf
Почитайте сами.


Увы в моей практике возрастание сроков на 15%-20% и пропорциональное увеличение объема кода гарантированно ставит крест на TDD.

Большое спасибо за ссылки на исследования! Я, к сожалению, не смог быстро ознакомится с исследованиями полностью, но внимательно прочитал Summary (Conclusions) каждого из них.

И, если честно, после прочитанного не могу разделить Вашего пессимизма.

В первом исследовании, действительно, пишут, что TDD не всегда улучшает high сohesion. Однако, автор уточняет, что утверждение верно, если TDD практикует программист с недостаточным количеством опыта.

Цитата
Here, the empirical data indicates that TDD does not always produce highly cohesive code as suggested in the literature. This is the case, at least, when the TDD users are inexperienced developers.

Во втором же, автор пишет в первом предложении Conclusions and Discussion, что TDD даёт плюшки без значимого снижения продуктивности

Цитата
Our experiences and distilled lessons learned, all point to the fact that TDD seems to be
applicable in various domains and can significantly reduce the defect density of developed
software without significant productivity reduction of the development team

Третье же исследование утверждает, что TDD в среднем на 21% улучшает качество кода.
В первом предложении Chapter 7 Conclusions.

Цитата
This study provided substantial evidence that Test-Driven Development is, indeed,
an effective tool for improving the quality of source code. Test-Driven Development
offered an overall improvement of 21% over code written using the test-last technique.
Considering the sheer volume of the codebases being analyzed, it’s reasonable to
conclude that the substantial difference is noteworthy.

И резюмируется следующее:
«With an improvement in metrics scores of 21%, Test-Driven Development appears to be extremely valuable as a Software Engineering practice. This work lends a great deal of additional validity to the assertion by Martin (2007) that not following the disciplines of Test-Driven Development would simply be unprofessional.»

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


Однако, автор уточняет, что утверждение верно, если TDD практикует программист с недостаточным количеством опыта.

Когда я учился в универе у нас был небольшой курс по методологиям.
Тогда было модно XP, мы спросили у препода о его мнении насчет этой методологии.


Он рассказал историю, про бум методик обучения в Советском союзе. В 80-х годах поднялся, как сейчас модно говорить, хайп с методиками школьного обучения. Проводились симпозиумы (конференции) заслуженных преподавателей, где они делились опытом о своих успехах. Только у других успехи были скромнее.


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


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


Мне почти всю жизнь довелось работать с посредственными программистами или чуть выше среднего, поэтому от всех "магических" методик я не получил никакого профита. А специально обученных TDD я не видел. Да и курсов на эту тему не видел.

Приведенное в статье TDD не канонично.
Согласно Кенту Беку не нужно сразу писать исчерпывающие тесты.
Вначале пишется пустой тест на несуществующий класс, затем создаётся класс. Если тест проходит, то пишется пустой тест на несуществующий метод, затем в класс добавляется сам метод. Затем тест на метод дополняется примитивной логикой, после чего уже пишется реализация самого метода, ну и т.д. Параллельно это все сдабривается изрядной долей рефакторинга, уже написанных тестов, так и методов.
Понятно, что многие вещи в процессе упускаются, но не на столько.
Должно соблюдаться правило: красный тест -> зеленый тест -> рефакторинг, и только после этого новый тест.
Согласен, на каноничность я не претендую. В моей практике именно каноничный TDD не помог отказаться от психотерапевта не прижился. Тут я рассказываю про свой опыт того что помогло.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий