Поспорил
тут с апологетом Agile по поводу степени применимости этого подхода, в частности, о возможности делать продукты без этапа проектирования с разработкой мегафрэймворка (с), а итерационно с помощью рефакторинга переходя к решениям, которые способны переварить новые требования заказчиков или бизнеса.
Итак, рефакторинг --- изменение кода программы при сохранении функционала. Изменение кода на практике означает применение пунктов из меню Refactoring вашей любимой IDE, а сохранение функционала обеспечивается Unit-тестами. Разумеется, хорошие IDE сами умеют рефакторить тесты при рефакторинге основного кода.
А теперь основные тезисы:
(1) рефакторинг не способен обеспечить качественного перехода на новый уровень продукта.
(2) качественный переход периодически требуется для выполнения новых требований.
(3) при качественном переходе львиная доля ваших тестов отправится в мусорную корзину.
Рассуждать на эту тему можно много, ограничусь примерами.
Пример первый, тактический. С помощью рефакторинга нельзя перейти от buble sort к qsort или от поиска подстроки в строке к поиску по похожести. Нет такой последовательности рефакторинговых действий, с помощью которых можно перейти от одного к другому.
Пример второй, стратегический. В коде исторически завелась 1000 условных конструкций, многие из которых опираются на несколько аргументов, причудливо связанных через OR, AND и NOT. Разумно править этим невозможно даже при совместном владении кодом и миллионом юнит-тестов. Юнит-тесты будут просто цинично показывать, что ЛЮБОЕ изменение привело к отъезжанию чего-то другого. Придется делать качественный переход на какой-то вариант системы управления правилами, с инструментами проверки их полноты, непротиворечивости и т.д. С помощью рефакторинга сделать этот переход невозможно. Придется полпроекта расколбасить, а вторую половину переписать почти с нуля.
Мораль.
(1) Рефакторинг делать надо.
(2) Но это не спасет.
(3) Юнит-тесты будут выкинуты. Придумайте способ как их получать, не тратя время. Например, автогенерацией, если ваша предметная область это хотя бы теоретически позволяет. Автогенерация юнит-тестов --- это качественный переход с разламыванием. Эволюционно перейти к нему нельзя.
(4) Устойчивый к изменениям код --- это код, который состоит из простых объектов с простыми типами и минимумом логики, зашитой в самих объектах. При этом фасад объекта должен давать иллюзию, что someobject.paintYourself() реализован в объекте, иначе у вас будет не ООП, а хрен знает что.
(5) Единственный способ писать такой код --- это использование мегафрэймворка, который многое унифицирует и за счет этого делает управляемым.
(6) На каждом этапе развития продукта нужен свой мегафрэймворк, который потом будет выкинут, как только новые требования в него не лягут.
(7) Хороший мегафрэймворк --- это такой, который не оставляет следов в объектах и не требует выполнения экзотических контрактов. Например, spring --- хороший. Hibernate с мэппингом в XML --- хороший, а с мэппингом на аннотациях --- плохой. Несмотря на то, что более удобный.
(8) Область применимости методологии разработки --- это даже не виды проектов, а различные этапы жизни и части внутри даже одного проекта.