Tag Archives: coldfusion

How I Learned To Stop Worrying And Love Inheritance

So for the last month or so (and for at least another couple of weeks to come) I’ve had my nose to the grindstone on what’s likely to become the primary project management tool for my current employer. It brings a lot of changes to the table for us (consolidating client, project, module, and user management into a single area, granting limited (secured) access to clients and their customers, incorporating hooks for a lot of planned new functionality to come, to name but a few) but one of the bigger departures is a move from a scattered and only weakly-enforced MVC format to a much cleaner (and more PHP-like) OOP structure in a tightly-enforced MVC format with most of the core functionality abstracted away in a series of classes from the hands of future junior devs and dabbling execs with coding privileges. As much a change in our standard coding practice as in the core architecture itself.

Setting that up made for the perfect excuse to do something I’ve wanted to try out for awhile: take advantage of CF9/Railo 3.2 and throw tags out the window altogether to move into all-script CFCs. On top of that, most of the existing ‘OOP’ architecture was little more than a collection of (undocumented) function libraries, so this seemed like a good time to force a move to JavaDoc-style notation and better OOP as well. Got data that multiple sub-modules need to keep straight? Make it a property of the core class. Want a bunch of methods available to the sub-modules but don’t want to keep rewriting it? Standard inheritance has your back. Et cetera. Good times.

What started as a few core modules ballooned into an ever-growing series of classes, subclasses, and utility libraries, and it only hit me belatedly that while there was a shell of a front-end interface waiting for the back-end to be completed, I hadn’t actually tried running any of them yet—unit testing is still on my Things-To-Start-Doing list, unfortunately. In front of me was a shiny (and mostly empty) display page, waiting for the refresh that would actually initialize the class at the end of a complex chain. Any errors in any of the other linked classes, properties, or methods would spell ruin for this page until fixed…

Sure enough, refresh was clicked, and the 500 error page appeared with a lengthy stacktrace. A long list of java.lang.StackOverflowErrors alternating between the parent class (ConsoleManager) and one of the new utility classes (Validate). Long-suffering sighs were made, code was delved into, names were desultorily changed in case I’d accidentally used a reserved term in a method or class name. No dice.

And then, on closer inspection, the culprit stood out plainly. In the parent consoleManager class:


component displayname="ConsoleManager" {
...
/**
* A reference to the super-module's custom DB validation library
**/
this.Validate = new ccc.console.validate();
...
}

And at the start of the Validate utility class:

component displayname="Validate" extends="ccc.console.consoleManager" {
...
}

The light dawned. Facepalm time. Custom methods within the Validate class were performed on the same core database referenced as a property in the ConsoleManager class, so initially Validate was set up to simply extend ConsoleManager and thus inherit those properties. But then Validate was needed for other sub-classes of ConsoleManager, so it seemed only logical to store an instance of it in ConsoleManager in the same way. Thus the eternal loop; ConsoleManager is instantiated, attempts to instantiate the Validate class, which is a child of ConsoleManager and thus instantiates another ConsoleManager, et cetera ad infinitum (or at least until stackOverflowError).

In the end, the database reference simply became an init() argument in Validate’s constructor function (passed in by ConsoleManager on instantiation) and no more extension was needed. The loop was broken, and many lessons were learned about class inheritance, the importance of test-driven development, and the pitfalls of too much uninterrupted coding.