How to Write Clean, Maintainable Backend Code: Layering, Cohesion, and Refactoring Tips
This article explains how backend engineers can achieve clean, readable, and easily maintainable Java code by applying proper layering, minimizing modules, reducing coupling, using design patterns wisely, and refactoring when methods become too long or parameters overly complex.
Editor’s note: The author, a backend engineer at Alipay, shares thoughts on writing clean code.
1. Background
In most business domains, code is divided into business‑oriented and data‑oriented parts, both heavy with business logic. Without good habits and design, code becomes tangled “noodles”. Clean code should be readable, understandable, and easy to modify.
1.1 Definition of Clean Code
Extremely, clean code could mean “no line can be removed”, like a textbook HelloWorld. In real industrial software, complexity and frequent changes require layered structures, abstraction of dependencies, and organized composition.
The goal of a clean structure is layering that:
Satisfies business requirements.
Keeps logic simple and expressive.
Minimizes modules for easier maintenance.
Simplifies configuration to reduce operational cost.
Avoids duplicate code.
Replaces human reasoning with program logic.
1.2 Analogy of Clean Code
Value: easy to read, test, fix, and change. Aim for clean code while considering cost and capability.
Q1: Clean Code vs Simple Code
A1: Clean code means clear logic, structure, and expression, not merely few lines. It often requires thoughtful design.
Q2: Clean Code vs Low‑Code
A2: Clean code is not about the smallest line count. Reasonable layering may add a few lines for models, conversion, validation, etc.
Q3: Clean Code vs Design Patterns
A3: Proper use of design patterns supports maintainability and does not conflict with clean code.
2. Layering Framework
2.1 Class Structure Layering
2.1.1 Standard Layers
Typical stack: RPC/TR/Handler → Service → Manager → DAO
Corresponding models: Info, Model, Config/VO, DO
2.1.2 Basic Principles
Layering abstracts responsibilities. While the standard four‑layer model is a guideline, flexibility is allowed to reduce unnecessary layers, models, or converters.
Key principles:
DO objects are unique to the DAO layer and must not appear in higher layers.
The four‑layer model is not rigid; adjacent layers can be merged when appropriate.
Service and Manager have different granularity; simple services may be merged into Manager.
Use a Repository layer only when data access logic is complex; avoid a Repository that merely forwards to DAO.
3. Practical Cases
3.1 Layer Structure
3.1.1 Uneven Layering
Case code shows RPC layer thin while business layer becomes bloated with ~200 lines.
Recommendations:
Keep RPC as façade; let business layer contain sub‑business modules (e.g., amount handling, voucher processing).
Assemble sub‑modules in the façade.
Place cross‑cutting or generic logic (e.g., activity checks) in the RPC layer.
3.1.2 Redundant / Ineffective Layers
If Service only forwards to Manager, or Repository only forwards to DAO, consider merging those layers.
3.2 Cohesion & Coupling
3.2.1 Overly Long Parameter Lists
private AdmitConfig consultAdmitConfig(String apdId, Date bizDate, String userId,
List<PrizeConfig> prizeConfigByUser,
List<RuleConfig> ruleConfigByUser, Map<String, PrizeConfig> prizeConfigMap,
List<UserEventFlowDO> userEventFlowDOS, UserBenefitFlow recentBenefitFlow,
UserEventFlowDO recentEventFlow, Voucher voucher,
List<VoucherTransferDetail> directVoucherUseDetails,
boolean autoChargeFlag) { ... }Ask whether all parameters are necessary and if the logic can be split.
3.2.2 Misuse of Input/Output Parameters
public Result process(Param param);
public void process(Param param, Result result);Prefer immutable inputs and return results rather than modifying parameters.
3.2.3 Coupling Expansion
Complex conditional logic tied to activity dates should be abstracted to a single “award end” flag.
3.3 Program Flow Branches
3.3.1 Complex Conditional Nesting
if (!alipayEggDowngrade) {
if (!taobaoRedPacketDowngrade || buildingQueryRequest.isForceToQuery()) {
// …
if (mainPageInfo != null) {
// …
if (buildingRedPacket != null) {
// …
}
}
} else {
// …
}
}
if (!taobaoRedPacketDowngrade || buildingQueryRequest.isForceToQuery()) {
// …
}
if (!alipayEggDowngrade && !taobaoRedPacketDowngrade) {
// …
}Reduce nesting, extract sub‑methods, and avoid repeated condition checks.
4. Summary
What
Correct functionality, simple structure, clear logic.
Why
Readability, testability, maintainability, adaptability.
How
Reasonable abstraction and layering, high cohesion, low coupling, think in program logic rather than literal translation.
When to Refactor
Method exceeds ~40 lines.
More than four parameters.
Unit tests become hard to write.
Configuration becomes tangled.
Code feels duplicated (DRY principle).
5. Recommended Reading
Code Complete
Refactoring
Clean Code
Programming Pearls
Effective Java
Java 8 in Action
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alipay Experience Technology
Exploring ultimate user experience and best engineering practices
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.
