Как вы реорганизуете класс, который постоянно редактируется?

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

Мандат сократился. Нам нужно реорганизовать класс монстров. Большая часть плана состоит в том, чтобы определить категории функциональности в своих классах с отношением has-a с классом монстра.

Это означает, что много ссылок, которые в настоящее время читаются следующим образом:

var monster = new orMonster();
var timeToOpen = monster.OpeningTime.Subtract(DateTime.Now);

скоро будет выглядеть следующим образом:

var monster = new Monster();
var timeToOpen = monster.TimeKeeper.OpeningTime.Subtract(DateTime.Now);

Возникает вопрос: как мы координируем такое изменение на Земле? Ссылки на "orMonster" помещают каждый бизнес-класс. Некоторые методы вызывают буквально тысячи мест в коде. Это гарантировало, что в любой момент, когда мы сделаем такой шанс, кто-то еще (возможно, несколько человек-elses) в команде проверит код, который вызывает свойство .OpeningTime

Как вы координируете такое крупномасштабное изменение без прерывания производительности до остановки?

Ответ 1

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

Для получения дополнительной информации см. Метод перемещения в классике Мартина Фаулера, Рефакторинг.

Ответ 2

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

Ответ 3

Я уже справлялся с этим, продолжая и рефакторинг кода, но затем добавляя методы, которые соответствуют старой сигнатуре, которая переадресовывает вызовы новому методу. Если вы добавите атрибут "Устаревший" к этим временным методам, ваш код будет по-прежнему строить как с помощью старых вызовов метода, так и с помощью новых вызовов методов. Затем со временем вы можете вернуться и обновить код, вызывающий старый метод. Разница здесь в том, что вы получите "Предупреждения" во время сборки, чтобы помочь вам найти весь код, который нуждается в обновлении.

Ответ 4

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

http://dotnettipoftheday.org/tips/ObsoleteAttribute.aspx

Ответ 5

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

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

Объедините это с предложением Патрика чтобы монстр вызывал маленьких монстров. Это позволит вам легко вернуться, если ваш объединенный клиентский код нарушит изменения этого клиента. Как говорит Патрик, вы сможете удалить методы монстров (теперь заглушки), как только вы докажете, что никто не использует его.

Я также повторяю советы нескольких плакатов, чтобы разоблачить разбитые классы напрямую - не через монстра. Зачем применять только половину лечения? С такими же усилиями вы можете применить полное лечение.

Наконец: напишите единичные тесты. Напишите много модульных тестов. О, мальчик, тебе нужны юнит-тесты, чтобы спокойно снять это. Я упоминал, что вам нужны модульные тесты?

Ответ 6

Сохраните старый метод и перейдите к новому методу (как говорили другие), но также отправьте сообщение журнала в методе пересылки, чтобы напомнить себе, чтобы удалить его.

Вы можете просто добавить комментарий, но это слишком легко пропустить.

Ответ 7

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

Ответ 8

var monster = new Monster();
var timeToOpen = monster.TimeKeeper.OpeningTime.Subtract(DateTime.Now);

Я не уверен, что разворачивать его и просто сделать часть его публично доступной лучше. Это нарушает закон demeter и может привести к боли NullReference.

Я предлагаю разоблачить хронометриста людям без участия монстра.

Если вам что-то не понравилось, проанализировав API и увидев, что вы можете вырезать и инкапсулировать в монстра. Конечно, давать игрушки монстров, чтобы играть, в отличие от того, чтобы монстр выполнял всю работу, это хороший вызов. Основное усилие состоит в том, чтобы определить, как монстр игрушек должен упростить свою работу.

Ответ 9

Не рефакторируйте его.

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

И вместо этого: "monster.TimeKeeper.OpeningTime.Subtract(DateTime.Now)"

Сделайте это: monster.SubtractOpeningTime(DateTime.Now). Не убивайте себя точечным обозначением (отсюда и demeter)

Ответ 10

Несколько человек предоставили хорошие ответы относительно организации самого рефактора. Этот ключ. Но вы также задали вопрос о координации изменений между несколькими людьми (что, по моему мнению, было ключевым для вашего вопроса). Какой источник управления вы используете? Все, что связано с CVS, SVN и т.д., Может обрабатывать входящие изменения сразу от нескольких разработчиков. Ключом к его плавному прохождению является то, что каждый человек должен делать свои коммиты зернистыми и атомными, и каждый разработчик должен заставлять других людей часто совершать ошибки.

Ответ 11

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

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

С этого момента вы, скорее всего, получите меньше конфликтов слияния, поскольку в каждом файле будет меньше изменений. Затем вы можете изменить каждый метод в классе монстра (по одному методу на проверку), чтобы вызвать новые классы.

Ответ 12

Такой огромный класс действительно проблема. Поскольку он становился настолько большим, и никто не чувствовал себя неудобно, должно быть что-то не в порядке с политикой проекта. Я бы сказал, что вы должны разделить на пары и сделать пару программ. Создайте ветвь для каждой пары программистов. Работать в течение 1-2 дней при рефакторинге. Сравните ваши результаты. Это поможет вам избежать ситуации, когда рефакторинг будет идти с самого начала в неправильном направлении, и, наконец, это приведет к необходимости переписывать класс монстров с нуля.