Как разделить большой Java-проект на более мелкие компоненты - PullRequest
8 голосов
/ 15 ноября 2008

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

Приложение состоит из WAR сервера и нескольких rich-клиентов, распределенных в JAR. Проблема в том, что все это в одной большой, волосатой базе кода, одном дереве исходников войны> 2k файлов. Каждый JAR имеет отдельный класс с методом main, но путаница зависимостей быстро завязывается. Это не так уж и плохо, хорошие практики постоянно следовали, и есть компоненты с конкретными задачами. Нужно просто улучшить ситуацию, чтобы наша команда масштабировалась по мере роста.

Каждый из модулей будет в проекте maven, построенном родительским POM. Процесс уже начался при перемещении каждого JAR / WAR в его собственный проект, но очевидно, что это только поцарапает поверхность: несколько классов в каждом JAR приложения и гигантский «старый» проект со всем остальным. Также уже есть несколько юнит-тестов и интеграционных тестов.

В любом случае, я интересуюсь инструментами, методами и общими советами по превращению слишком большой и запутанной кодовой базы в нечто более управляемое. Свободный / открытый исходный код является предпочтительным.

Ответы [ 6 ]

8 голосов
/ 15 ноября 2008

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

6 голосов
/ 17 ноября 2008

Недавно мы выполнили аналогичную задачу, то есть проект, который состоял из> 1 тыс. Исходных файлов с двумя основными классами, которые нужно было разделить. В итоге у нас было четыре отдельных проекта, один для базовых служебных классов, один для клиентской базы данных, один для сервера (проект является клиентским приложением rmi-server) и один для клиентского графического интерфейса. Наш проект пришлось отделить, потому что другие приложения использовали клиент только в качестве командной строки, и если вы случайно использовали какой-либо из классов графического интерфейса, вы испытывали исключения без головы, которые возникали только при запуске на сервере развертывания без головы.

Некоторые вещи, которые следует учитывать из нашего опыта:

  • Используйте весь спринт для разделения проектов (не позволяйте другим задачам мешать разделению, так как вам потребуется все время спринта)
  • Использовать контроль версий
  • Записать юнит-тесты до , переместить любую функциональность куда-нибудь еще
  • Используйте систему непрерывной интеграции (не имеет значения, выращен ли он дома или из коробки)
  • Минимизируйте количество файлов в текущем наборе изменений (вы сэкономите много работы, когда вам придется отменить некоторые изменения)
  • Используйте инструмент анализа зависимостей полностью до движущихся классов (мы добились хорошего опыта с DependencyFinder )
  • Потратьте время на реструктуризацию пакетов в разумные наборы пакетов проекта
  • Не бойтесь менять интерфейсы, но у вас есть все зависимые проекты в рабочей области, чтобы вы могли получить все ошибки компиляции
2 голосов
/ 15 ноября 2008

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

Если у вас уже есть сильный набор тестов, значит, вы в хорошей позиции. В противном случае, я бы провел несколько хороших тестов высокого уровня (иначе: системные тесты).

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

1 голос
/ 17 ноября 2008

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

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

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

1 голос
/ 17 ноября 2008

Чтобы продолжить ответ Итая, я предлагаю прочитать «Эффективная работа Майкла Фезерса с устаревшим кодом» (pdf) . Он также рекомендует, чтобы каждый шаг был подтвержден тестами. Существует также Книжная версия .

1 голос
/ 15 ноября 2008

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

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

Чтобы это работало, нам пришлось выделить необходимую функциональность, отличную от декоративного пуха, чтобы все это работало. Например, там много разных строковых классов, и один человек потратил то, что должно было потратить много времени на преобразование строки в 2 Кб между COleDateTime в const char* и обратно; это был пух, код для решения задачи, связанной с основной целью (получение информации из базы данных и из нее).

То, что нам пришлось сделать, это определить большую цель, которую достиг этот код, а затем написать для этого базовую логику. Когда возникла задача, которую нам нужно было выполнить, которая, как мы знаем, была выполнена ранее, мы нашли ее и обернули в вызовы библиотеки, чтобы она могла существовать сама по себе. Например, один фрагмент кода активирует драйвер устройства USB для создания образа; этот код не затронут текущим проектом, но вызывается при необходимости через библиотечные вызовы. Другой блок кода работает с ключом безопасности, а еще один запрашивает данные у удаленных серверов. Это весь необходимый код, который можно инкапсулировать. Тем не менее, код для рисования создавался более 15 лет и был настолько безумным, что переписывание в OpenGL в течение месяца было лучшим использованием времени, чем попытка выяснить, что сделал кто-то другой, а затем добавить к этому.

Я немного запутался, потому что наш проект был от MFC C ++ до .NET C #, но применяются основные принципы:

  1. найти главную цель
  2. определить все маленькие цели, которые делают возможным достижение главной цели
  3. Изолировать уже инкапсулированные части кода, если они есть, для использования в качестве библиотечных вызовов
  4. выяснить логику, чтобы собрать все воедино.

Надеюсь, это поможет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...