[framework-one] Best Practices: extending the framework past the basic objects & composition of service objects

175 views
Skip to first unread message

Bittersweetryan

unread,
May 18, 2010, 11:24:58 AM5/18/10
to framework-one
I have a few questions regarding extending the framework past basic
and composition of the service objects.

First I have a bunch of rules utility classes that don't really fit
into the basic FW/1 folder structure. Before FW/1 my objects lived in
their own packages such as com.idl.app.user (IDL is the company I work
at) which had controllers and rules in that namespace and
com.idl.data.user which had my model classes in there. This would
produce a directory structure like so:

-com
-idl
-app
-user
-UserController.cfc
-UserRules.cfc
-utility
-QueryUtility.cfc
-data
-user
-User.cfc
-UserDAO.cfc
-UserGateway.cfc

Using the FW/1 conventions this structure doesn't work. I don't have
a good place to put my Rules and Utility classes. Would it be good
practice to create a new namespace (folder) for each type of object
that I use? For instance:

-controllers
-UserController.cfc
-services
-UserService.cfc
-model
-User.cfc
-UserDAO.cfc
-UserGateway.cfc
-rules
-UserRules.cfc
-Utils
-QueryUtilities.cfc

Second, I'm really working on trying to strengthen my OO skills and I
have a question about the composition of my Service objects.

Lets say i have a UserService object. This object will be composed of
the UserDAO object for CRUD, the UserGateway object for getting lists,
and the UserRules (which also uses the UserService and UserGateway
objects to talk to the database) object to validate a user against
some business rules.

My question is where should all these objects live within my object?
Do they go in the variables scope and add them to this object via
IoC? Or would they be transients that are created and destroyed as I
need them? For instance, I would only be using the DAO for a save
method and only using a Gateway for a list method.

Thanks to anybody who has taken the time to read this post and help me
out, I hope I wasn't too confusing!

--
You received this message because you are subscribed to the Google Groups "framework-one" group.
To post to this group, send email to framew...@googlegroups.com.
To unsubscribe from this group, send email to framework-on...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/framework-one?hl=en.

Sean Corfield

unread,
May 18, 2010, 2:18:56 PM5/18/10
to framew...@googlegroups.com
On Tue, May 18, 2010 at 8:24 AM, Bittersweetryan <ryan....@gmail.com> wrote:
> First I have a bunch of rules  utility classes that don't really fit
> into the basic FW/1 folder structure.  Before FW/1 my objects lived in
> their own packages such as com.idl.app.user (IDL is the company I work
> at)  which had controllers and rules in that namespace and
> com.idl.data.user which had my model classes in there.  This would
> produce a directory structure like so:

Sounds like they're part of the model?

> -model
>   -User.cfc
>   -UserDAO.cfc
>   -UserGateway.cfc
>   -UserRules.cfc

There's nothing to stop you using the reverse.domain.package.Component
approach with FW/1 for the model, BTW:

com/
idl/
app/
...
controllers/
...
layouts/
...
views/
...

>   -QueryUtilities.cfc

Sounds like that also belongs in your model tree somewhere?


> Lets say i have a UserService object.  This object will be composed of
> the UserDAO object for CRUD, the UserGateway object for getting lists,
> and the UserRules (which also uses the UserService and UserGateway
> objects to talk to the database) object to validate a user against
> some business rules.

I'd strongly recommend not getting into this whole bean + DAO +
gateway + service approach. You'll create a lot more objects than you
need and you'll likely end up with an anemic domain model (a 'struct'
for a bean and all your logic elsewhere).

Here's what I recommend:
- a bean per entity (nothing controversial there)
- a gateway for each group of related entities - that handles both
CRUD *and* aggregate queries
- a service for each distinct area of your application

The services and gateways do not need to match up (they often will -
they just don't have to).

There's no real benefit to having separate DAO / gateway objects
unless you're working from generated code (the CRUD stuff is easier to
generate) - and even then, having the gateway extend the generated
CRUD CFC keeps your system cleaner.

Outside the CF world, DAO and gateway are interchangeable. The Core
J2EE Design Patterns book stands pretty much alone in calling them
DAOs where almost everywhere else calls them gateways (or data
gateways or table data gateways).

> My question is where should all these objects live within my object?
> Do they go in the variables scope and add them to this object via
> IoC?  Or would they be transients that are created and destroyed as I
> need them?

The services and data access layer (gateway) CFCs are likely to be
singletons and therefore managed by IoC - and injected into your
(transient) domain objects as needed.

