Is TDD Dead, part 2

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

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

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

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

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

Очень часто наличие интерфейсов объясняется не только желанием протестировать класс в изоляции, но и попыткой дать возможность заменить компонент без перекомпиляции приложения. Этот момент очень классно прокритиковал Кент и Дэвид: попытка заменить слой доступа к данным и заменить базу данных веб-сервисом, или in-memory DB на практике невозможна, поскольку каждая из этих реализаций обеспечивает слишком разные характеристики с точки зрения надежности или времени исполнения. На практике даже переход от одной реляционной СУБД на другую оказывается сложным или невозможным, не говоря уже о таких принципиальных сменах «деталей реализации».

Кент Бек:
«You think you decoupled, but in reality you really, really not!»

И, напоследок, отличная мысль от Кента по поводу Дизайна (да, с большой буквы):

«Я сейчас не говорю об использовании или не использовании TDD. Я сейчас говорю о дизайне в целом. TDD не принимает за вас решения, это делаете вы. Если вы приходите к решению, которое вас не устраивает, так принимайте другой решение. 
Здесь нужно сделать шаг назад к основополагающим принципам: как вы будете получить обратную связь от системы, как вы будете проверять качество вашего API, как вы получите ту уверенность в системе, о которой мы говорили в прошлый раз. Никто не решит это за вас. Я думаю о дизайне и мне плевать на наличие или отсутствие TDD. Для меня важны эти основополагающие вещи, а процесс (workflow) находится где-то далеко в низу этого списка.»

Очень интересно слышать, как Кент Бек, «папа» TDD говорит о том, что он чего-то не знает и готов учиться. Поэтому если вдруг вы считаете, что вы знаете все о дизайне, или, не дай Бог, все о TDD, вспомните эти слова Кента. Идеального процесса не существует, нужно всегда продолжать развиваться и смотреть на известные истины с новых сторон.

И главное: ни один инструмент не приведет к хорошему дизайну, эти решения принимать вам. Инструмент может стимулировать к принятию хороших или плохих решений, но эти решения все равно принимать вам!

#isttddead, #tdd, #design
Shared publiclyView activity