Migration: Legacy application and trigger happy

Many of my major projects of my career have been in application migration involving rewrite using a new technology. I can think of only one instance where it was a big bang approach, where we built a new system and in one go replaced the other system. It wasn’t as simple as it sounded, but we could justify this approach and it worked well.
However every other time, we have built the new system invariably adding new features while keeping the old system running and accessible.
There have been many different approaches to this strategy. While in some cases, we would force the users to switch to the new application when available while disabling features from the old. Other times we would keep the old app running in parallel while making continuous releases on the new application. We have even had to maintain and service the old application to keep the business happy and sometimes to make the application gel with the new features being introduced in the newer application, especially when database changes were involed.

I’ll go through one such case where we had to rewrite a critical application while keeping access to the old system. We discovered that a lot of business functionality was kept in database triggers. There were many apps and I guess at that point someone decided to use triggers since they then needn’t touch any of the apps to add new features. You can read my take on business in database here.

We had decided to use DDD approach and this meant consolidating all those business rules in the trigger in their respective domains. The database being a common layer for both the applications, called for some strategy here.

The triggers couldn’t simply be disabled nor could we have them trigger when the new applications interacted with those underlying tables.

We need to restrict those triggers to only the old applications. The triggers will fire, no stopping that. But, we’ll stop the triggers body from continuing execution of the SQL. There are couple of ways of doing this.

  1. Using App Name

    This is the least impact way of determining if the trigger needs to continue execution or return. Providing an app name in the connection string ;app=YourApplicationName, would make it available in your SQL session. I also make it a practice to include this as it helps in profiling your database more easily. In your SQL (Trigger) you can now check

    1
    if (APP_NAME() = 'YourApplicationName') RETURN;
  2. Using a column to track the transaction source

    Depending on your situation, this might be intrusive or acceptable. If this is a new column, you might want it to have a default value so that older applications can use that. You should set a specific value from your new applications for each transaction it does with these specific tables. Check for these values in the trigger and exit from executions. Of course the trigger would execute completely for transactions from your older applications. With this column you can also gain some insight in to who is transacting with which app. Be sure to check correctly in inserted or deleted special table depending on the operation that activates the trigger.

In both the above methods, there would be no change in the legacy applications.

BTW, many of the triggers were good candidates for domain events.

I have used both approaches and they have worked well for me. If there are other ways of doing this, let me know in your comments.