Building an Application with ColdBox and ColdSpring - Part 1

I have begun putting together an application to build using ColdBox and ColdSpring. I am doing this to demonstrate how I have been doing this to solicit feedback from the experts to see if I am making any huge or stupid mistakes and to show some new comers to OO how to build an Application using OO principles and tools. I am hoping that my learning experience and blogging can help others learn these concepts too.

As I said before, I do not consider myself an expert in Object-Orient programming or in ColdBox/ColdSpring, but I feel I know enough to demonstrate these things at a basic level. I am counting on the true experts to keep me honest.

The application I have decided to build is a simple To-Do Organizer. This application will be used to:

  1. Create To-Do Lists
  2. Create To-Do Items in To-Do lists
  3. Give other basic functionality to lists and items (Update, Delete, etc)
  4. Save everything to a database

So, to begin this project, I am creating a UML diagram to determine the basic structure of the application. This is my first attempt at UML on a "real" project, as opposed to just dabbling. In researching the project I realized that there are several ways to model it. I looked at examples, like Brian Kotek's, here, and I looked at a discussion in the comments section of a post on Charlie Griefer's blog. And I had long discussions will Charlie Griefer and Paul Marcotte on the subject. Thanks to both of you for taking the time.

In all of the diagrams below I tried to use similar techniques to what Brian Kotek did in his diagram posted here.

This is what I came up with:

My first diagram is almost completely copied from Brian's. The main difference is that I did not include a factory and I did include DAOs. I thought about using Transfer in this project, but I do not want to for a few reasons:

  1. Transfer solves a problem. If we begin using Transfer before the beginners realize what that problem is, then they have not learned much.
  2. Adding a factory can complicate things because that is more things to understand and more functions to know. Transfer simplifies development, but I think it could complicate learning
  3. For myself. I started using Transfer before I fully understood how to do many of the thing Transfer does for me. So it would be a learning experience for me too.



My second diagram is influenced by feedback from others and from reading. While my first diagram does not completely have 5:1 Syndrome, it does have a lot of objects. So it was suggested I get rid of the DAOs and create a more powerful gateway. Since Todo Lists and Todo Items are so tightly integrated, and items cannot live without lists, it makes sense to have a single, powerful gateway that handles both.



My final Diagram does include a Factory. I thought I would include this just for fun and exercise. Like I said, I think that using any kind of factory for this small project might be over-whelming or confusing, plus I think it is important for me, and other novices, to learn to do this without Transfer. We are still going to use ColdSpring, regardless of which implementation we choose.



So, I have these three models. Right now, I am leaning more toward using model 2. I think it is a more simplistic design that still has the features we are looking for in a learning application. I would love to get some input or suggestions on this.

FYI, I do not think any of these models are complete. I am sure I am missing methods that we will need, or that I have something modeled incorrectly. So please feel free to point out my mistakes as well. I want to learn from this too. After we chose which model to go with, I will work on fleshing it out and getting all of the methods that we need.

Comments
brian's Gravatar Thinking about getting into ColdBox myself, so really looking forward to this series of posts.

From diagram 1.2 it looks like the Gateway intercepts stuff like save and delete without any interaction with ToDoItem or ToDoList. Could ToDoItem and ToDoList have their own save,update and delete methods which might be handed off to a Gateway if necessary? This would put ToDoItem and ToDoLisr at the heart of the model rather than the Gateway, which in terms of DAO functions may be made superfluous anyway once you implement transfer/reactor etc.
# Posted By brian | 9/22/08 5:23 AM
John Whish's Gravatar Really looking forward to this series. Can I ask what you used to create your UML diagrams?
# Posted By John Whish | 9/22/08 6:13 AM
Jason Dean's Gravatar @brian, because I have used DAOs and Transfer in the past (Never at the same time), I have never had beans with their own save(), update(), delete() methods. And honestly, I don;t like the idea of it. I don't know much about the Active Record pattern, but frankly, I don't really like the idea of my beans interacting with anything but themselves. Other objects can use TodoList and TodoItem beans, but the beans never call on the other objects.

Again, I am new to this as well, so maybe my thinking here is off. But it also seems that if the bean has it's own persistence methods that either it would need to have SQL in it, or it would need to talk directly to the gateway.

In my current design, the gateway is the only object with SQL in it. And like I said, i don't like the idea of my beans asking for things from the gateway.

I hope this is making sense. It's clear in my head. Though not much else is :)
# Posted By Jason Dean | 9/22/08 8:49 AM
Jason Dean's Gravatar @John - I used Poseidon for UML - http://www.gentleware.com/
# Posted By Jason Dean | 9/22/08 8:50 AM
Drew's Gravatar Firstly, thanx for this Jason.
Secondly, I'm a long time fusebox user and have followed convention all the way (sometimes blindly till the penny dropped.).
That said, all my models have followed diagram 1, I'm not understanding why we'd drop the DAO's and place this logic in the gateway.
# Posted By Drew | 9/30/08 7:21 PM
Jason Dean's Gravatar @Drew, thanks for the question. It is a good one, and one that I asked when this was first suggested to me. And the simple answer is, why not?

