Write Maintainable, High‑Performance Backend Code: Standards, Design Patterns & Optimization Tips
This article presents a comprehensive guide to building maintainable, extensible backend systems by covering coding conventions, branch naming, commit messages, comment standards, result‑wrapping patterns, database normalization, algorithmic improvements, concurrency handling, service layering, and practical code examples.
1. Introduction
Most developers face pressure to deliver features quickly, often sacrificing refactoring and resulting in code that is hard to maintain, extend, or hand over. Maintaining readability, extensibility, and good hand‑off characteristics is essential for long‑term project health.
2. Code Optimization
2.1 Commit Conventions
# Submit: main types
feat: add new feature
fix: fix bug
# Special types
docs: documentation only
style: formatting changes (spaces, indent, semicolons)
build: build tool or external dependency changes
refactor: code refactoring
revert: git revert message
test: add/modify tests
perf: performance improvements
ci: CI related changes
chore: other changes (build process, tools)2.2 Branch Naming
Use a clear pattern such as date_user_purpose (e.g., 210905_xfg_updateRuleLogic) to indicate the branch purpose.
2.3 Commit Message Format
Include author and type, e.g., 小傅哥, fix: 更新规则逻辑问题, following the Commit Message specification.
2.4 Comment Standards
Configure class header templates in IDEs (e.g., IDEA P3C plugin) using a format like:
/**
* @description:
* @author: ${USER}
* @date: ${DATE}
*/2.5 Interface Standard
When designing RPC interfaces, always return a clear Code and Info so callers can determine success or failure.
2.6 Result Wrappers
public class Result implements java.io.Serializable {
private static final long serialVersionUID = 752386055478765987L;
/** return code */
private String code;
/** return info */
private String info;
public Result() {}
public Result(String code, String info) { this.code = code; this.info = info; }
public static Result buildSuccessResult() {
Result r = new Result();
r.setCode(Constants.ResponseCode.SUCCESS.getCode());
r.setInfo(Constants.ResponseCode.SUCCESS.getInfo());
return r;
}
// getters & setters omitted
}
public class RuleResult extends Result {
private String ruleId;
private String ruleDesc;
public RuleResult(String code, String info) { super(code, info); }
// getters & setters omitted
}
public class ResultData<T> implements Serializable {
private Result result;
private T data;
public ResultData(Result result, T data) { this.result = result; this.data = data; }
// getters & setters omitted
}Both wrapper styles allow callers to uniformly check Code and handle responses.
3. Database Design
Follow the first three normal forms (1NF, 2NF, 3NF) to avoid redundant fields, ensure atomic columns, and keep each table focused on a single entity. Over‑normalization beyond 3NF often adds unnecessary constraints.
4. Algorithm Logic
For high‑concurrency scenarios (e.g., flash‑sale), avoid global locks and instead use segmented static locks (activity‑ID + stock‑ID) so failed locks do not block subsequent users. Workers can compensate failed locks to prevent overselling.
4.1 HashMap Performance Pitfall
@Test
public void test_idx_hashMap() {
Map<String, String> map = new HashMap<>(64);
map.put("alderney", "未实现服务");
// ... other keys ...
map.put("insincere", "已实现服务");
long start = System.currentTimeMillis();
for (int i = 0; i < 100_000_000; i++) {
map.get("insincere");
}
System.out.println("耗时(initialCapacity):" + (System.currentTimeMillis() - start));
}The test demonstrates how deliberately colliding keys can degrade O(1) look‑ups to O(n) by forcing all entries into the same bucket.
5. Responsibility Separation
Use design patterns (template method, interface + abstract class) to isolate configuration, validation, and business logic, enabling flexible extensions without breaking existing contracts.
public interface IRuleExec { void doRuleExec(String req); }
public class RuleConfig { protected Map<String,String> configGroup = new ConcurrentHashMap<>(); }
public abstract class AbstractRuleBase extends RuleConfig implements IRuleExec {
@Override
public void doRuleExec(String req) {
String ruleConfig = super.queryRuleConfig("10001");
checkRuleConfig(ruleConfig);
doLogic(configGroup.get(ruleConfig));
}
protected abstract void doLogic(String req);
private void checkRuleConfig(String rc) { /* validation */ }
}
public class RuleExec extends AbstractRuleBase {
@Override
protected void doLogic(String req) { /* business logic */ }
}6. Logical Rigor & Incident Prevention
Common production incidents stem from database slow queries, service timeouts, missing idempotency, and race conditions. Example: a flash‑sale RPC call succeeds but times out, leading to duplicate point deductions. Introducing idempotent request IDs and compensating tasks mitigates such issues.
7. Domain Aggregation
Applying DDD concepts—event storming, domain models, and bounded contexts—helps separate business concerns, avoid monolithic “mudball” services, and build highly reusable, composable components.
8. Service Layering
Separate technical components, domain services, and business orchestration into distinct layers. This enables independent evolution of each layer and easier composition of new features.
9. Concurrency Optimization
Leverage distributed techniques—message queues, async processing, Redis caching, sharding, and distributed transactions—to avoid centralized bottlenecks and maintain high throughput under load.
10. Source‑Code Mastery
Understanding core Java mechanisms (HashMap bucket + linked list/red‑black tree, AOP, Spring dynamic data‑source routing, MyBatis integration) empowers developers to solve real‑world performance and scalability problems.
@Around("aopPoint() && @annotation(dbRouter)")
public Object doRouter(ProceedingJoinPoint jp, DBRouter dbRouter) throws Throwable {
String dbKey = dbRouter.key();
if (StringUtils.isBlank(dbKey)) throw new RuntimeException("annotation DBRouter key is null!");
String dbKeyAttr = getAttrValue(dbKey, jp.getArgs());
int size = dbRouterConfig.getDbCount() * dbRouterConfig.getTbCount();
int idx = (size - 1) & (dbKeyAttr.hashCode() ^ (dbKeyAttr.hashCode() >>> 16));
int dbIdx = idx / dbRouterConfig.getTbCount() + 1;
int tbIdx = idx - dbRouterConfig.getTbCount() * (dbIdx - 1);
DBContextHolder.setDBKey(String.format("%02d", dbIdx));
DBContextHolder.setTBKey(String.format("%02d", tbIdx));
logger.info("数据库路由 method:{} dbIdx:{} tbIdx:{}", getMethod(jp).getName(), dbIdx, tbIdx);
try { return jp.proceed(); }
finally { DBContextHolder.clearDBKey(); DBContextHolder.clearTBKey(); }
}3. Summary
Rewriting tangled code is rarely feasible; instead, adopt incremental refactoring, clear layering, and design patterns to keep the codebase healthy.
Every new feature or bug fix should be an opportunity to improve structure, naming, and modularity.
Study design patterns and Spring internals to deepen your ability to craft maintainable, extensible backend systems.
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.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
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.
