The TDD That Works for Me

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

Test-driven development (или TDD) был восстановлен Кентом Беком и объяснен в его знаменитой книге в 2002 году. В 2014 году Дэвид Хейнемайер Ханссон (создатель Ruby on Rails) заявил, что TDD мертв и только вредит архитектуре. Роберт Мартин (изобретатель принципов SOLID) не согласился и объяснил, что TDD может не работать только в определенных случаях. Через несколько дней он даже сравнил важность TDD с важностью мытья рук в медицине и добавил, что “не удивлюсь, если однажды TDD станет обязательным законом”. Два года спустя, всего несколько месяцев назад, он написал больше об этом, и больше, и больше. Эта тема, кажется, актуальна. Конечно, у меня есть собственное мнение на этот счет; позвольте мне поделиться.

В теории, TDD означает “сначала пишем тесты, затем код”. На практике, судя по моему опыту работы с более чем 250 разработчиками за последние четыре года, это означает, что мы пишем тесты, когда у нас хорошее настроение и нет других дел. И это только логично, если мы понимаем TDD буквально, как в книге Кента Бека.

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

За последние четыре года я лично написал почти 300 000 строк кода на Java, Ruby, PHP и JavaScript, и я никогда не делал TDD по книге: “написать тест, сделать его работающим, сделать его правильным”. Никогда.

Несмотря на то, что я являюсь огромным поклонником автоматизированного тестирования (юнит-тестирования или интеграционного) и полностью согласен с Ункл Бобом: тех, кто не пишет тесты, следует посадить в тюрьму, у меня есть своя собственная интерпретация TDD. Вот как это выглядит:

  • Затем я развертываю его в продакшн. Да, он попадает к моим “пользователям” без каких-либо тестов, потому что он работает для меня. Они могут быть либо настоящими пользователями, если это что-то с открытым исходным кодом или одним из моих пет-проектов, либо ручными тестировщиками, если это коммерческий проект.

  • Затем они ломают его. Они либо тестируют его, либо используют; это не имеет значения. Они просто находят проблемы и сообщают об ошибках. Сколько только могут.

  • Сразу после сообщения о некоторых ошибках я выбираю наиболее критические из них и… вуаля!… создаю автоматизированный тест. Ошибка для меня - это сигнал о слабости моих тестов, которые необходимо исправить в первую очередь. Новый тест покажет, что код сломан. Или, возможно, я исправлю существующий тест. Здесь я придерживаюсь подхода “сначала тесты”. Я не трогаю код в продакшене, пока не удастся сломать сборку и доказать существование проблемы с помощью нового теста. Затем я выполняю git commit.

  • Наконец, пришло время исправить проблему. Я вношу изменения в производственный код, чтобы убедиться, что сборка снова проходит успешно. Затем я выполняю команды git commit и git push. И я перехожу к шагу “развертывание”: обновленный продукт достигает пользователей.

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

Обоснование такого подхода без предварительного тестирования простое: нам не нужно тестировать, пока что-то не сломается, главным образом потому, что мы понимаем, что технически невозможно протестировать все или исправить все ошибки. Мы должны исправлять только то, что видимо и неприемлемо для бизнеса. Если бизнес не обращает внимания или наши пользователи/тестеры не видят наши ошибки, мы не должны “тратить” ресурсы проекта на их исправление.

С другой стороны, когда бизнес или наши пользователи/тестеры жалуются, мы должны быть очень строгими с собой; наша система тестирования слабая и должна быть исправлена в первую очередь. Мы не можем просто исправить код продукции и развернуть его, потому что в этом случае мы можем снова сделать эту ошибку после некоторой переработки, и наши тесты не поймают ее. Пользователь снова найдет ошибку, и бизнес опять заплатит нам за ее исправление. Это будет “тратой” ресурсов.

Как видите, все здесь зависит от денег. Во-первых, ничего не исправляйте, если за это никто не платит. Во-вторых, исправьте это раз и навсегда, если они на самом деле заплатили. Все так просто.

Благодаря такому подходу, когда исправления производятся только в случае неисправности, баланс между рабочим кодом и кодом тестов не одинаков на всем протяжении жизненного цикла проекта. Когда проект только начинается, практически нет тестов. Затем количество тестов растет вместе с числом ошибок. В конце концов, ситуация стабилизируется, и мы можем перейти от бета-версии продукта к первому релизу.

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

yegor256/takes (веб-фреймворк, Java):

yegor256/xembly (XML-конструктор, Java):

jcabi/jcabi-aspects (библиотека AOP, Java):

yegor256/s3auth (шлюз S3, Java):

Первый коммерческий проект:

Второй коммерческий проект:

На каждом графике есть две части. Первая сверху демонстрирует динамику рабочего кода (зеленая линия), тестовых HoC (красная линия) и количества проблем, сообщенных в GitHub (оранжевая линия).

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

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

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

Вы также можете проанализировать свой проект с помощью моего инструмента и увидеть график. Было бы интересно узнать, какую кривую вы получите.

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-17 at 17:01

sixnines availability badge   GitHub stars