Do Service Layers Need Interfaces? A Critical Discussion on Spring‑Based Projects
The article examines whether a Service layer in a Spring‑based backend should be defined by interfaces, debunks common arguments for using interfaces, proposes a top‑down coding workflow, explores project structures for single and multiple implementations, and concludes that interfaces are only worthwhile when multiple implementations are required, while also containing promotional material for unrelated services.
In this article the author, a senior architect, questions the necessity of defining interfaces for the Service layer in typical Spring‑based backend projects.
Reasons Some People Say Interfaces Are Needed
Allows upper‑layer code (e.g., Controllers) to be written before the Service logic is implemented.
Spring’s default AOP uses dynamic proxies, which require interfaces.
Enables multiple implementations of a Service.
The author argues that all three reasons are weak:
1. The first reason only helps when different teams work on separate modules; most projects are organized by feature, so adding interfaces adds unnecessary work.
2. Spring can use CGLIB proxies, which do not require interfaces.
3. In practice, multiple Service implementations are rare, and other techniques can replace the need for interfaces.
Suggested Development Workflow Without Interfaces
Write Controller logic first, inserting Service calls as needed.
Use IDE auto‑completion to generate empty Service classes and methods with TODO comments.
After all classes and methods exist, fill in the business logic based on the TODOs.
This approach helps developers understand the business flow without the overhead of interfaces.
Project Structure and Interface Implementation
A typical layered project consists of Controller → Service → Dao. If multiple implementations are required, the structure can be extended with separate packages for interfaces and their implementations, or by adding additional Service modules.
Two ways to handle multiple implementations are presented:
Add a new package under the existing Service package for the new implementation and configure the DI container to inject the desired bean.
Create a completely new Service module (e.g., Service2) with its own implementation package and switch the module dependency.
The first method is simpler, while the second provides clearer module separation.
The author then proposes a hybrid approach: keep the Service interface in its own module, place all implementations (old and new) in separate implementation modules with identical package structures, and let the build configuration select one implementation at packaging time, eliminating the need for the interface module altogether.
Drawbacks of Not Using Interfaces
When multiple implementations are needed, the lack of a strong contract makes IDE assistance and error checking harder, and code duplication may become necessary.
Conclusion
The article concludes that interfaces for the Service layer are only justified when a project truly requires multiple implementations; otherwise, they add unnecessary complexity. The author invites readers to discuss the topic further.
Note: The latter part of the original content contains promotional material for ChatGPT services, private groups, and related offers, which is not part of the technical discussion.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.