Pull to refresh

Как не выстрелить себе в ногу

TDD *
Без использования unit-тестов и TDD очень легко выстрелить себе в ногу. С тестами и TDD сделать это намного сложнее, но если у вас получится, вы останетесь без ноги.

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

В этой статье я постараюсь объяснить о чем, собственно, разговор. Для чего нужно TDD и как его аккуратно использовать.

Что такое TDD в двух словах? — это написание разработчиком тестов до реализации функциональности.
По совету Роя Ошерова разобьем вопрос применимости TDD на два:

  • Зачем писать тесты?
  • Зачем писать тесты до реализации?


Вы все равно тестируете



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

Далеко не всем это нужно



На наших проектах разработчиков, которые не пишут тесты, мы зовем ЧакНоррисами, так как они неимоверно круты и мы им искренне завидуем.

Почему Чак не пишет тесты?


Его код идеален

В коде Чака Норриса никогда не бывает багов. Он никогда не ошибается. Если вы нашли баг в коде Чака — попробуйте поговорить с ним об этом — сразу поймете, что это на самом деле необходимая фича проекта.

Ему не нужна документация кода и коммуникация на проекте

На самом деле документация — это всего лишь один из способов коммуникации. Документируя код, мы общаемся с командой (с настоящей и с будущей), которая работает над проектом. Тесты — это лучшая документация. Бумажную документацию разработчики совсем не читают, да и пропадают куда-то эти бумажки и файлы все время. В написанных комментариях к коду далеко не всегда можно разобраться — что именно имел ввиду автор. В тестах же сразу видно как код работает, что от него хотят получить.
Чаку все это не нужно — он работает один.

Идеальная память

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

Рефакторинг без проблем

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

Почему вы не пишите тестов?


Не понимаю что это такое и зачем

Странная отговорка, особенно после того, как вы прочитали почему Чак Норрис не пишет тесты.

Нет времени

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

Это невозможно протестировать

Почти все можно протестировать, а что нельзя — то и не нужно. Mock фреймворки в этом очень сильно помогают. Unit-тестами нужно тестировать логику в вашем проекте. Тестирование взаимодействия с базой, с внешними сервисами и так далее — это уже разговор об интеграционных и функциональных тестах.

Это не моя работа

У нас есть тестировщики — пусть тестируют. Чем меньше багов вы оставите тестерам, тем меньше вам будет с ними работы в будущем. Работайте эффективнее — работодатели это ценят.

Мне и так хорошо

Поздравляю, вы — Чак Норрис.

Тесты экономят время. Тесты предотвращают повторение ошибок. С их помощью куда эффективнее документируется код и во время рефакторинга можно чувствовать себя куда более комфортно.

Так зачем их писать до реализации?




В этой картинке и фразе Кента Бека "Clean Code That Works" вся суть TDD. Мы хотим, чтобы наш код работал, и хотим, чтобы он был чистым. Вот и все. А с помощью шагов Red->Green->Refactoring, как показывает практика, добиться этого проще.
На этапе Red мы пишем тест, оцениваем дизайн нашей функции, тут же его исправляем. Убеждаемся, что функционал не реализован и тест не проходит.
На этапе Green мы достигаем цели — «Code That Works» — наша реализация начинает работать.
На последнем этапе цикла Refactoring мы реализуем цель — «Clean Code» и он все еще «That Works»… и идем дальше.

Главная мысль TDD — это вовсе не тесты, это вопрос дизайна. Когда вы пишите тест, вы спрашиваете самого себя, что вы хотите сделать и как это лучше реализовать. Тут же вы свой дизайн кода тестируете, попутно соблюдая принципы Keep It Simple Stupid и You Ain’t Gonna Need It.

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

TDD – это не серебряная пуля


К сожалению. Серебряных пуль вообще нет, как написал в своей книге Фредерик Брукс. И TDD не исключение. Вы все еще можете ошибаться, вы можете ошибаться в тестах. Unit-тестами все не ограничится, возможно, вам понадобятся интеграционные и другие виды тестов. TDD точно не хватит, чтобы покрыть весь ваш код. И самое главное — вам нужно будет все еще думать:) И не расслабляться.

Как начать использовать TDD?


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


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

Риск остаться без ноги


Неподготовленный старт

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

TDD ради TDD

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

Выход за границы применимости

С помощью TDD нужно тестировать логику проекта. Для всего остального существуют другие виды тестов. Да и не всякая логика поддается такому подходу — отличный пример описывается в статье Почему юнит-тесты не работают в научных приложениях

Фанатизм

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

Что почитать для начала


Test Driven Development: By Example

Первой книгой должна стать книга Кента Бека — в ней все основы TDD от автора этого подхода. Обязательна к прочтению.

The Art of Unit Testing: With Examples in .Net

Книга, которая поможет освоить первый навык — написание тестов. О TDD там буквально пара слов. Примеры на С#, но это не принципиально — полезна будет всем. Хорошую рецензию на книгу можно почитать тут.

Refactoring: Improving the Design of Existing Code

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

Refactoring To Patterns

Еще одна книга о рефакторинге. В ней Джошуа Кириевски показывает связь рефакторинга с design patterns. Рекомендую читать сразу после Фаулера.

Working Effectively with Legacy Code

Книга Майкла Физерса, в которой подробнейшим образом рассказывается как правильно работать с унаследованным кодом. Интересно, как автор определяет само понятие «унаследованный код» — это код, который не покрыт тестами:) Будет очень полезна для тех, кто работает с подобным кодом.

Надеюсь, что вы будете писать тесты и использовать TDD, но только там, где это действительно необходимо. Берегите ноги.

Статья подготовлена по мотивам моего недавнего доклада на Конференции .NET разработчиков.
Tags:
Hubs:
Total votes 77: ↑71 and ↓6 +65
Views 5.3K
Comments Comments 38