UML Diagram of My General Model Structure
During my recent presentation to the IECFUG, one of the parts we didn't really have time to touch on was a diagram I created of my general model architecture.
The diagram is below, and contains a good number of comments to explain the different pieces. Given the recent discussions going on in the blogosphere and on the lists, I thought this might be interesting to some folks. If anyone has questions, please feel free to ask and I'll do my best to answer. Comments are welcome as well, of course.
Note that this is really just a starting point, and that I tweak this base setup as necessary, depending on the project and the specific problem being addressed. But I've found that, in general, this kind of setup provides me with a lot of flexibility and is actually quite easy to create or even generate. If one chooses to look at ColdSpring and/or Transfer, much of this can be generated automatically and then tweaked as necessary. But even if those frameworks aren't suited to your development approach, each of these pieces is relatively straightforward to create.





- drop the aggregation symbol, it has no standard meaning
- multiplicities on those associations might be useful
- remove the attribute compartment if there are no attributes.
- a well-chosen sequence diagram or two might make most of those big comments unnecessary.
To be honest though, this level of abstraction is really quite overkill for a huge number of applications from small to medium in size. Using transfer directly in the Services or keeping most of the logic in the business objects themselves does just fine.
This kind of (very) complicated solution has it's merits, and I've certainly seen places where it solves a number of problems, but it also does wonders to make application design much harder for small applications and really scare new developers away from OO.
That said, this diagram is lovely and really communicates this model of design so much better than all the mailing list posts and blog entries I've seen combined. I'll definitely use this as a teaching reference.
I do wish there were more voices about other approaches to application design in the CF community. This really isn't the only (right) way, we just don't hear much about how Django, Pylons, TurboGears, Rails, the various php frameworks, and even other CF based apps are designed very much. At least not on this side of the fence.
Some might think it is overkill but I really don't. Moving Transfer into the Gateway is not really any extra effort since you need a Gateway anyway for normal SQL. And keeping logic in the business objects is something I would do regardless of project size. I suppose the bottom line is that it really isn't a very complicated solution. There are a number of objects in use but no one of them is particularly complicated. In fact, many of them are very simple or are things that I usually don't even have to write at all (like the Remote Proxy or the Factory) because they are part of other frameworks that I use.
Still, I'm glad you think it is a decent overview of how one might approach at least a fairly large or complex application (which I suppose is what I generally am working on so I could be biased). Thanks, feel free to use the image as a reference!
It seems I was confusing because I mentioned Transfer. InvoiceGateway.getLineItem() / newLineItem() makes much more sense to me than using some kind of external factory for creating objects. We're putting the save/ delete/ and update behavior in the gateway, so throwing in an artificial separation with a "factory" to do create doesn't make sense, at least to me. Sean has also said before that having separate DAOs and Gateways doesn't always make sense. Though you don't really have that here. Instead you have a gateway that does most of the DAO logic, and pushed the create() to something separate.
Replace transfer with "persistence implementation". Since you pass the id into the create() method the Factory must know how the objects are stored, or delegate to someone who does. Similarly, since you can getByFilter(), the Gateway needs the same knowledge. So breaking these things apart isn't gaining you any extra abstraction, just more classes. You can't swap either out without changing both of them.
That's just my opinion on the design though.
The comment "the Gateway is not really any extra effort since you *need a Gateway anyway for normal SQL*" (emphasis mine) is really what I was getting at. Having a gateway at all is considered totally ridiculous in some communities. If we were doing this in the rails mindset we'd just do:
item = LineItem.new
item.populate(params)
result = item.save
The object delegates back to the persistence mechanism. It knows all about it's own validation, and anything else it might be interested in. There's no need for the services, and there's also no need to create Gateways. In fact you mention the word Gateway or DAO over there and you'll get laughed out of the room.
This is not specific to rails though. This is a huge number of communities that include languages from python, to perl, to ruby, to php and beyond. And even essentially the large majority of the CF world.
This *is* the reason that we get called JavaLite though. This kind of application design is very rooted in the Java "enterprise" world, and to most outside it is considered terribly over complicated. Try asking around freenode, you'll get the picture fast.
Is it over complicated? Well that's preference, and there's a holy war just waiting to get started there...
In any case, I'm really not trying to argue which way is better (I sure hope I didn't come across saying either way is right/wrong here). What I'm trying to express that the mindset expressed in this post is very very specific to one very specific way of developing applications. And from an OO perspective certainly not the only right way.
Not a jab at you. Just a thought.
I suppose to someone who was used to just piling everything into a service layer, didn't have the need for AOP or remote calls, etc., this would be over complicated. Personally, I would build things this way even if the project didn't necessarily require all of it yet. Because in my experience these kinds of issues and the solutions this setup provides (factories, gateways, etc.) are things that almost universally impact every project I work on. I am against making too many assumptions or over-engineering in general, but separating object construction from object use is an example of something that is not negotiable (for me). Separating interaction with external resources like databases is not negotiable. If I fail to do these things, there's about a 99% chance that I will regret it later.
So, yes, this may be rather specific to the kinds of projects I work on, but most of this is there because of something I didn't do and learned the hard way that I should have. ;-)
This was a very helpful posting to help get my mind around good model architecture. I am just starting out with OO concepts and am looking for a good model to adopt as a starting point.
Without infringing on any intellectual property, do you think you could post a downloadable zip file of an example of all these CFCs in action. To take what you done with a picture a step forward with as an example would really drive it home for me. (but only if you have something laying around that you don’t mind sharing.)
I can’t tell you how tired I am of seeing Hello World examples
Ryan