The purpose of putting our code into different objects is to encapsulate their purposes, or to keep like functionality together. So functionality that is specific to the "user" object is kept separate from functionality that is specific to the "shoppingCart" object. That makes sense and it would gives us our userService and our shoppingCartService if we were working with that type of application.

Well, since we want to be able to swap out or model layer at anytime, it does not make sense for our service layer to talk directly to our database. So we need an object that will talk to the database. Enter the Gateway Object.

At one time it was suggested that we might want to have two separate objects for database interaction, a DAO and a Gateway. The DAO would handle functionality that was specific to a single object (a bean) and the gateway would handle all the other transactions (most of which returned arrays or query objects).

So the current line of thinking is, why do we need to separate the database interaction into more than one object? Well, we don't. It is reasonable for our Gateway object to handle all interactions with the database (unless we are using an ORM, then the gateway handles anything that the ORM doesn't). Why have more objects than we need?

Now to take that one step further, my Todo Items (in my application) cannot exist without a ToDoList to be a part of. So why have a separate object for those objects? ToDoLists are integral to the existence of ToDoItems and ToDoLists are pretty useless without something to go inside of them. So they are not concerns that need to be separated.

Now let's say I was dealing with objects that were related but not integral to each other. For example, let's say I added a "Project" object to my Application. And a Project would contain ToDoLists, which contained ToDoItems. Well could a Project exist without one or more TodoLists? Sure. And could ToDoLists exist outside of a project? Sure. Maybe not in this application, but maybe in another. Or maybe I would add another Object to this application that could also have a ToDoList, like maybe "Conference" object. Plus, a Project would probably have other objects in it too, like Milestone objects, or Task objects, etc. So I would create a seperate gateway object for my Project object, and I would create a separate gateway for my Conference object, but I would still leave my ToDoGateway as is. Because my ToDoLists and ToDoItems will never exist without each other.

This is just how I am thinking about it. I am not suggesting this is the perfect way, but this is the way that makes sense to me. What do you think?
# Posted By Jason Dean | 9/30/08 8:57 PM
Drew's Gravatar what you say sounds fair enough.
I guess I just liked having a CRUD for each object. Besides keeping me strict with it's role it prolly made it a little easier for me to pick up the concept of using an ORM like transfer as well.

Maybe if you were to modify your demo afterwards to use Transfer...that'd be pretty kewl as well. It'd show everything from go to wo in logical sequence....maybe?
Then like you said, diagram one would be best yes

Glad I found your Blog Jason. This is great.
# Posted By Drew | 10/1/08 2:20 AM
Chris's Gravatar One thing nice to see would be how you would do this using Transfer once you are done with the series so we can see the difference. Just a thought. I know time is probably the key.
# Posted By Chris | 12/7/08 6:44 PM
Paul Baylis's Gravatar One of the things I liked about separate CRUD (DAO) and Gateway objects is that if you just want to manipulate a single row during a CRUD operation, you just pass one argument to the DAO object, i.e. the primary key value. If you combined the two objects into the gateway object only, you're either going to need two separate methods doing, say, a select operation - one at the single-record level and the other on the multiple record level, OR have a composite function looking something like:

select * from products
<cfif isnumeric(arguments.product_id>
where product_id = #arguments.product_id#
</cfif>

It wouldn't make sense to retain the two versions of the query in the gateway object as that would just give you a huge cfc. So, you'd probably want to amalgamate the functions.

Not that this is a super-biggie, but depending on what you're doing with your query, it could get convoluted and nasty. The idea shouldn't be to make the UML diagram look clean, but the queries themselves to be clean and easily maintainable. If that takes two separate objects, then why not.
# Posted By Paul Baylis | 3/7/10 10:08 PM
Jason Dean's Gravatar @Paul,

Seems like a reasonable point. I am certainly not going to disagree. It has been so long since I wrote these posts that I am not sure if I would write things the same again.

I appreciate your input.
# Posted By Jason Dean | 3/8/10 10:22 AM
Brad's Gravatar Thanks Jason, this is exactly what I've been looking for!

Cheers
# Posted By Brad | 6/2/10 1:17 AM
Brad's Gravatar Hi Jason,

I just check back to continue the "Building an Application with ColdBox and ColdSpring" series but I'm unable to find the part 2 and higher. Could you provide a link to this series, thank you!
# Posted By Brad | 6/4/10 5:45 PM
Jason Dean's Gravatar @brad,

They should all be in here:

http://www.12robots.com/index.cfm/ColdBox
# Posted By Jason Dean | 6/4/10 8:05 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.1. Contact Blog Owner