Slicing an Application with Packages

Maciej Walkowiak
97 Things
Published in
2 min readJun 17, 2019

One of the first things a developer does after joining a project with an existing codebase is expand the directory tree to learn what the project does. Often the first thing the developer encounters is a package structure where each package represents a layer — like web, service, repository, and model. In this case, the application most likely exposes HTTP endpoints, does some business logic, and persists data to the database. Not very unique, right? But splitting an application by layer comes with serious drawbacks. That structure may work well for small, simple projects. For larger applications, where long-term maintainability is an important aspect of software architecture, there are other options to consider.

Layers don’t tell you anything about the business domain — there is no way to discover what the application does by going through the packages and diving deeper when you need more details. Layers also enforce a particular architecture for each feature: Code separation into web, service, and model may be a great fit for most use cases, but it’s definitely not the best choice for all.

Each feature is spread across multiple packages, which makes finding related classes hard. It also means that most of the classes have to have a public modifier — and can be used anywhere in the application — which leads to sharing classes between different features. Achieving encapsulation on the feature level becomes close to impossible.

One alternative that has proven to work well in traditional three-tier applications is to cut application into vertical slices. A slice can represent a single feature or a bigger chunk. The key is that a slice contains classes from all the layers required to build a particular functionality. It also lets you hide most if not all classes from other slices by changing their visibility to package protected. Classes that are meant to be used by other slices are public and become an API of the package.

In complex projects, a single package per slice may end up containing too many classes to be easy to comprehend, and you may find that splitting into subpackages would improve overall readability. That’s a perfectly valid option. Just keep in mind that you may need to increase some classes’ visibility to public and loose slice encapsulation guaranteed by the compiler. In that case, consider looking into tools such as ArchUnit that make sure slice boundaries aren’t violated during the unit test phase.

In addition to improved encapsulation, another advantage is that a sliced codebase doesn’t enforce the same structures across different slices. Maybe there is no need for services in some of them, and it’s enough to return data from repositories directly to controllers. Maybe there is no need to have controllers at all, and exposing repositories with Spring Data REST is the way to go. You can organize each slice in a way that best serves the particular feature.

--

--