The term "legacy application" strikes fear in the heart of many a developer, invoking images of spaghetti code, undocumented secret sauce, and evidence of multiple attempts to start some semblance of a paradigm that might have been in the vague direction of a coding standard or convention. Fortunately, there now exists a direct path to bring your legacy out of the cold and into the warm embrace of a modern framework.

ColdBox has seen the need for a migration path for these applications and implemented a feature called Implicit View Dispatch. This means that without having an event handler defined, you can create views, and the events and actions are implicitly created based on folder structure of /views. For example, I can create a view file in the location of views/about/contactUs.cfm, and the corresponding event is implicitly created, permitting the URL mysite.com/about/contactUs to display that view. No handlers, no layouts, no routes. Just views. Pretty slick.
 
This also allows for entire applications to be dropped into the views folder, and ColdBox handles it automatically – all old URLs remain intact! Once it's working this way, you can slowly start adding MVC magic to your app: extracting a layout; building model objects and services; creating real controllers; using interceptors and plugins for security, logging, etc.
 
We recently traveled this road with a client's legacy, internal administration tool. With over 10 years of development, calling it "legacy" is gracious. We knew it was a mess, and only a complete rewrite seemed sufficient to bring it up to modern standards. However, I started playing with Implicit View Dispatch as a pet project and over time realized its viability for moving the app toward a real framework. This writing is intended to share the steps we took and the things we learned as we (successfully!) wrapped the application in ColdBox and have begun the process of refactoring into true MVC.

Hide index.cfm

Without some rewrite magic, URLs will take the form of /index.cfm/folder/view.cfm, but that's likely not the URL structure your app is accustomed to. ColdBox provides Apache and IIS rewrite rules to mask "index.cfm" from the URL, so you can match your old URLs exactly.

Application.cfm/cfc

Most applications have an application.cfc or .cfm in the root, but now the app should use ColdBox's. This file should be removed. If magic happened here, it needs to be moved elsewhere.

Routes

The first thing you'll notice after placing your app within ColdBox is that some of the pages will work, others will return 404s. ColdBox is great about finding pages that are 1 folder deep, such as /views/about/contactus.cfm. But we had files in the root folder of the site, and others that were 2, 3, or more subdirectories deep. ColdBox would not recognize these right away.
 
Fortunately, a little Routes magic did the trick. For files in the root of the site (now in Views), this route was necessary:

addRoute(pattern="/index", view="index");

We then added routes for each file that was directly in /views. For files that were 2+ directories deep (e.g., mysite.com/department/accounting/staff.cfm), we added routes like this:

addRoute(pattern="/department/accounting/:action", handler=" department/accounting");

This worked for all the files within /views/department/accounting/*.cfm. We added one of these for each directory with a depth greater than 1. If you're command line savvy, you can generate a list of all the directories that need to be added. I recommend this approach to avoid mistakes.

cfincludes

We had <cfinclude /> statements everywhere. In an attempt to be minimally invasive to our application, we decided not convert these to RenderView() statements yet. We did, however, do a search and replace to prepend /views to all of our cfinclude template paths. Depending on your application, a small handful of mappings might negate the need to change these.

Static Assets

We decided to move our static assets (images, javascript, css) into ColdBox's includes folder. Most of our assets were aggregated in a central location in our legacy app, so this was another search and replace in the codebase.

CFCs

We had several CFCs in our system, conveniently located in a dedicated folder. We moved these into the ColdBox model folder, and put them into a subdirectory called 'legacy.' As we refactor, we have different standards and will eventually want these to disappear altogether as they're replaced with true model objects. We did a search/replace for CreateObject statements, converting them to getModel() statements. If these will be autowired, you can generally delete the .init() portion of the statement, as well.

Settings, Environments

We had amassed quite a collection of settings that were created onApplicationStart(), and lived in the application scope. These were moved into the ColdBox config as settings, and environments were used to adjust these for various development environments we use. This prompted another search and replace for application.mysetting to be replaced with getSetting("mysetting").
Note: This does not work in model objects without the Controller object. You can inject it via WireBox if necessary.

Security

ColdBox has a flexible security interceptor that we've used in other applications, but at this time we chose to keep our security in-place in the views folder. This will be one of the first things we extract and refactor using ColdBox's interceptor.

Layouts

A notion of a layout was half-complete in our legacy application, but we at least had a consistent header and menu on most pages. Fortunately, this HTML was in a single file that was included from many other pages. Using this, we created our main layout. Using the layout settings in ColdBox.cfc, we set this as default. We noticed, however, that many of our pages were now being given layout that previously weren't. So we created some empty or pared down layouts, and again used the layouts settings to apply these to the appropriate views and entire folders of views.

Next Steps

At this point, the application is working within ColdBox, but is still procedural in nature. Extracting business logic to models and services, building true views, and wiring them together with handlers will take time, but we can now do it on our own timeline.

Conclusion

These basic steps allowed us to bring our application into a framework in a way that kept the existing logic intact and now provides the opportunity to slowly refactor over time. Getting over this hump was a huge milestone for us and we are excited about all the tools, conveniences, and best practices that are provided by ColdBox. We now have the foundation to talk about sweeping changes, such as major visual redesigns, enterprise-level caching and security that our other apps already enjoy.