Шипы Вокруг Золота

Примечание автора: это перевод статьи Боба Мартина.

Меня вдохновило написать эту статью статья Марка Симана «Ловушка IsNullOrWhiteSpace» (@ploeh).

Статья Марка лаконична и хорошо изложена.

Пожалуйста, сначала прочтите его, прежде чем продолжать читать это.

Ловушка, о которой говорит Марк, — это частный случай более общей ловушки, которую я называю кража золота .

Я могу продемонстрировать эту ловушку, вернувшись к статье Марка.

Обратите внимание, что первый тест, который написал Марк, выглядел так:

   

[InlineData("Seven Lions Polarized" , "LIONS POLARIZED SEVEN" )] [InlineData("seven lions polarized" , "LIONS POLARIZED SEVEN" )] [InlineData("Polarized seven lions" , "LIONS POLARIZED SEVEN" )] [InlineData("Au5 Crystal Mathematics", "AU5 CRYSTAL MATHEMATICS")] [InlineData("crystal mathematics au5", "AU5 CRYSTAL MATHEMATICS")]

Он уже попал в ловушку.

Почему? Потому что он уже украл золото .



Золото и шипы

Основная функциональность, которую пытается описать Марк, — это упорядочивание слов в алфавитном порядке.

Естественно, его тесты отражают эту функциональность.

Основной функционал - золото и он украл его.

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

Что это за колючая изгородь? В случае Марка это значение null и пустая строка в качестве входных данных.

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

Я усвоил урок, что она всегда рядом.

Я понял, что если ты попытаешься украсть золото слишком скоро невидимая изгородь станет мешать вашему прогрессу и разорвет ваши усилия на куски [1].

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



Разведка и очистка

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

Именно в такой последовательности.

Один за другим я пишу такие тесты и заставляю их проходить.



Поведение исключений

Это поведение, которое обнаруживает недопустимый ввод, с которым основная функциональность никогда не должна сталкиваться.

Эти варианты поведения возвращают коды ошибок, регистрируют ошибки и/или выдают исключения.

В случае Марка обработка значений NULL — единственное исключительное поведение.

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

Конечно, эти случаи связаны с обработкой входных данных.

Но они также включают семантические нарушения, такие как удаление несуществующей записи или добавление уже существующей записи.



Дегенеративное поведение

Здесь мы говорим о входных данных, из-за которых основная функциональность «ничего не делает».

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

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

В конце концов он решил проблему таких строк с помощью сложного набора условий и операций, которые возвращали пустую строку в случае одного пробельного символа или пустую строку в качестве входных данных, в противном случае все пробельные символы были удалены [2].

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

Рассмотрим, например, компилятор Java, который обрабатывает исходные файлы, содержащие тысячи строк, состоящих из точек с запятой и комментариев.

Каким должен быть результат обработки?

Вспомогательное поведение

Иногда эти случаи труднее всего обнаружить.

Вспомогательное поведение — это поведение, которое окружает и поддерживает основную функциональность, но не является ее частью.

Например, функция getSize() класса Stack. Ответ на запрос размера не связан с основной функциональностью, реализующей LIFO. Дело в том, что вспомогательное поведение часто полезно для основного функционала по очевидным причинам.

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

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

Сначала я пишу все эти тесты и заставляю их проходить.

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

Тогда и только тогда я возьму золото .

[1] Действительно, буквально позавчера я провел четыре часа, запутываясь в шипах, которые промахнулся и не расчистил должным образом.

В конце концов, git Reset - Hard оказался моим единственным вариантом.

[2] Охватывает ли он все возможные условия? А как насчет табуляции, новой строки, пробелов и непечатаемых символов? Теги: #tdd #.

NET #дизайн и рефакторинг #tdd

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.