RESTIFYING A LEGACY APPLICATION – AN EXPERIENCE
If your developers fear touching the code, then you know you’ve hit the legacy application nightmare. This could be due to lack of test coverage, lack of domain knowledge, outdated technology stack or simply lack of comfort dealing with unknown code base. To me, this is the reality in most successful software applications. As they build new features to adapt to the market needs, they end up accumulating technical debt. Some might be better at paying off the debt, when compared to the rest. But taking on debt is inevitable.
Recently, we (Ashwini Alhat, myself & 2 more developers) started working on a product that was developed around 7 years back. When we looked @ the code base, we were happy to find some JUnit tests. But soon we realized the test cases were outdated and none of them passed. Fixing the tests seemed like a huge task in itself.
The product/application is into Revenue optimization for a particular industry (that’s what we do @ IDeaS :)) ETL is part of our application & it requires daily feeds from the 3rd party application. In order to improve the output from our Revenue Optimization analytics, we decided to enhance the data feeds specifications, for new clients. However we had to support both Specification 1 (earlier specification) & (new) specification 2.
At this stage most of our developers have seen the benefit of automated (unit and acceptance) tests. It was a scary thought for a developer to think about changing legacy code without the safety net of automated tests. However we HAD to change the code to support Specification 2.
2 Layers to start-with
So after discussing with Naresh, we took a more pragmatic approach. We started with a couple of Workflow and Domain Logic acceptance Tests for the existing Specification 1.Advantage of writing these two layers of Tests was that we were confident while touching the code that as long as these Tests for Spec. 1 are passing, we haven’t broken anything significant for Spec. 1.
Now, if we look @ the Workflow test, since they are business facing tests, they should be implementation agnostic. These tests shouldn’t know how the data is stored and retrieved. They should never be tied to the database scheme.
Hence we decided to expose our existing services, as RESTful endpoints that would return the required data to verify. And hence the requirement of “RESTifying our application.”
As most of the people would do, we did the same thing… We googled for some sample codes & we found few… We downloaded the sample project from javacodegeeks and built and ran it. Now, we thought that it’s going be easy to implement the similar thing in our application.
Our legacy application uses Ant scripts to build the project. The first roadblock we hit was trying to identify all the dependent JARs required to make the application RESTful.
The downloaded sample helped us in this case. The sample application was built using Jersey & Jersey-JSON APIs. Also, it was a Maven project and so when we built the .war application out of it, it pulled all the required dependencies (Thanks Maven you were useful here :), sometimes simple logical thinking helps :D).
So with that, we were ready with dependent/required JARs & it’s related infrastructure setup.
We have Struts, Spring, Hibernate & MySql in our application. Struts Action Handlers and middle Service/Manager layers are all Spring Beans (Initialized using IoC).
Like any other standard app, Service/Manager layer would implement the main business logic and Struts handlers would deal with the Request/Response part. So our idea was to RESTify the Manager layer (rest assured that we knew that we need to have good security layer around it) & so we started googling about Jersey-Spring Integration. We are using spring version in 2.5. Yes, it was that old.
We could find many references that talked about Jersey-Spring integration but for the Spring 3.0 version onwards. We were getting little anxious thinking that no-one has ever tried this, but we kept hunting.
In the mvnrepository we could find list of older version of Jersey-Spring integration. Believe me, but we tried all the way up to version 1.0 but it was in vain. It didn’t produce the expected behaviour. It was unable to pull the Spring bean from the application context and so all of it’s dependents beans were NULL. Boo Woooohhh!!!! 😦
Time was running and our attempt to RESTify the application was making no headway. We took a step back and discussed once more.
What’s the key objective?
Is it make our Service/Manager layer REST Enabled or is the intention is to make the application REST enabled by some way. Answer looked fairly simple. We realized that even if we would have found a Jersey-Spring integration out of the box then also, given the fact that we we would expose the REST endpoint (all though to the application), it would require us to push the incoming data validation down to the Service layer (which means, a lot of code change in the service layer).
So we took the approach of introducing a REST End-Point layer. This layer would internally pull the spring bean from the context & then make a call to an appropriate Service/Manager bean to get or PUT the data. This way we could control the data validation @ this layer even before calling the spring bean’s method. This implementation (after setting up the stage) was a no brainer and we could easily implement it for a service/manager. This success opened the gates to many needs.
With this, it was possible for us to write the ` Workflow Test` which was database agnostic. To us, where having Safety Net to the code is the TOP MOST priority (Thanks to Joshua’s key note speech in Agile Pune 2014) it turned out to be great Ship It idea…
We (myself, Ashwini & Naresh), are all excited with this breakthrough.
Though there were many anxious moments during our attempt to RESTify the legacy application, I must say, that the journey to `successfully RESTify a legacy application` was something we ate breathed & drank in those 24 hours…
- We are no more afraid to touch the existing code.
- We have ability to enhance the application and make it AJAX based