Building AIM, Part 2: CFML Architecture

We needed to build an inventory system, one that was free from the restrictions of our legacy system. We wanted to build a system that could describe any piece of inventory: from cars to carpets, from houses to job listings. We needed an interface for our sellers to actually manage that inventory. That interface is the AutoConX Inventory Manager, which we call AIM.

This is the story of the CFML architecture for AIM.

In an effort to make my life easier, I began to work on a framework. CFML, itself, has a framework infrastructure called the Application.cfc, and many developers do without an established MVC framework. However, I thought I could provide myself a leg up on upcoming projects while also providing the community with another framework solution. I got to work on CoreConX, iterating on it as AIM grew and matured.

CoreConX is a standalone CFC or Application extender that provides methods and functionality that I found helpful in developing AIM. I wrote it to extend AIM’s Application.cfc atop CoreConX, enhancing the application with CoreConX’s features. With CoreConX you can define and configure a translator, an authenticator, a query string utility, and a structure value output utility. The framework, while providing me with a great deal of help in the early days of AIM, did not ultimately make its way into any other project. I plan to replace CoreConX in AIM with the ColdBox framework in the future.

How is the CFML organized? After creating CoreConX, I still had to organize the rest of the project. Every metaphorical object has an object CFC and a data CFC. The object CFC models getters and setters and display methods. The data CFC is responsible for talking to the API and then providing that data in a way that easily populates the object CFC. This allowed some separation of the data fetching and manipulation from the actual shape of the items I was working with. This made commits smaller, and it localized logic in a way that made sense. I also created an APIServer service that handled all the communication with the API server, centralizing the logging and debugging.

How to handle views? CFML is part tag language and part script language. It was designed to blend in with HTML, so it’s easy to write views. It’s another matter to write views that are reusable and logic-less. I made a concerted effort to establish a pattern for rendering views using parameters. This increased reusability of those views and also came in handy for the style guide. I could use the same exact view in both places by just passing fake data to the Style Guide. This made it possible to produce a living style guide that changed as actual code changed and allowed me to establish a visual regression testing procedure using PhantomCSS.

What about testing? Testing was a first-class citizen on this project. Every component was built with testing in mind. There is not enough test-shaming in the CFML community, despite there being good tools to test with and absolutely no excuse not to write tests. I created test suites for every component with logic in it and used the BDD-style syntax within TestBox to write them. I typically develop using TestBox’s HTML runner, but the simpler runners came in handy as part of the Gulp test:cfml task and precommit hook.

What did I do wrong? I’ve read plenty of application development articles, and I tried my best to adhere to best practices. That said, you’ll notice I said nothing about controllers or routes. What stood in for controllers was a mess of cfscript at the top of each page. There was no dynamic routing. The URL you saw in the browser told you exactly where to find the CFM file. Services, too, were a problem. They were lumped into the same folder as the rest of the models, and their roles were not explicitly defined. The frustration associated with all these shortcomings would lead me to use a more robust and mature framework for future projects.