In 2014, refactoring means the using of menu options in a JetBrains IDE (or similar) to change code. It also means you should be brave and safe in respect of a codebase, with commits that introduce no functional changes. Dragging source files using WindowsExplorer isn’t refactoring, as it requires a bunch of follow up work in your IDE to make it all work again. If you can’t commit immediately after that drag operation, it is not refactoring, it’s the first step into a rewrite. If it is not clear yet, rewrites are not the same thing as refactorings.
Instead, you should do a bunch of “move” centric refactorings with Intellij (or one of the other IDEs for the other languages). You get to rely on a fully context-aware way of moving code, which is immensely valuable. You couldn’t be further from the old cut/paste technique.
WebLogic to Tomcat Services Example
I was recently asked how to refactor services out of a legacy WebLogic application. Here is that plan :)
The case we are going to model is the a large legacy EAR file solution in a WebLogic. For what ever reason, the company in question wants to break it up, into many smaller services. Instead of doing it all on a branch, and merging that back later, we can do it safely within the trunk, if we’re prepared to follow a very strict choreography or set of rules. Here is the before and after.
Assume the source folder for the legacy jar/war/ear is <trunk>/src, and that a Maven-style modular build is where you want to head to.
The First step is to move that to <trunk>/legacy/src and commit that. You’ll probably have to notify everyone that you’re going to do that, as they need to time commits so that least merge pain is encountered after that.
The next step is to create <trunk>/first/src and <trunk>/second/src and <trunk>/third/src (these are just contrived names). Create Maven pom.xml files for each of those (even though source is missing), and have them listed as modules in a new parent pom. Commit, obviously. Make sure that jar build but the first module is listed as a dependency for A and C.
The tricky part.
(remember: lots of little commits will give you rollback safety)
Next, in the IDE, start working on the actual refactoring. If you use the refactoring menu item “move” exclusively, Intellij is going to warn you that build would be impossible if you attempt move code inappropriately. If it warns, don’t do it, otherwise do it. You prime goal is to move a subset of the service logic from A to B. You may also be wanting to move code from A to C for UI stuff. Note: The way I’ve shown the diagram above is that there is no shared code between B and C, so lets assume that if C uses B at runtime, it is able to handle it’s own marshaling of requests and responses.
If a particular move refactoring would break buildability my moving code A needed to a place it would not be visible in, consider abandoning that refactoring, and focussing on the smallest amount of code that A and C needs and moving it to X (as I have it on the diagram) instead. That’s a pure jar, not a service.
You need to know that you move tests for classes in the same way that you moved production code for classes. If tests are missing, you have an ideal moment to add some. If you have functional tests that confirm that the larger application works, then running them before each commit is your final proof that the refactoring has introduced no functional change. Adding functional tests to do this at the start, is one of the smarter decisions you’d make in this endeavor.
Remember to commit. Repeat this a lot, until there’s nothing more to do.
The rules spelled out
- Refactor menu – Move operation (and similar refactorings) are your friends.
- No commit should prevent the larger application from going live (or break the build in any way)
- Do lots of little commits – notify colleagues as necessary.
- All moves are within the same source-control repo and branch (trunk).
- Concentrate on “most depended on, least depending” first.
I have set techniques that I have published on before – Legacy App Rejuvenation – a method of snipping away at a hairball application methodically while still doing functional work, as the business would wish. A Singleton Escape Plan is worth a read too, as it talks about methodical non-functional migrations.
Source Code Laundering hopefully sells why you need to do all of this in the same branch as regular development (trunk), and not a different branch or different repo (which is worse still).
Danilo Sato demonstrated safe refactoring at high speed in this 14 minute video, which everyone who’s used the term refactoring should watch. I led a day-long “OO Bootcamp and best practices” session at a client last week (twice), and this video was a popular segue from the slideware and discussion, setting the context for a following section – hands-on experimentation with Intellij.
Danio’s video shows him hitting a “blocker”. Something he was bravely attempting, wasn’t going to pay off. He abandoned it, and used source-control to rollback to a safe place. Because he had been committing little and often, the abandonment of that change (that rollback effected), was not costly.
If you were not doing services as such, but were heading towards a non SOA replacement using pure components in, say, a SpringFramework solution, it would be exactly the same series or steps and rules.