Java Backend Nightmares: Async Misuse, Bad Practices, and Lock Bugs
The author inherited a poorly engineered Java backend project riddled with massive methods, missing abstractions, unsafe async handling with Thread.sleep, ineffective @Async annotations, and a broken distributed lock implementation, highlighting how such technical debt creates a maintenance nightmare.
Earlier this year the company optimized some staff, and I recently took over their project.
At first I didn’t take it seriously, but the estimated two‑day development turned into five days of overtime.
The code lacks abstraction, caching, batch processing, proper transactions, and compensation; many methods are 700‑800 lines long, handling uploads, order creation, and other operations synchronously without regard for timeouts.
Most of the business logic is implemented by brute‑forcing directly.
A Closer Look
The coding style and fundamentals are sometimes worse than an intern’s, even though the company hires engineers with over five years of experience.
All code belongs to the company, so it’s blurred.
First, there are console prints left in production code, indicating a lack of cleanup.
Next, a snippet shows that JSONObject already implements Map, making an extra map conversion redundant.
Then comes a puzzling Thread.sleep(300) inside an @Async method.
The sleep is used to wait for the main thread’s transaction to commit so the async method can read the newly inserted data; this is a form of “magical programming” that bets on the transaction finishing within 300 ms.
Another @Async usage is a “fake async”: a method createWxxx is annotated with @Async but is only called from another method within the same class, so Spring’s proxy never intercepts it and the async behavior never occurs.
Finally, the distributed lock implementation is flawed: the lock key and unlock key differ, and the finally block deletes the lock unconditionally, potentially removing a lock held by another process.
if (redis.setNx(xxx)) {
// lock acquired, do something
}
finally {
redis.del(xxx) ???
}These issues, combined with other bad practices like wrapping RPC calls in transactions inside loops, illustrate how a project can become a “shit mountain” that burdens the company and future developers.
Conclusion
Solid fundamentals and a modest pursuit of code quality are more valuable than hiring “rockstar” developers, because most code is written by ordinary engineers and every hidden pit adds up to a massive technical debt.
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.