The key is to keep as much business logic as appropriate in your
domain objects so that services act only as coordinators for
operations that must span multiple domain objects.

An exercise I like to give people learning OO is to take a problem,
identify the domain objects and then assign a domain object to each
person and have them pass messages to each other in order to solve
problems. This focuses people on object responsibility and
collaboration and gets them away from code. In such group exercises,
there are no service objects (except sometimes me acting as a
coordinator, if the problem requires it).
--
Sean A Corfield -- (904) 302-SEAN
Railo Technologies, Inc. -- http://getrailo.com/
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood

bittersweetryan

unread,
May 20, 2010, 10:23:44 AM5/20/10
to framework-one
I just read your blog post "The DAO and Gateway separation in CFML is
nonsense" and I understand what you are saying a little more clearly
now. However, would you be able to expand on this statement "- a
gateway for each group of related entities - that handles both CRUD
*and* aggregate queries " a bit more for me? Specifically, "related
entities" is where I get confused, are you suggesting one gateway for
an object and all of its related objects as defined by FK
relationships in the database?

FWIW I really appreciate the help, I'm a big proponent of the
ColdFusion language and I think the best way to promote it is to have
good coders writing good applications. It's so easy to get
complacent, especially with such an easy to use language like CF.
This is which what has happened to me over the last few years. I
started writing applications in what I thought was a O-O approach and
never bothered to challenege myself, and I never had the privelage of
working with coworkers who were great OO developers to challenge me
either. My eyes have been opened lately, and I am working really hard
to become a better programmer. Without help from people like you
ColdFusion programmers like myself would never push themselves to
become better.

-Ryan


On May 18, 1:18 pm, Sean Corfield <seancorfi...@gmail.com> wrote:
> Railo Technologies, Inc. --http://getrailo.com/
> An Architect's View --http://corfield.org/

Dave Anderson

unread,
May 20, 2010, 3:57:36 PM5/20/10
to framework-one
That's exactly what Sean's suggesting, I believe. Say you've got
(from the cf example app database) artists and art works. You might
have two or three different tables, but instead of having ArtistDAO,
ArtistGateway, ArtDAO, and ArtGateway objects, you might simply have
an ArtDB object that wraps all that functionality into one cfc with
methods like saveArt() saveArtist() readArt() readArtist() methods and
so on. Some might resist that in favor of the ability to use those
ArtXXX objects in other apps (without the corresponding ArtistXXX
objects), but if that seems unlikely, it might be nice, as Sean
suggested, to have all the DB interactivity for both Art and Artist
objects encapsulated in one CFC.

(I've personally used Illudium a lot, and Sean's suggestion makes me
want to create a custom template. :)

Sean Corfield

unread,
May 20, 2010, 6:14:47 PM5/20/10
to framew...@googlegroups.com
On Thu, May 20, 2010 at 12:57 PM, Dave Anderson <da...@metaldog.net> wrote:
> That's exactly what Sean's suggesting, I believe.  Say you've got
> (from the cf example app database) artists and art works.  You might
> have two or three different tables, but instead of having ArtistDAO,
> ArtistGateway, ArtDAO, and ArtGateway objects, you might simply have
> an ArtDB object that wraps all that functionality into one cfc with
> methods like saveArt() saveArtist() readArt() readArtist() methods and
> so on.

Yup. If you have a group of related entities - and they can be
conceptually related, not just physically related - then having a
single "data gateway" object makes sense. Dave's picked a good
example: whilst you have separate Art and Artist entities, you're not
really going to be dealing with them in isolation, you'll be doing
CRUD on Art and Artist, true, but you'll also asking for all of an
Artist's works and, most times, when referencing a piece of Art,
you'll want the associated Artist. You may also have a Movement
entities, like "impressionist" and either Art or Artist (or both) will
be associated and so data operations on Movement would be a good fit
for your ArtGateway object.

This way you have:
* Art.cfc, Artist.cfc, Movement.cfc
* ArtGateway.cfc

Then your application might have GalleryService.cfc to coordinate
those (or LibraryService or ArtCollectorService or whatever is an
appropriate domain-specific name). That service will interact with the
ArtGateway and probably other data gateway objects - and indeed there
may be other services that also interact with the ArtGateway,
depending on the application.

I say "might" because you want to try to keep services to a minimum
and have rich domain objects instead. Some services will be necessary
because they encapsulate orchestration rules (collaboration /
coordination).

