Designing Spring controllers that stay boring on purpose
Controllers tempt new teams with quick wins: logic piles up, tests sprawl, and reviewers lose the plot. We coach a rhythm where controllers translate HTTP concerns only, pushing workflows into application services with explicit inputs and outputs. That habit makes diffs easier to scan during busy release weeks.
Naming matters as much as structure. We standardize method prefixes, error handling, and response wrappers so a teammate can jump between repositories without relearning local quirks. The payoff is calmer onboarding when someone joins mid-stream.
Testing follows the same discipline. Slice tests cover the web layer with focused fixtures, while integration tests own database behavior. Students practice failing tests first, then minimal fixes, mirroring how mature teams avoid overfitting mocks.
Finally, we document boundary assumptions beside the code: who may call a route, which headers are required, and how pagination keys behave under concurrency. Those notes become the backbone of cross-org workflow discussions later.