Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Java Legacy Hairball: Refactoring Case Study

DZone's Guide to

Java Legacy Hairball: Refactoring Case Study

Ten years ago, I led a team for a banking client to rejuvenate their FX-trading platform. One aspect of that mission was to snip away at the existing singleton-laden solution in order to make a cleaner and more unit-testable. Check out this slide deck from back then used to convince the client to start the rejuvenation work.

· Java Zone
Free Resource

Try Okta to add social login, MFA, and OpenID Connect support to your Java app in minutes. Create a free developer account today and never build auth again.

Ten years ago, I led a team for a banking client to rejuvenate their FX-trading platform. One aspect of that mission was to snip away at the existing singleton-laden solution in order to make a cleaner and more unit-testable. I’ve written the case-study for this methodical (and pausable) decomposition project over a few prior articles:

From the 2008 article—the one that introduced Most Depended-on and least depending component as a strategy—an attempt to find a visual metaphor for entanglement/disentanglement:

Today though, a slide deck from back then used to convince the client to start the rejuvenation work. 

Note: for the sake of this article ‘singleton’ is the Gang of Four pattern, not the Spring/Guice idiom.

Eleven Slides Showing the First Refactoring

Architecture as Described by the Client:

Image title

The Starting Point Was the Logical Business Tier:

Image title

It Turns Out, It Was Not as Decomposed as Hoped for:

Image title

Make Room in the Diagram for More Boxes:

Image title

Introduce Service Locator and a Place for Refactored Components:

Image title

Identify the **Most Depended on, and Least Depending**, Component:

Image title

Move It to New Codebase (Make Sure Its Unit Tests Come Too and Rejuvenate Those):

Image title

In Old Codebase, Two Depending Components Now Look-up the New Component via the Service Locator. Part New and Part Old, the App/Service Should Go Live at This Point:

Image title

Identify Another Component to Move (Most Depended-on and Least Depending):

Image title

Move It as Before. This Time With a Pre-Existing Dependency (via Service Locator):

Image title

In the Old Codebase, Add One More Looks-up to the New Component (via the Service Locator). Repeat the Last Three Steps Until There Are No Singletons Left:

Image title

A Methodical Nature to This

The refactoring effort could pause at any stage (as there are higher priorities for the dev team), or carry on methodically with other business priorities. Indeed, the app/service going live at a certain cadence perhaps should be part new functionality and part refactoring. To get there, you really want to be doing Trunk Based Development, and perhaps even Continuous Delivery. If this work is being done on a separate branch, with the promise of a merge back later (and a go live), there is an increasing risk of the business halting the initiative, perhaps irrevocably with career-impacting consequences.

The Project Back in 2006?

We were concurrently migrating from multi-branch ClearCase to single Trunk Perforce. Components were being shaped up first in ClearCase, and removed as they were being put in the Perforce trunk in a hierarchical source tree and build (Maven style, but in Ant). Things from ClearCase that needed components now in Perforce found them in ‘binary repo’ (WebDav then, but like Sonatype’s Nexus or Artifactory). Gradually, components (and their tests) migrated out of ClearCase and into the Perforce Trunk with a hierarchical build. CruiseControl (a precursor to Jenkins, etc.) had a build that would create the binary artifacts in the repo, as well as use them in builds. That CI pipeline would be triggered by commits to one of two SCMs and well as binaries being replaced in the binary repo.

All the while, teams that were not focussing an iteration on the migration would carry on with business functionality. The sum of the business functionality and the refactoring was put live in the same release, on an unchanged (or bettered) cadence. The business never knew the refactoring was going on, or that test coverage was increasing.

The guiding principal was to attack the “Most Depended-on and least depending component” only. Each time that was achieved, there’d be a new candidate for that in the hairball.

A couple of years later, at Google, I worked with Angular-creator Misko Hevery’s intern (David Rubel) on the Google Singleton Detector. This helps easily visually identify most Depended-on and least depending component for future initiatives. Helped, perhaps, it might not work with Java 8/9 anymore.

After All the Singletons Are Gone, What Next?

Go to dependency injection, of course. You would do this in a second series of refactorings and stop when there nothing using the service locator any more. The latter has to go still, as it facilitates undesirable static mutable state.

Danilo Sato shows you how with Intellij IDEA, in this super impressive video:

Ref: Refactoring Experiment on Vimeo.


Danilo does one refactoring at a time pushing service-locator lookups up to the constructor, then into the constructor’s parameters, and finally towards the startup class that composes the solution.

Danilo’s blog entry that accompanies the video: Refactoring Strategies: a walkthrough experiment.

Build and launch faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
trunk based development ,perforce ,codebase ,refactoring ,clearcase ,singleton ,continuous delivery ,legacy app

Published at DZone with permission of Paul Hammant, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}