Then your application will have one or more controllers - each
handling a specific related group of screens in your application. They
may or may not map to services. For example, I might have a Login
controller that talks to a SecurityService (and maybe a UserService).
The SecurityService may talk to a UserGateway and an AccessGateway
(the latter interacts with Role and Permission entities, the former
with User and Profile objects - consider a system where a user can
have multiple private and public profiles on a social networking
application). You'd probably have a Profile controller too, also
interacting with the UserService. And of course, if the services are
really thin or non-existent, the controllers might talk directly to
the gateways - which highlights the issue of how you might handle
secure access in an application. If you have no remote (Flex, Web
Service, Ajax) access to services, then the only security is going to
managed by your controllers / framework, interacting with a
SecurityService. If you need remote access, you'll need at least a
facade for those services that also provides security. In that
situation your facade will interact with the SecurityService.

Some people like to push the security down into the service layer so
they can reuse things "more easily" between a web controller and a
remote controller (such as a Flex app). I prefer the flexibility of
building a custom remote facade when it is needed - but making sure
that the original web controllers do not handle security directly:
they delegate to a SecurityService so that can easily be reused. My
reason for this is based on experience: the API you need to expose for
a remote controller such as Flex is often quite different to what you
need for a web controller because the user experiences will be
constructed differently (after all, what's the point of simply
replicating a web app in Flash?). For remote access, you're more
likely to be passing credentials (of some sort) on every request since
you *must* perform security checks in the remote facade. For web
controller access, you're more likely to be relying on session-based
authentication and using the controller / framework for
"pre-authorization" before requests go to the service layer.

> Some might resist that in favor of the ability to use those
> ArtXXX objects in other apps (without the corresponding ArtistXXX
> objects), but if that seems unlikely, it might be nice, as Sean
> suggested, to have all the DB interactivity for both Art and Artist
> objects encapsulated in one CFC.

More to the point, you can start with "the simplest thing that will
work" (a single data gateway) and then refactor into multiple gateways
_if_ you need them. However, the more gateways you have, the more
often you have to ask "where does this aggregate query method go?"
since it touches multiple related entities.

> (I've personally used Illudium a lot, and Sean's suggestion makes me
> want to create a custom template. :)

And that's why I don't like code generators in general. They work from
a fairly mechanical set of rules and they lead to the 5:1 syndrome by
default (bean + dao + gateway + service + controller). To generate the
sort of structure I prefer to work within - that I believe is much
easier to understand and manage (because you have fewer objects and
the objects you do have and more cohesive) - would require a fair bit
of configuration and design input, identifying related groups of
entities etc, and at that point it really becomes a matter of
diminishing returns: you get close to being able to hand-code some of
this faster.

And that's especially true when you're using an ORM (of any sort)
since it obviates the need for CRUD operations anyway...
--
Sean A Corfield -- (904) 302-SEAN
Railo Technologies, Inc. -- http://getrailo.com/
An Architect's View -- http://corfield.org/

Sean Corfield

unread,
May 20, 2010, 6:27:39 PM5/20/10
to framew...@googlegroups.com
On Thu, May 20, 2010 at 7:23 AM, bittersweetryan <ryan....@gmail.com> wrote:
> Specifically, "related
> entities" is where I get confused, are you suggesting one gateway for
> an object and all of its related objects as defined by FK
> relationships in the database?

Well, I don't start with a data model - I start with an object model.
That means I'm not thinking about FK relationships specifically, I'm
thinking about closely related domain objects in the business problem
space. Hopefully my reply to Dave's post will make that clear.

As an example, when I built the Broadchoice Workspace*** with Joe
Rinehart, Brian Kotek and Ray Camden, we were using Hibernate and we
let it manage the schema for us completely. We designed - and refined
- an object model and Hibernate created / modified tables and
relationships for us. As it solidified, we had our DBA review it and
make some changes for consistency of the data model and for
performance, but it freed us from even thinking about the physical
representation of the system.

*** Workspace is a Flex-based AIR app that talks to a BlazeDS / Groovy
/ Spring / Hibernate service layer running on JBoss / MySQL. We then
installed Railo and built a Model-Glue / ColdSpring web app for the
iPhone that reused the underlying Groovy services (we had a separate
remote facade already for BlazeDS to talk to).

Also bear in mind this is a journey - the destination keeps moving
into the future as current thinking on best practices evolves. When I
started down the OO path (in January 1992), a lot of current best
practice enshrined in "standard" text books simply did not exist! For
example, the classic "Design Patterns" book had not even been written
- it appeared at the end of '94...
--
Sean A Corfield -- (904) 302-SEAN
Railo Technologies, Inc. -- http://getrailo.com/
An Architect's View -- http://corfield.org/
Reply all
Reply to author
Forward
0 new messages