CASE STUDY ยท FINANCIAL SERVICES
How custom Java packages helped an asset management firm reduce build failures and cut dependency risk.
- 87%Dependency-related build failures reduction*
- 96%Release cycle speed, QA โ Production faster*
01 ยท PROJECT OVERVIEW
When every service solves the same problem twice.
The client runs enterprise financial applications on a Java microservices estate. Each service had grown on its own timeline, with its own dependency versions and its own private copies of logic that half the other services also needed.
Nothing was broken enough to stop the business. But everything was slow enough to cost it. A library upgrade in one service could quietly break another. Shared utilities lived in three places and drifted apart. Engineers spent more of the sprint negotiating with the build than writing features.
Brandsmashers was brought in as an embedded Java developer inside the client's delivery team not to rebuild the platform, but to make the platform safe to change.
- 1Dependency versions drifting across services with no shared baseline.
- 2Reusable logic copy-pasted between codebases instead of shared.
- 3Upgrades postponed because nobody could predict what they would break.
- 4Build failures that surfaced late in the CI/CD pipeline rather than early.
02 ยท THE CHALLENGE
Upgrading without breaking anything downstream.
The hardest problem on the engagement was deceptively plain: move dependencies forward without disturbing services that already worked.
Newer library versions brought API changes. Those API changes pulled transitive dependencies behind them. And in a microservices estate, a transitive conflict rarely announces itself in the service you just edited it shows up two services over, in an environment where it is expensive to find.
- PROBLEM 01API drift
Method signatures and behaviour changed between versions, breaking compiling code silently at runtime.
- PROBLEM 02Transitive conflicts
Two libraries pulling incompatible versions of a third, resolved differently per service.
- PROBLEM 03Duplicate logic
The same utility maintained separately in multiple services, each with its own bugs.
- PROBLEM 04Late feedback
Problems reached CI/CD or QA instead of being caught at analysis time.
The technical debt wasn't in the code anyone was writing. It was in the code nobody wanted to touch.
03 ยท THE PROCESS
Analysis first, then libraries, then a repeatable path to production.
- 01Mapped the dependency tree before changing a line
Every upgrade started as an analysis task, not a code task. Our engineer walked the dependency tree service by service, identified where versions conflicted, and flagged which APIs had actually changed behaviour rather than just version numbers.
- 02Upgraded and reconciled versions across services
Dependencies were moved to newer, mutually compatible versions. Where an upgrade forced an API change, the affected code was updated in the same pass so the service never sat in a half-migrated state.
- 03Built custom Java libraries for shared functionality
Logic that had been duplicated across services was pulled out into purpose-built internal libraries. One implementation, one owner, one place to fix a bug.
- 04Packaged and published to the internal artifact repository
Libraries were built into versioned JAR artifacts and published to the client's internal artifact repository, so consuming services could pin a known version.
- 05Integrated, tested, and validated the full build
Each package was integrated into consuming services and put through unit and integration testing, with regression testing and full build validation after any dependency change.
- 06Supported CI/CD and shepherded releases through to Production
Build failures in the pipeline were triaged and resolved, and services/packages were deployed across QA, UAT, and Production on a controlled, repeatable path.
- 1โRequirement
- 2โJava service development
- 3โDependency analysis
- 4โCustom library build
- 5โUnit testing
- 6โJAR packaging
- 7โArtifact repository
- 8โService integration
- 9โCI/CD pipeline
- 10QA โ UAT โ Production
04 ยท RESULTS
What changed.
The estate became safe to upgrade. Shared functionality got a single home. And moving a change from a developer's branch to Production stopped being an act of faith.
| BEFORE | AFTER |
|---|---|
| Dependency versions drifting service by service | Reconciled, compatible versions across the estate |
| Reusable logic duplicated in multiple codebases | Shared custom libraries with one owner and one version |
| Upgrades deferred because the blast radius was unknown | Dependency analysis and regression testing before every change |
| Build failures surfacing late in CI/CD | Failures triaged and resolved as part of the delivery loop |
| Ad-hoc deployment across environments | Controlled QA โ UAT โ Production release process |
- Lower technical debt
Dependency-related debt was paid down instead of accumulating quietly.
- Higher maintainability
Services became easier to change because their foundations stopped moving underneath them.
- Genuine reuse
Custom packages gave the team a way to write something once and use it everywhere.
- A process, not a heroic effort
Building, publishing, and deploying packages became a repeatable path any engineer could follow.
05 ยท DELIVERABLES
What we delivered.
- Microservice developmentOngoing development and enhancement of multiple Java services.
- Dependency engineeringVersion upgrades, conflict resolution, and compatibility analysis.
- Custom Java librariesReusable internal packages replacing duplicated logic.
- Artifact managementJAR builds published to the internal artifact repository.
- Testing & validationUnit, integration, and regression testing after every change.
- Release supportCI/CD build support and deployment across QA, UAT, and Production.
- Language / Architecture
- JavaMicroservices
- Build
- Maven / Gradle
- Packaging
- JAR PackagingArtifact Repository
- Delivery
- CI/CD
- Quality
- Unit & Integration Testing
- Environments
- QAUATProduction
WHY IT WORKED
One engineer, embedded, with ownership.
This wasn't a project handed over a wall. Brandsmashers placed a Java developer inside the client's team through our IT staff augmentation model close enough to the codebase to see where the real friction was, and accountable enough to fix it end to end, from dependency analysis through to a Production deployment.
That's the pattern we see work most often with engineering-heavy clients: hire capability, not headcount, and let it compound. The custom package layer built here keeps paying off every time a new service needs functionality that already exists.
YOUR TURN
Have services that are hard to change safely?
Brandsmashers Tech embeds engineers who untangle dependencies and make shared code safe to reuse.