Экстремальное программирование. Разработка через тестирование - [8]

Шрифт
Интервал


$5 + 1 °CHF = $10, если курс обмена 2:1

$5 * 2 = $10

Сделать переменную amount закрытым членом класса

Побочные эффекты в классе Dollar?

Округление денежных величин?


Мы получили один рабочий тест, но в процессе заметили нечто странное: при выполнении операции с объектом Dollar изменяется сам объект. Хотелось бы написать так:


public void testMultiplication() {

Dollar five = new Dollar(5);

five.times(2);

assertEquals(10, five.amount);

five.times(3);

assertEquals(15, five.amount);

}


Я не могу представить простого способа, который заставит этот тест выполняться. После первого вызова метода times() пять уже больше не пять – на самом деле это уже десять. Если же метод times() будет возвращать новый объект, тогда мы сможем умножать наши исходные пять баксов хоть целый день, и они не изменятся. Для реализации этой идеи нам потребуется изменить интерфейс объекта Dollar и, соответственно, изменить тест. Это нормально, ведь вполне возможно, что наши догадки о правильном интерфейсе не более правдоподобны, чем догадки о правильной реализации.


public void testMultiplication() {

Dollar five = new Dollar(5);

Dollar product = five.times(2);

assertEquals(10, product.amount);

product = five.times(3);

assertEquals(15, product.amount);

}


Новый тест не будет компилироваться, пока мы не изменим объявление метода Dollar.times():


Dollar

Dollar times(int multiplier) {

amount *= multiplier;

return null;

}


Теперь тест компилируется, но не работает. И это тоже прогресс! Чтобы заставить его работать, придется возвращать новый объект Dollar с правильным значением:


Dollar

Dollar times(int multiplier) {

return new Dollar(amount * multiplier);

}

$5 + 1 °CHF = $10, если курс обмена 2:1

$5 * 2 = $10

Сделать переменную amount закрытым членом класса

Побочные эффекты в классе Dollar?

Округление денежных величин?


В главе 1, когда мы заставляли тест работать, мы начинали с заготовки и постепенно улучшали код, пока он не стал полноценным. Теперь мы написали сразу правильную реализацию и молились, пока выполнялись тесты (довольно короткие молитвы, честно говоря – выполнение тестов занимает миллисекунды). Нам повезло, тесты выполнились успешно, и мы вычеркнули еще один пункт.

Мне известны три способа быстрого получения зеленого индикатора. Вот первые два:

• подделать реализацию, иначе говоря, создать заглушку, возвращающую константу, и постепенно заменять константы переменными до тех пор, пока не получится настоящий код;

• использовать очевидную реализацию – просто написать сразу настоящую реализацию.

Используя TDD на практике, я периодически переключаюсь между двумя этими способами. Когда все идет гладко и я знаю, что делать, – я просто создаю одну за другой очевидные реализации (каждый раз запуская тесты, чтобы убедиться, что решение, очевидное для меня, также очевидно для компьютера). Как только я натыкаюсь на красный индикатор, я возвращаюсь к методике «поддельная реализация», после чего провожу рефакторинг. Когда уверенность возвращается, я снова использую методику «очевидная реализация».

Есть еще одна, третья методика, «Триангуляция» (Triangulation), которую мы рассмотрим в главе 3. Подведем итоги. Мы выполнили следующее:

• сформулировали дефект проектирования (побочный эффект) в виде теста, который потерпел неудачу (из-за дефекта);

• создали заглушку, обеспечившую быструю компиляцию кода;

• заставили тест успешно выполняться, написав вроде бы правильный код.

Преобразование чувства (например, отвращения, вызываемого побочными эффектами) в тест (например, двукратное перемножение одного и того же объекта Dollar) – обычная практика в TDD. Чем дольше я этим занимаюсь, тем легче эстетические суждения переводятся в тесты. В результате мои рассуждения о проектировании становятся более интересными. Сначала мы обсуждаем, должна ли система работать так или по-другому. После определения правильного поведения системы можно поговорить о наилучшем способе его реализации. Можно сколь угодно долго рассуждать об истине и совершенстве за пивом, но раз мы занимаемся программированием, у нас есть возможность оставить пустые разговоры и перейти к конкретике.

3. Равенство для всех

Если у меня есть целое число и я прибавляю к нему 1, то не предполагаю, что изменится исходное число, – в результате я ожидаю получить новое число. Объекты же обычно ведут себя иначе. К примеру, если у меня есть контракт и я добавлю 1 к его сумме, это будет означать, что сумма контракта должна измениться (да, несомненно, это пример для обсуждения многих интересных законов бизнеса, которые мы здесь рассматривать не будем).

Мы можем использовать объекты в качестве значений, так же как используем наш объект Dollar. Соответствующий шаблон называется «Объект-значение» (Value Object). Одно из ограничений этого шаблона заключается в том, что значения атрибутов объекта устанавливаются в конструкторе и никогда в дальнейшем не изменяются.

Значительное преимущество использования шаблона «Объект-значение» состоит в том, что не нужно беспокоиться о проблеме наложения имен (aliasing). Скажем, у меня есть объект Check, представляющий собой чек, и я устанавливаю его сумму – $5, а затем присваиваю эти же $5 сумме другого объекта Check. Одна из самых неприятных проблем на моей памяти заключалась в том, что изменение суммы в первом объекте может приводить к непреднамеренному изменению суммы во втором. Это и есть проблема наложения имен.


Рекомендуем почитать
Язык PL/SQL

В учебно-методическом пособии рассматриваются основы языка программирования PL/SQL, реализованного в системе управления базами данных Oracle Database Server. Приводятся сведения о поддерживаемых типах данных, структуре программ PL/SQL и выполнении SQL-предложений в них. Отдельно рассмотрено создание хранимых в базах данных Oracle программ PL/SQL – процедур, функций, пакетов и триггеров.


Введение в Direct3D8

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


Пишем драйвер Windows на ассемблере

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


Язык программирования С# 2005 и платформа .NET 2.0.

В этой книге содержится описание базовых принципов функционирования платформы .NET, системы типов .NET и различных инструментальных средств разработки, используемых при создании приложений .NET. Представлены базовые возможности языка программирования C# 2005, включая новые синтаксические конструкции, появившиеся с выходом .NET 2.0, а также синтаксис и семантика языка CIL. В книге рассматривается формат сборок .NET, библиотеки базовых классов .NET. файловый ввод-вывод, возможности удаленного доступа, конструкция приложений Windows Forms, доступ к базам данных с помощью ADO.NET, создание Web-приложений ASP.NET и Web-служб XML.


Вариации на тему STL. Адаптер обобщенного указателя на функцию-член класса

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


Самоучитель UML

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