Статьи

Пакет Layer для весенних проектов устарел

Я считаю, что Spring-приложения не должны быть структурированы по принципу «пакет за слоем». На мой взгляд, пакет за функцией имеет гораздо больше смысла.

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

«Пакет по слою» («Папка по типу» в мире, отличном от Java)

Эта структура проекта группирует файлы исходного кода в пакеты / каталоги на основе уровня архитектуры, к которому они принадлежат:

.
└── net
    └── lkrnac
        └── blog
            ├── Application.java
            ├── persistence
            │   ├── ProjectRepository.java
            │   └── UserRepository.java
            ├── dto
            │   ├── ProjectDto.java
            │   └── UserDto.java
            ├── model
            │   ├── Project.java
            │   └── User.java
            ├── service
            │   ├── ProjectService.java
            │   └── UserService.java
            └── web
                ├── ProjectController.java
                └── UserController.java

«Пакет по функциям» («Папка по функциям» в мире, отличном от Java)

Этот подход, с другой стороны, группирует файлы, принадлежащие определенной функции в системе:

.
└── net
    └── lkrnac
        └── blog
            ├── Application.java
            ├── project
            │   ├── ProjectController.java
            │   ├── ProjectDto.java
            │   ├── Project.java
            │   ├── ProjectRepository.java
            │   └── ProjectService.java
            └── user
                ├── UserController.java
                ├── UserDto.java
                ├── User.java
                ├── UserRepository.java
                └── UserService.java

тенденции

Эта тема интересовала меня давно. Когда я сравниваю Google «пакет за слоем» с «пакет по функции» или «папка по типу» с «папка по функции», создается впечатление, что растет число сторонников структуры «по функциям». Я тоже в этом лагере.

Angular (одна из самых известных сред одностраничных приложений) продвигает такую ​​структуру папок в своем руководстве по стилю .

Весенняя структура проекта

Так как есть много литературы о плюсах и минусах каждого подхода, я сосредоточусь на последствиях для проектов Spring.

Традиционная структура создания приложений Spring CRUD (если ваше внутреннее приложение не использует Spring Data REST) ​​делится на три уровня: веб / служба / постоянство. Подавляющее большинство Java / Spring проектов, над которыми я работал, следовали этой структуре.

Связь

Пакет за слоем, скорее всего, берет свое начало в прошлом веке, где в качестве механизма развязки использовались многоуровневые архитектуры. На самом деле, «разделение» часто было ответом, когда я бросал вызов пакетным структурам слоев. Я не согласен. Для меня пакет за слоем является одной из основных причин тесной связи.

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

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

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

пересчет

Что произойдет, если проект начнет иметь более 10 классов в слое web / service / persistence? Разработчики склонны группировать классы в подпакеты. Но как они классифицируют их? По моему опыту, это в основном основано на функциях. Поэтому мы часто можем найти такую ​​структуру в более крупных проектах:

.
└── net
    └── lkrnac
        └── blog
            ├── Application.java
            ├── dao
            │   ├── ...other repositories...
            │   ├── ProjectRepository.java
            │   └── user
            │       ├── UserRepository.java
            │       └── UserRoleRepository.java
            ├── dto
            │   ├── ...other DTOs...
            │   ├── ProjectDto.java
            │   └── user
            │       ├── UserDto.java
            │       └── UserRoleDto.java
            ├── model
            │   ├── ...other models...
            │   ├── Project.java
            │   └── user
            │       ├── User.java
            │       └── UserRole.java
            ├── service
            │   ├── ...other services...
            │   ├── ProjectService.java
            │   └── user
            │       ├── UserRoleService.java
            │       └── UserService.java
            └── web
                ├── ...other controllers...
                ├── ProjectController.java
                └── user
                    ├── UserController.java
                    └── UserRoleController.java

Разве это не очевидное безумие?

Будущее Доказательство

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

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

Заключение

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