Working with legacy software often means dealing with performance bottlenecks that weren’t an issue when the system was first built. Over time, usage grows, data accumulates, and what was once an acceptable response time can become a serious problem. Sometimes, these issues arise due to overlooked inefficiencies or outdated dependencies that no one thought to revisit. Recently, we uncovered hidden legacy system performance opportunities in OpenLMIS, achieving an impressive 98% improvement thanks to a simple update.
The performance bottleneck
While working with OpenLMIS OSS, we encountered a painfully slow operation: saving around 100 records of a simple entity (UUID and Long) was taking over 30 seconds. The save method itself was part of Spring’s CrudRepository, with no custom logic, no pre-save listeners, and nothing in the entity that should have caused such a delay. Yet, the slowdown occurred before the transaction even completed, suggesting that something was happening before the actual database write.
Debugging beyond the obvious
At this point, knowing that Spring supports aspect-oriented programming (AOP) is key. Third-party libraries can hook into repository methods without making it obvious—these behaviors don’t show up in code reviews, and many IDEs won’t highlight them.
Proper debugging was the way forward. Instead of relying on step-over debugging, we stepped into the repository save method, following the execution flow through Spring’s layers. That’s when we hit the culprit:
Javers Auditing.
This library was generating and executing SQL audit records, turning a simple insert operation into a massive overhead.
The power of a simple upgrade
Finding that a widely used library was causing such extreme slowdown was surprising. Was it a configuration issue? Or were we simply running an outdated version?
A quick check revealed that we were using Javers 2.8.2—a version from the early 2010s! Digging into the changelog, we found a particularly interesting note in version 3.14.0:
“Performance of JaVers commits with SQL repo is significantly better…”
Several later versions also mentioned improvements in SQL generation. We picked a stable, modern version that wouldn’t introduce breaking changes, ran our tests, and the results were staggering:
Single dependency update
98% improvement
30 seconds → <500ms
Takeaways: Don’t let legacy stay stagnant
This experience was a reminder that legacy doesn’t have to mean slow. Software libraries evolve, and performance optimizations happen all the time. But if we don’t actively track and update dependencies, we miss out on these improvements.
For teams maintaining legacy system performance, having a structured process for regularly reviewing third-party dependencies—not just for security but also for performance—can prevent these kinds of hidden bottlenecks.
Sometimes, the biggest performance gains don’t come from complex optimizations, but from simply keeping up with the times.