📎 Webclip
Package by component and architecturally-aligned testing
Simon Brown presents package by component as a hybrid packaging style that aims for stronger modularity and clearer architecture in code. It keeps a presentation layer on top, but groups business and data access logic into coarse-grained components with public interfaces and package-protected implementation details.
Reading notes#
- Package by layer groups code by type, which can make data access easier to swap and layers easy to test, but it often leads to a big ball of mud.
- Package by feature groups code by vertical slice, keeps feature-specific classes together, and can hide some implementation details, but cross-feature access can push classes toward public visibility again.
- Package by component combines business and data access logic for a specific domain concept or bounded context, with a public interface and package-protected internals.
- New features that need data from other components must go through those components’ public interfaces, and direct access to data access code is not allowed.
- This approach depends on using Java access modifiers properly and not making classes public by default.
- For testing, the article suggests not forcing everything into “unit tests” and instead testing some classes in isolation and some components through their public interface.
- Domain classes, utility classes, and web controllers with mocked components are examples of classes that can be tested in isolation.
- Components that store data in MySQL should be tested end to end from the public interface back to the database.
- The article treats integration-style testing as component-level black-box testing, especially when the component controls what it touches.
- External services and asynchronous messaging may require dependency injection points such as ports and adapters to make testing practical.
- The same testing strategy applies to microservices, with class tests, service tests through public interfaces, and system tests end to end.
- Brown says this strategy produces a simpler codebase with understandable dependencies, less test-induced design damage, and code that better reflects the architecture drawn in design discussions.
