Однажды рано утром в пятницу к Уорду Каннингэму зашел босс и представил его Питеру, перспективному заказчику системы WyCash. Эта система предназначалась для управления портфелем облигаций, ее разработкой и продажей занималась компания Уорда. «Возможности вашей системы впечатляют, – сказал Питер. – Но вот в чем проблема: я собираюсь открыть новый фонд облигаций. Как я понял, ваша система поддерживает облигации, номинированные только в долларах США. Мне же понадобится система, поддерживающая разные валюты». Босс повернулся к Уорду и спросил: «Мы сможем это сделать?»
Вот он, кошмарный сценарий для любого разработчика. Все шло хорошо, пока события развивались по намеченному плану, и вдруг все меняется. Надо сказать, это было кошмаром не только для Уорда – босс, съевший собаку на управлении программными проектами, тоже не знал, что ответить.
Система WyCash была разработана небольшой командой программистов за пару лет. Она позволяла работать с большинством ценных бумаг с фиксированным доходом, имеющих хождение на американском рынке. Более того, она поддерживала некоторые редкие инструменты рынка ценных бумаг, например гарантированные инвестиционные контракты (Guaranteed Investment Contracts), и этим выгодно отличалась от конкурентов.
В основу разработки WyCash легли объектно-ориентированные технологии, также была использована объектная база данных. Базовой абстракцией системы был класс Dollar, класс, который отвечал за вычисления и форматирование результатов. В самом начале работы над системой его разработку поручили отдельной группе хороших программистов.
В течение последних шести месяцев Уорд и остальные члены команды постепенно уменьшали количество обязанностей класса Dollar. Оказалось, что числовые классы языка Smalltalk вполне подошли для реализации вычислений, а для округления до трех десятичных знаков был написан специальный код. Результаты вычислений становились все точнее и точнее, и в конце концов сложные алгоритмы тестирования, выполнявшие сравнение величин с учетом погрешности, были заменены простым сравнением реального и ожидаемого результатов.
За форматирование результатов в действительности отвечали классы пользовательского интерфейса, а не класс Dollar. Так как соответствующие тесты были написаны на уровне этих классов, в частности для подсистемы отчетов2, поэтому предполагаемые изменения не должны были их коснуться. В результате, спустя шесть месяцев, у объекта Dollar осталось не так уж много обязанностей…
Один из наиболее сложных алгоритмов, вычисление средневзвешенных величин, также постепенно менялся. Вначале существовало много различных реализаций этого алгоритма, разбросанных по всему коду. Однако позже, с появлением подсистемы отчетов, стало очевидно, что существует только одно место, где этот алгоритм должен быть реализован, – класс AveragedColumn. Именно этим классом и занялся Уорд.
Если бы удалось внедрить в этот алгоритм поддержку работы с несколькими валютами, система в целом смогла бы стать «мультивалютной». Центральная часть алгоритма отвечала бы за хранение количества денег «в столбце». При этом алгоритм должен быть достаточно абстрактным для вычисления средневзвешенных величин любых объектов, которые поддерживали арифметические операции. К примеру, с его помощью можно было бы вычислять средневзвешенное календарных дат.
Выходные прошли как обычно – за отдыхом, а в понедельник утром босс поинтересовался: «Ну как, мы сможем это сделать?» – «Дайте мне еще день, и я скажу точно», – ответил Уорд.
В вычислении средневзвешенной величины объект Dollar как бы являлся переменной. В случае наличия нескольких валют потребовалось бы по одной переменной на каждый тип валюты, нечто вроде многочлена. Только вместо 3x2 и 4y3 – 15 USD и 200 CHF3.
Быстрый эксперимент показал, что при вычислениях можно работать не с объектом Dollar (доллар), а с более общим объектом – Currency (валюта). При этом, если выполнялась операция над двумя различными валютами, значение следовало возвращать в виде объекта PolyCurrency (мультивалютный). Сложность заключалась в том, чтобы добавить новую функциональность, не сломав при этом то, что уже работает. А что, если просто прогнать тесты?
После добавления к классу Currency нескольких (пока нереализованных) операций большинство тестов все еще успешно выполнялось; к концу дня проходили все тесты. Уорд интегрировал новый код в текущую версию и пошел к боссу. «Мы сможем это сделать», – уверенно сказал он.
Давайте задумаемся над этой историей. Через пару дней потенциальный рынок для системы WyCash увеличился в несколько раз, соответственно подскочила ее ценность. Важно, что возможность создать значительную бизнес-ценность за такое короткое время не была случайной. Свою роль сыграли следующие факторы:
□ Метод – Уорду и команде разработки WyCash потребовался опыт в пошаговом наращивании проектных возможностей системы, с хорошо отработанным механизмом внесения изменений.
□ Мотив – Уорду и его команде было необходимо четкое представление о значимости поддержки мультивалютности в WyCash, а также потребовалась смелость взяться за такую на первый взгляд безнадежную задачу.
□ Возможность – сочетание всеохватывающей, продуманной системы тестов и хорошо структурированной программы; язык программирования, обеспечивающий локализацию проектных решений и тем самым упрощающий идентификацию ошибок.
Мотив – это то, чем вы не можете управлять; сложно сказать, когда он у вас появится и заставит заняться техническим творчеством для решения бизнес-задач. Метод и возможность, с другой стороны, находятся под вашим полным контролем. Уорд и его команда создали метод и возможность благодаря таланту, опыту и дисциплине. Значит ли это, что, если вы не входите в десятку лучших разработчиков планеты и у вас нет приличного счета в банке (настолько приличного, чтобы попросить босса погулять, пока вы занимаетесь делом), такие подвиги не для вас?
Нет, вовсе нет. Всегда можно развернуть проект так, чтобы работа над ним стала творческой и интересной, даже если вы обычный разработчик и прогибаетесь под обстоятельства, когда приходится туго. Разработка через тестирование (Test-Driven Development, TDD) – это набор способов, ведущих к простым программным решениям, которые может применять любой разработчик, а также тестов, придающих уверенность в работе. Если вы гений, эти способы вам не нужны. Если вы тугодум – они вам не помогут. Для всех остальных, кто находится между этими крайностями, следование двум простым правилам поможет работать намного эффективнее:
□ перед тем как писать любой фрагмент кода, создайте автоматизированный тест, который поначалу будет терпеть неудачу;
□ устраните дублирование.
Как конкретно следовать этим правилам, какие существуют в данной области нюансы и какова область применимости этих способов – все это составляет тему книги, которую вы сейчас читаете. Вначале мы рассмотрим объект, созданный Уордом в момент вдохновения, – мультивалютные деньги (multi-currency money).