Существуют ли передовые практики для организации пакетов (Java)?

Некоторое время назад я увидел ответ на вопрос, касающийся тонкой организации пакетов Java. Например, my.project.util, my.project.factory, my.project.service и т.д.

Я не могу найти его сейчас, поэтому я могу также задать вопрос.

Существуют ли передовые практики в отношении организации пакетов в Java и что с ними происходит?

Как вы организуете свои классы в своем проекте Java?

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

Ваши мысли и комментарии приветствуются.

Ответ 1

Организация пакетов или структурирование пакетов обычно - это горячая дискуссия. Ниже приведены некоторые простые рекомендации по наименованию и структурированию пакетов:

  • Следуйте java соглашения об именах пакетов
  • Структура ваших пакетов в соответствии с их функциональной ролью, а также их бизнес-ролью
    • Разбивайте свои пакеты в соответствии с их функциональностью или модулями. например com.company.product.modulea
    • Дальнейший отрыв может быть основан на уровнях вашего программного обеспечения. Но не переходите за борт, если у вас всего несколько классов в пакете, тогда имеет смысл иметь все в пакете. например com.company.product.module.web или com.company.product.module.util и т.д.
    • Избегайте выхода из строя со структурированием, IMO избегает отдельной упаковки для исключений, заводов и т.д., если нет насущной необходимости.
  • Если ваш проект мал, держите его простым в нескольких пакетах. например com.company.product.model и com.company.product.util и т.д.
  • Взгляните на некоторые из популярных проектов с открытым исходным кодом на Apache projects. Посмотрите, как они используют структурирование для проектов различного размера.
  • Также рассмотрите сборку и распространение при именовании (позволяя вам распространять ваш api или SDK в другом пакете, см. сервлет api)

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

Ответ 2

Я организую пакеты по функциям, а не по шаблонам или ролям реализации. Я думаю, что пакеты, как:

  • beans
  • factories
  • collections

не правы.

Я предпочитаю, например:

  • orders
  • store
  • reports

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

Ответ 3

Краткий ответ: один пакет на модуль/функцию, возможно, с подпакетами. Поместите тесно связанные вещи вместе в один и тот же пакет. Избегайте круговых зависимостей между пакетами.

Длинный ответ: Я согласен с большей частью этой статьи

Ответ 4

Я предпочитаю функцию перед слоями, но я думаю, это зависит от вашего проекта. Рассмотрим свои силы:

  • зависимости
    Попробуйте минимизировать зависимости пакетов, особенно между функциями. Извлечение API, если это необходимо.
  • Организация команды
    В некоторых организациях команды работают над функциями, а в других - над слоями. Это влияет на то, как организован код, использовать его для формализации API или поощрения сотрудничества.
  • Развертывание и управление версиями
    Помещение всего в модуль упрощает развертывание и управление версиями, но затрудняет исправление ошибок. Разделение вещей обеспечивает лучший контроль, масштабируемость и доступность.
  • Ответить на изменение
    Хорошо организованный код гораздо проще изменить, чем большой шарик грязи.
  • Размер (люди и строки кода)
    Чем больше, тем более формализованным/стандартизированным оно должно быть.
  • Важность/качество
    Некоторые коды важнее других. API должны быть более стабильными, чем реализация. Поэтому оно должно быть четко отделено.
  • Уровень абстракции и точка входа
    Для постороннего должно быть возможно узнать, о чем код, и с чего начать чтение, посмотрев на дерево пакетов.

Пример:

com/company/module
  + feature1/
    - MainClass          // The entry point for exploring
    + api/               // Public interface, used by other features
    + domain/
      - AggregateRoot
      + api/             // Internal API, complements the public, used by web
      + impl/ 
    + persistence/       
    + web/               // presentation layer 
    + services/          // Rest or other remote API 
    + support/            
  + feature2/
  + support/             // Any support or utils used by more than on feature
    + io
    + config
    + persistence
    + web

Это всего лишь пример. Это довольно формально. Например, он определяет 2 интерфейса для feature1. Обычно это не требуется, но может быть хорошей идеей, если разные люди используют их по-разному. Вы можете позволить внутреннему API расширять общедоступность.

Мне не нравятся имена 'impl' или 'support', но они помогают отделить менее важные вещи от важных (домен и API). Когда дело доходит до именования, мне нравится быть максимально конкретным. Если у вас есть пакет с именем 'utils' с 20 классами, переместите StringUtils в support/string, HttpUtil в support/http и так далее.

Ответ 5

Есть ли лучшие практики в отношении организации пакетов на Java и что происходит в них?

На самом деле нет. Есть много идей и много мнений, но "наилучшей практикой" является использование вашего здравого смысла!

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

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

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

Ответ 6

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

В дополнение к этому я обнаружил, что гибридная стратегия "пакет за модулем, слой, затем функция" работает очень хорошо на практике, поскольку она имеет много преимуществ "пакет за функцией":

  • Способствует созданию фреймворков многократного использования (библиотеки с аспектами как модели, так и пользовательского интерфейса)
  • Позволяет реализации уровня "включай и работай" - практически невозможно с "пакетом по элементу", потому что он размещает реализации уровня в том же пакете/каталоге, что и код модели.
  • Многое другое...

Я подробно объясняю здесь: Структура и организация имени пакета Java, но моя стандартная структура пакета:

revdomain.moduleType.moduleName.layer. [layerImpl].feature.subfeatureN.subfeatureN + 1...

Куда:

revdomain обратный домен, например com.mycompany

moduleType [app * | framework | util]

moduleName, например, myAppName, если тип модуля - приложение, или "финансы", если это учетная структура

слой [модель | пользовательский интерфейс | постоянство | безопасность и т.д.,]

layerImpl, напр., wicket, jsp, jpa, jdo, hibernate (Примечание: не используется, если слой является моделью)

например, финансы

subfeatureN напр., бухгалтерский учет

subfeatureN + 1, например, амортизация

* Иногда "приложение" пропускается, если moduleType является приложением, но его размещение делает структуру пакета согласованной для всех типов модулей.

Ответ 7

Мне не известны стандартные методы организации пакетов. Обычно я создаю пакеты, которые охватывают довольно широкий спектр, но я могу различать в рамках проекта. Например, в личном проекте, над которым я сейчас работаю, есть пакет, посвященный моим настраиваемым элементам управления пользовательским интерфейсом (полный классов, подклассифицирующих классы swing). У меня есть пакет, посвященный моей работе с базой данных, у меня есть пакет для набора слушателей/событий, которые я создал, и т.д.

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

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

Ответ 8

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