Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HhW8LD8r3EigoBaCGrQZx5 Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01HhW8LD8r3EigoBaCGrQZx5
2.2 KiB
project-structure
Companion project for the article Spring Boot Project Structure: Package-by-Layer vs Package-by-Feature on ankurm.com.
One small library application (books, plus loans in the feature layout) written twice, with the same
HTTP API, so the only difference between the two is where the files live. Every console block quoted in
the article came out of output/, written by the test suite, so a claim that stops being true turns the
build red.
There is deliberately no docs/ folder: the deeper material lives in collapsible sections inside the
article itself.
Versions
| Spring Boot | 4.1.1 |
| Spring Framework | 7.0.9 |
| JDK | 21 (OpenJDK 21.0.12) |
| Maven | 3.9 |
The module was compiled and run on JDK 21 only; it has not been run on JDK 25.
Quickstart
mvn test # runs everything and rewrites output/01-04
./scripts/run-all.sh # same, then lists output/
mvn spring-boot:run # starts the recommended (by-feature) layout on :8080
Source layout
| Package | What it is |
|---|---|
bylayer/ |
package-by-layer: controller/, service/, repository/, model/, dto/, exception/ |
byfeature/book/ |
the book feature: everything package-private except BookCatalog, the feature's public API |
byfeature/loan/ |
the loan feature: uses books only through BookCatalog |
byfeature/shared/ |
cross-cutting: ApiException and the one @RestControllerAdvice |
Both applications have their own @SpringBootApplication (ByLayerApp, ByFeatureApp), and each scans
only its own package, so the two never see each other's beans.
Captured output
| File | What it shows |
|---|---|
01-package-trees.txt |
the real source tree of both layouts (9 files vs 15 files) |
02-public-surface.txt |
every top-level type and whether it is public: 9 of 9 by layer, 3 of 15 by feature |
03-compiler-boundary.txt |
the same one-line shortcut (new BookRepository() from another package): compiles by layer, rejected by javac by feature |
04-same-api-both-layouts.txt |
five identical requests against both layouts, plus the loan feature's three requests |