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/