Что я должен иметь в виду, чтобы провести рефакторинг огромной базы кода? - PullRequest
12 голосов
/ 16 мая 2009

Я собираюсь провести рефакторинг определенных частей в огромной базе кода (более 18000 классов Java). Цель состоит в том, чтобы иметь возможность извлекать нижние уровни как независимые библиотеки для повторного использования в других проектах, которые в настоящее время используют дубликаты этой базы кода. Особенно одна часть представляет интерес для преобразования в структуру, независимую от бизнес-логики. В конечном итоге я хотел бы, чтобы код имел чистую архитектурную структуру.

Я рассмотрел код с помощью инструмента под названием Structure 101 для Java и обнаружил множество (!) Проблем с архитектурным наслоением, когда нижние уровни ссылаются на верхние уровни.

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

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

Есть мысли по этому поводу?

Ответы [ 9 ]

7 голосов
/ 16 мая 2009

Вам также следует взглянуть на «Работа с устаревшим кодом» Майкла Фезерса:

http://www.amazon.com/Working-Effectively-Legacy-Robert-Martin/dp/0131177052/ref=sr_1_1?ie=UTF8&s=books&qid=1242430219&sr=8-1

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

5 голосов
/ 16 мая 2009

18 000 классов действительно стремятся к «огромному» концу вещей. Это создаст вам определенные проблемы, включая время сборки / компиляции и появление дыма из компьютера, когда вы запускаете ide.

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

Другим возможным источником избыточности являются бесполезно глубокие иерархии классов или груды бессмысленных интерфейсов (пример - там, где я работаю, существует каталог из примерно 50 классов, большинство из которых> 1000 строк (не мои, не мои!). Каждая из них реализует интерфейс, который является не чем иным, как собственным скелетом метода. Других реализаций этих интерфейсов не существует. Все 50 могут быть удалены без проблем). Есть также разработчики, которые только что открыли OO и действительно заинтересованы в этом - вы знаете, единственную конкретную реализацию, которая расширяет цепочку из 5 абстрактных классов и 3 интерфейсов.

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

4 голосов
/ 16 мая 2009

Первое: удачи, тебе это понадобится. Это потенциально ОГРОМНАЯ работа, с которой вы столкнулись. Это звучит очень знакомо для меня; Я работал над подобными вещами в прошлом.

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

Это сказало: я бы посмотрел на нарезку отдельных «вертикальных» фрагментов функциональности и посмотрел, сможете ли вы написать для них отдельные модульные и интеграционные тесты; как только это будет сделано, я запрыгну и начну работать над рефакторингом. Хотя поначалу он может быть очень маленьким, просто процесс выделения вертикального фрагмента функциональности, а затем написания кода интеграции и модульного тестирования для него даст вам большой опыт работы с существующей кодовой базой. И если вам удастся сначала сделать это немного лучше, то вы намного впереди.

После того, как вы это сделаете, начните искать потенциально большие блоки функциональности для рефакторинга. Если нет возможности получить чистые блоки функций для рефакторинга, я бы начал смотреть на небольшие куски; если вы можете найти небольшой (иногда ОЧЕНЬ маленький) кусок кода для извлечения, модульного тестирования и рефакторинга, вы двигаетесь вперед. Иногда это может показаться очень-очень медленным прогрессом, и это произойдет, если у вас действительно большой проект, но вы БУДЕТЕ делать вмятину.

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

3 голосов
/ 16 мая 2009

На мой взгляд:

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

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

  • подготовить текущую производственную среду и квалифицировать текущие ошибки, потому что параллельные запуски понадобятся, когда вы начнете рефакторинг (чтобы убедиться, что все те же функции работают), и вы не хотите, чтобы ваши параллельные запуски быть совместимым на 100% (потому что это означает, что вы успешно воспроизвели ошибки!)

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

1 голос
/ 16 мая 2009

Постарайтесь сделать свое дерево зависимостей как можно более плоским.

Один хороший способ сделать это - использовать инвертированные зависимости, другой код может зависеть от интерфейса / службы, но не от поставщика этой услуги. Это нам очень помогло.

1 голос
/ 16 мая 2009

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

0 голосов
/ 16 мая 2009

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

Я бы очень рекомендовал Рефакторинг Мартина Фаулера . Это единственный самый важный инструмент, который я нашел, который помог мне улучшить мой подход к работе с дерьмовой базой кода. Он описывает логичный и простой процесс рефакторинга любого кода. Это помогает прочитать это от кого-то, кто сделал это много раз.

0 голосов
/ 16 мая 2009

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

0 голосов
/ 16 мая 2009

Всего несколько мыслей:

  • Ищите общие шаблоны проектирования - попробуйте посмотреть, какие классы используются для основной работы, какие являются фабриками, какие - фасадами или адаптерами.
  • Разделите код на группы классов, которые зависят от состояния приложения или совместно используют его.
  • Определите, какие классы имеют постоянные объекты и те, которые сериализуются в / из базы данных (которые должны быть проще всего изолировать, обеспечивать самый чистый транзакционный интерфейс и затем переносимы между проектами)
...