Backend Development 30 min read

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.

macrozheng
macrozheng
macrozheng
50+ Proven Tips to Slash Bugs in Your Backend Development

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

<code>`name` varchar(255) DEFAULT NOT NULL</code>

Validate 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

<code>public class TransactionTest{<br/>  public void A(){ B(); }<br/>  @Transactional<br/>  public void B(){ /* insert */ }<br/>}</code>

Direct calls bypass the proxy, causing transaction loss.

1.3.3 Swallowed Exceptions

<code>@Transactional<br/>public void method(){<br/>  try{ /* insert */ }catch(Exception e){ logger.error("exception caught", e); }<br/>}</code>

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.

<code>select id,name from employee where id>1000000 limit 10;</code>
<code>SELECT a.* FROM employee a, (select id from employee where ... limit 1000000,10) b where a.id=b.id;</code>

1.7.2 Batch Operations

Prefer batch inserts/updates (e.g., 500 rows per batch) over single‑row loops.

<code>remoteBatchQuery(param);</code>
<code>for(int i=0;i<100000;i++){ remoteSingleQuery(param); }</code>

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

<code>if(object!=null){ String name = object.getName(); }</code>

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

<code>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));</code>

Using

YYYY

yields 2020‑12‑31; prefer

yyyy

.

<code>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/>}</code>

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

<code>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); }</code>

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.

<code>if(deleteAvailableTicketById(ticketId) == 1){ /* proceed */ } else { return "No ticket"; }</code>

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

<code>// Old interface<br/>void oldService(A,B){ newService(A,B,null); }<br/><br/>// New interface<br/>void newService(A,B,C);</code>

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 →

string

Conclusion

This article summarizes more than fifty coding and architectural best practices to help developers reduce bugs and improve system reliability.

Backend DevelopmentDatabase Optimizationcode qualitycache strategybug reduction
macrozheng
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.