50+ Proven Tips to Slash Bugs in Your Backend Development
This article compiles over fifty practical tips covering database design, code practices, and cache usage to help developers dramatically reduce bugs, improve reliability, and boost overall software quality in everyday backend projects.
Introduction
Today we discuss how to reduce bugs in daily development, summarizing more than 50 practical points across three major areas: database, code, and cache usage.
1. Database Section
Key areas prone to bugs: slow queries, field considerations, transaction failures, deadlocks, master‑slave delay, data compatibility, classic SQL pitfalls.
1.1 Slow Queries
1.1.1 Index Hit
Queries without indexes or that fail to hit indexes cause slow performance. Indexes may become ineffective when:
Query conditions contain OR String fields are not quoted
Using LIKE with wildcards
Composite index columns are not in the leading position
Applying MySQL functions on indexed columns
Performing arithmetic on indexed columns
Using !=, <>, or NOT IN on indexed fields
Testing for NULL or NOT NULL Mismatched character sets in joins
MySQL optimizer prefers full table scan
1.1.2 Large Data Sets – Sharding
When a single table exceeds ~20 million rows (B‑tree height grows), performance degrades; consider sharding with middleware such as mycat or sharding-jdbc.
1.1.3 Unreasonable SQL
Avoid excessive joins (e.g., six tables) and too many indexes (more than five per table) as they hurt insert/update performance.
1.2 Field Considerations
1.2.1 Length Overflow
`name` varchar(255) DEFAULT NOT NULLValidate input length to prevent overflow errors.
1.2.2 Nullability
Prefer NOT NULL with sensible defaults (0 or -1 for integers, empty string for text) to avoid null‑pointer issues.
1.2.3 Missing Fields
Ensure schema changes in testing are propagated to production scripts.
1.2.4 Emoji Support
Use utf8mb4 for columns that need to store emojis.
1.2.5 Text/Blob Caution
Store file paths instead of full files; use prefix indexes for large TEXT columns.
1.3 Transaction Pitfalls
1.3.1 @Transactional on non‑public methods
Spring AOP proxies ignore non‑public methods, so transactions won’t apply.
1.3.2 Self‑invocation
public class TransactionTest{<br/> public void A(){ B(); }<br/> @Transactional<br/> public void B(){ /* insert */ }<br/>}Direct calls bypass the proxy, causing transaction loss.
1.3.3 Swallowed Exceptions
@Transactional<br/>public void method(){<br/> try{ /* insert */ }catch(Exception e){ logger.error("exception caught", e); }<br/>}Catching exceptions without rethrowing prevents rollback.
1.3.4 rollbackFor Misuse
Spring rolls back only unchecked exceptions by default; specify rollbackFor for checked ones.
1.3.5 Engine Support
MyISAM does not support transactions; use InnoDB.
1.3.6 Thread Context
Transactional code must run in the same thread as the Spring proxy.
1.4 Deadlocks
Deadlocks occur when multiple transactions hold locks the other needs, reducing resource utilization.
1.4.1 Lock Scenarios
Primary key + RC
Unique secondary index + RC
Non‑unique secondary index + RC
No index + RC
Primary key + RR
Unique secondary index + RR
Non‑unique secondary index + RR
No index + RR
Serializable
1.4.2 Analysis Steps
Simulate deadlock
Run SHOW ENGINE INNODB STATUS Identify offending SQL
Analyze lock types
Review lock compatibility matrix
1.5 Master‑Slave Delay
Read‑after‑write may miss recent data if the slave lags; use the master for strong consistency or accept eventual consistency for less critical reads.
1.6 Data Compatibility
When adding new columns, define default values for existing rows; handle nulls carefully to avoid NPEs.
1.7 Classic SQL Tips
1.7.1 Large Pagination
Three solutions: use incremental IDs, limit page numbers, or employ sub‑queries to fetch IDs first.
select id,name from employee where id>1000000 limit 10; SELECT a.* FROM employee a, (select id from employee where ... limit 1000000,10) b where a.id=b.id;1.7.2 Batch Operations
Prefer batch inserts/updates (e.g., 500 rows per batch) over single‑row loops.
remoteBatchQuery(param); for(int i=0;i<100000;i++){ remoteSingleQuery(param); }2. Code Layer
2.1 Coding Details
2.1.1 Six Typical Null‑Pointer Issues
Wrapper type nulls
Chained calls
Equals left‑hand null
ConcurrentHashMap does not allow null keys/values
Direct array/collection access
Direct field access
if(object!=null){ String name = object.getName(); }2.1.2 Thread‑Pool Usage
Avoid Executors.newFixedThreadPool (unbounded queue may OOM)
Use custom pools with clear naming
Isolate pools per business domain
Handle pool exceptions properly
2.1.3 Linear‑Safety Collections
Use thread‑safe structures like ConcurrentHashMap instead of HashMap in high‑concurrency scenarios.
Non‑thread‑safe: HashMap, ArrayList, LinkedList, TreeMap
Thread‑safe: Vector, Hashtable, ConcurrentHashMap
2.1.4 Date/Amount Precision
Calendar calendar = Calendar.getInstance();<br/>calendar.set(2019, Calendar.DECEMBER, 31);<br/>Date testDate = calendar.getTime();<br/>SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd");<br/>System.out.println(dtf.format(testDate));Using YYYY yields 2020‑12‑31; prefer yyyy.
public class DoubleTest {<br/> public static void main(String[] args){<br/> System.out.println(0.1+0.2);<br/> System.out.println(1.0-0.8);<br/> System.out.println(4.015*100);<br/> System.out.println(123.3/100);<br/> double amount1 = 3.15;<br/> double amount2 = 2.10;<br/> if(amount1 - amount2 == 1.05){ System.out.println("OK"); }<br/> }<br/>}2.1.5 Large File Handling
Avoid Files.readAllBytes for big files; use BufferedReader line‑by‑line or NIO channels.
2.1.6 Resource Closing
try (FileInputStream inputStream = new FileInputStream(new File("jay.txt"))) {<br/> // use resources<br/>} catch (FileNotFoundException e) { log.error(e); } catch (IOException e) { log.error(e); }2.1.7 Exception Handling Pitfalls
Avoid e.printStackTrace() Log exceptions appropriately
Do not catch generic Exception for everything
Never use exception handling as business logic
2.1.8 Concurrency Consistency (Check‑then‑Update)
Replace separate check‑then‑update with atomic DB update/delete to avoid race conditions.
if(deleteAvailableTicketById(ticketId) == 1){ /* proceed */ } else { return "No ticket"; }2.2 External Interface Design
2.2.1 Parameter Validation
Validate length, format, and range before persisting to prevent DB errors.
2.2.2 Backward Compatibility
// Old interface<br/>void oldService(A,B){ newService(A,B,null); }<br/><br/>// New interface<br/>void newService(A,B,C);2.2.3 Rate Limiting
Use Guava RateLimiter or Alibaba Sentinel to protect services from traffic spikes.
2.2.4 Security (Signing & Auth)
Critical APIs (e.g., transfers) must enforce authentication, signing, and verification.
2.2.5 Idempotency
Design APIs to be idempotent—use unique keys, tokens, database constraints, or distributed locks (Redis, Zookeeper) to prevent duplicate processing.
2.3 Third‑Party Calls
2.3.1 Timeout Handling
On remote call timeout, avoid updating local state; instead, query the remote system later to confirm outcome.
2.3.2 Retry Mechanism
Implement retries for transient failures, respecting idempotency.
2.3.3 Degradation Strategy
If a non‑essential downstream service fails (e.g., email), degrade gracefully—complete the primary flow and handle the optional step asynchronously.
2.3.4 Asynchronous Processing
Offload notification calls (SMS, email) to async threads to improve response time.
2.3.5 Exception Handling for Remote Calls
Define clear fallback logic, decide between retry or failure, and ensure eventual consistency.
3. Cache Section
3.1 Database‑Cache Consistency
3.1.1 Cache Patterns
Cache‑Aside (read‑through/write‑through)
Read‑Through/Write‑Through
Write‑Behind (asynchronous)
Most systems use Cache‑Aside: read cache first, fall back to DB on miss, then populate cache.
3.1.2 Delete vs Update Cache
Deleting stale cache entries avoids dirty reads compared to directly updating cache after DB writes.
3.1.3 Order of Operations
In Cache‑Aside, always write to the DB first, then delete or update the cache to prevent stale reads.
3.1.4 Ensuring Final Consistency
Cache‑aside double delete with delay
Retry deletion
Asynchronous log‑driven cache eviction
3.2 Cache Penetration
Cache penetration occurs when requests for non‑existent keys repeatedly miss the cache and hit the DB, causing unnecessary load.
Mitigation:
Validate request parameters at API entry
Cache empty results with short TTL
Use Bloom filters to pre‑check existence
3.3 Cache Avalanche
Cache avalanche happens when many keys expire simultaneously, flooding the DB.
Mitigation: stagger TTLs (e.g., base + random offset) and ensure Redis high‑availability.
3.4 Cache Breakdown (Hot‑Key Miss)
When a hot key expires, a burst of concurrent requests may bypass the cache and overload the DB.
Solutions:
Mutex lock (e.g., Redis SETNX) to allow only one thread to rebuild the cache
Never‑expire hot data and refresh asynchronously
3.5 Hot Key Handling
Scale Redis clusters, hash‑shard hot keys, or add a local JVM cache to distribute load.
3.6 Memory & Eviction
3.6.1 Capacity Planning
Cache only frequently accessed data; monitor memory usage to avoid OOM.
3.6.2 Redis Eviction Policies
volatile‑lru / allkeys‑lru volatile‑lfu / allkeys‑lfu volatile‑random / allkeys‑random volatile‑ttl noeviction
3.6.3 Data Structure Choice
Leaderboard → zset User info → hash Message queue / article list → list Tags / social sets → set Counters / locks →
stringConclusion
This article summarizes more than fifty coding and architectural best practices to help developers reduce bugs and improve system reliability.
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.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.
