Font Awesome Free 5.13.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)

Package by feature or component

A way to divide your system based on functional areas

Basic idea

Package by feature

Package by component

(image source )

  • Divide system into features/components based on functional areas
  • A feature/component exposes an interface for the outside world to use and hides its internals (including DB access etc.) from the rest of the codebase
    • In package by feature, features are separated up to the level of controllers
      • If one feature needs another, it needs to go through the controller
    • In package by component, the separation happens below the level of controllers
      • If one component needs to call another, there is no need to go through controllers
      • Controllers can group and combine data based on what makes sense to API consumers
      • A single controller can easily use several components (could be especially handy for retrieving data)
      • A single component could be used by several controllers
      • The way components are divided into functional areas could potentially differ from the way controllers are divided into functional areas
    • Encapsulation of internals should be enforced
      • Ideally, use language constructs like packages, modules, ...
      • Alternatively, integrate dependency checking rules into automated tests or linting
  • Top-level structure shows functional areas of the application rather than technical layers
  • Within feature/component, likely to have some kind of layered structure, may or may not be the same across all features/components

Note: probably still some cross-cutting concerns that apply to several features/components

  • Can just put these next to the features/components structure
  • Not all code has to be divided into features/components

Benefits/drawbacks

  • Good way to divide codebase into different functional areas that different teams could potentially take ownership of
    • "Modular monolith"
    • Can be a good stepping stone towards microservices
  • Finding a sensible way to divide the system into clearly separated features/components could be challenging or feel artificial for some applications

Testing

  • Some classes should be tested in isolation
    • Think domain classes, utility classes, ...
    • If large amount of mocking needed to test a class in isolation, it's maybe better to test it at another level
  • Some behavior easiest to test through public interface of feature/component
    • Treat feature/component as black box
    • Can still be useful to mock other components or external services when doing this

The "reshaped testing pyramid" by Simon Brown (aimed at package by component or microservices):

Reshaped testing pyramid

(image source )

Resources