Integrating a Legacy Web App with a Modern One: A Tale of Two Apps

Ah, the mid-to-late 90’s. Bill Clinton was president, Nirvana and grunge still ruled the airwaves, and web apps were perfect…Sure. The truth is that there are still a plethora of classic ASP, PHP, Flash, and Java apps still lingering on the modern web. If you’re a company like Airship that does software consulting, you will occasionally run into clients who still have working, complex software with a ton of logic that you couldn’t possibly untangle all at once. The “just rewrite it” approach doesn’t always cut it for medium and large enterprise applications.

I recently ran into this situation with one of our clients who had a classic ASP app built around 1999. The site was still in active development up to last year (2015) when the original developer moved off the project. My task was to build a new feature into the app. As with all legacy systems, over time inertia sets in. Code that was was once small and easy to add to had gotten brittle and difficult to comprehend. To make things worse, I nor any of the team knew much at all about classic ASP. I know ASP.NET and got my start in Visual Basic, but a lot has changed between old school web forms and today’s slick ASP.NET MVC apps. Our team knew that bolting on another feature just wasn’t feasible in the client’s budget or timeline. The risk was too great for breaking something. So we opted for a different approach. I believe this solution is applicable in not just this piece of software, but for any classic web app.

For us, we wanted to accomplish many things:

1. Write all the back-end logic in a modern web technology.
2. Make user interface elements renderable in the newer web technology, but accessible for interaction with the legacy UI components.
3. Use the new web app as a foundation for new features as well as the slow porting of existing features.
4. Store all new code into a modern source code repository.
5. Minimize risk of breaking legacy features.

What’s the solution for all of this? No, it isn’t some fancy new web product I’m going to sell you. It’s the lingua franca of the web: Javascript. It turns out Javascript acts as a pretty sturdy bridge to communicate between different apps. Much like C can be used as a bridge to connect hardware components or system services, Javascript is accepted by pretty much every web framework and web browser out there. Here’s an example of how we were able to integrate two disparate systems using this approach. Note that to protect the nature of our client’s software, I’m going to make up an example of a software that does something similar in nature but is common across any line-of-business web app.

Let’s say a local church in the late 90’s decided to be as cool as Ice Cube and build a site that allows them to manage membership, finances, and sermon materials. Maybe they even have a few front end pages bolted on that serve up static information about their church to those brave few willing to venture the newly built information superhighway. Things were rocking along great for years and the site still serves them well for their business needs. But now it’s 2016 and the young new pastor wants to have as much swagga as Drake. The church has now spread to multiple campuses and they need a new page with some fancy dashboards to show them attendance across campuses. Here’s what they want it to look like:

And here’s what their current “Reports” module looks like in their old site.

legacy

Here’s what the old Reports.asp page might look like:

<h1>Reports</h1>
 
    <form id="frmReports" action="reports.asp">
        <label>Report Type</label>
        <select id="report_type">
            <option value="1">Tithing</option>
            <option value="2">Member List</option>
            <option value="3">Attendance by Campus</option>
        </select>
        <br />
        <label>From Date</label>
        <input type="text" id="frmDate" />
        <br />
        <label>To Date</label>
        <input type="text" id="toDate" />
        <br />
        <input type="submit" value="Run Report" />
    </form>
<div id="rptResults"></div>

<% 
'A bunch of complicated code to handle the form post and manipulate the html in the "results" div based on the report type would pollute this page.
%>

Note here that I’ve added our new report type, “Attendance by Campus” onto the old report type options.

Obviously we don’t want to add to what is likely already a complex page. We want to do this in our new web app! The problem, though, brings up the first proposition in our pattern:

1. Complex server form posts can be hijacked with Javascript.

We’ll handle this in the page’s javascript. What we want is to NOT post to the old ASP server page, but to reroute the page to the new web server:

$(document).ready(function() {
    $("#frmReports").submit(function(e) {
        var reportType = $("#selRptType").val();

        if (reportType === "3") {
            $.get('http://localhost:3000', function(response) {
                //do something here
            });

            return false;
        }

        return true;
    });
});

I’m not going to go into the details of the logic behind the new web server since we can just assume it performs some business logic on the database and renders the appropriate chart. I’m also not going to handle how authentication should work to allow the legacy app to ensure it has access to the new one. You can handle all that with a wide variety of solutions outside the scope of this article.

As you can see in the code above, we’ve hijacked the form, checked to see if the new report chosen needs to go through the new server or the old server. If it needs to hit the new server, we just make a simple web request and get back the response. Now what do we do with it? This brings us to our second proposition:

2. New server technologies can be hybridized into the DOM of the old server.

How do we do this? In our case, we could do something like this:

$("#results").html(response);

We essentially bypass all that old server logic that’s manipulating the “results” div and just dump it into the DOM. The beauty of this approach is that if there’s additional behavior on the old web UI that needs to happen, we can manipulate anything we want in the old page’s Javascript because the new page logic is every bit as much of the DOM as the old one. Just keep in mind here that any extra scripts you load from the new page are going to be loaded asynchronously. There are some solutions to this described [here].

This obviously isn’t a silver bullet, and there are some considerations you need to think through before doing this. Do you *really* want to create a deep UI dependency between the two server’s pages via Javascript? But for small features like this, it works great. I was able to use this approach for what I was doing and be pretty content with it. It’s a great way to bypass the pain points of old server technologies and redirect you from the 1990’s to the 2010’s.

Ready to get started?