Best Practices for Developing Scalable, High‑Performance Backend Services
This article outlines essential principles for building extensible, high‑performance online services, covering interface design, coding standards, caching strategies, and logging practices to reduce bugs and simplify development and maintenance.
Online service programs require extensibility and high performance; following certain guidelines reduces the likelihood of bugs and makes development and maintenance easier. This article discusses development principles for server programs from interface design, coding, cache usage, to log printing.
Interface Design
Avoid using generic types such as Map<String, Object> for parameters and return values to improve readability and extensibility.
Avoid ambiguous return values; distinguish between null for "not found" and null for errors.
Do not use void or Boolean as return types when future requirements may need richer information.
Prefer wrapper types like Integer over primitive types to allow a null value indicating an omitted parameter.
Use enums instead of constant integers to enforce type safety at compile time.
Adopt an elegant return pattern, e.g., returning a RpcResult object that contains the actual value.
Do not change the signature of already published interfaces; deprecate old ones instead of deleting them.
Coding Implementation
Never trust the caller; always validate input parameters and guard against SQL injection and XSS attacks.
Check all return values and handle error cases explicitly.
Limit the number of items in batch interfaces and paginate results for large data sets.
Avoid circular service calls; provide batch interfaces to reduce pressure.
Set timeout values for all network calls to prevent resource exhaustion.
Process non‑critical steps asynchronously (e.g., token updates, cache refreshes) using thread pools or message queues; prefer MQ for durability.
Minimize creation of temporary objects; use StringBuilder instead of string concatenation in loops.
Do not create thread pools inside service interfaces; manage them at a higher level.
Choose appropriate data structures and only use thread‑safe collections when necessary.
Synchronize access to shared resources, using distributed locks in a distributed environment.
When comparing with constants, place the constant on the right side to avoid NullPointerException .
Avoid strong dependencies on non‑critical path steps; allow those steps to fail without breaking the main flow.
Prevent circular dependencies between services to avoid cascading performance degradation.
Cache Usage
Set expiration times for cached data to avoid stale data and uncontrolled cache growth.
Treat cache as a weak dependency: the system should continue to function by fetching from the data source if the cache fails, and configure read/write timeouts.
Monitor cache hit rates; low hit rates can introduce overhead that outweighs benefits.
Measure cache response times and log unusually long latencies for further analysis.
Log Printing
Use asynchronous logging to reduce performance impact.
Avoid logging meaningless information.
Include a unique request ID in every log entry.
Log at least one entry on critical paths.
Log an entry whenever an error occurs.
Ensure logs contain key information needed for troubleshooting.
Do not mix log levels arbitrarily; keep level usage consistent.
Author Biography
Yang Yonggang – Head of ZuanZuan basic services, specializing in high concurrency and network programming.
Zhuanzhuan Tech
A platform for Zhuanzhuan R&D and industry peers to learn and exchange technology, regularly sharing frontline experience and cutting‑edge topics. We welcome practical discussions and sharing; contact waterystone with any questions.
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.