[Rails] Program logic behind Ruby On Rails

Stefan Arentz stefan.arentz at norad.org
Sat Jan 15 09:25:48 GMT 2005


On Jan 14, 2005, at 9:03 PM, Michael Koziarski wrote:

>> I agree that it is bad having the logic in controllers. But I also
>> don't like to put business logic in in the domain model. I try to keep
>> the model objects as lightweight as they can be; if I add logic to 
>> them
>> it is usuall for handling relationships between model objects or 
>> simple
>> getter/setter logic.
>>
>> My approach is this: I move all business logic, the glue that actually
>> puts model objects together to make sense as a whole, in a Service
>> Layer. Personally I think this is a much cleaner design because it
>> doesn't pollute the domain model with application logic.
>>
>>   http://www.martinfowler.com/eaaCatalog/serviceLayer.html
>
> I can quote Fowler too ;).  What you're describing is an anemic domain
> model,  and the style of programming is quite common in java (IOC
> containers especially).
>
> http://www.martinfowler.com/bliki/AnemicDomainModel.html
>
> "In general, the more behavior you find in the services, the more
> likely you are to be robbing yourself of the benefits of a domain
> model. If all your logic is in services, you've robbed yourself
> blind."

In that article he calls himself an 'object bigot'. I guess I'm just a 
bit more pragmatic than that. I understand what he is saying, but in 
practice (been using these  patterns for a long time) it doesn't matter 
much. The end result is a nicely layered application where persistence, 
business logic and gui logic are all seperate. And easily pluggable 
(with different implementations or mock objects for example).

Also, I quoted that page for the picture, not for Fowler's highly 
academic view on software development. Personally I think he has lost 
touch with reality.

Anyway, my applications usually look like this:

Backend:

Domain Model Objects: User, PhoneNumber

These are plain objects. They have NO idea about persistence and do not 
inherit from any persistence framework. That is handled by the 
persistence engine transparently. It keeps them dumb. They simply use 
the language features for relationship mapping to other objects; 
arrays, maps and object references.

Why is this good? I might also want to store a domain object in memory 
or use it in a GUI using a typical Command pattern. Then I don't want 
to have: a) all the extra baggage that for example ActiveRecord's 
persistence logic adds to the object and b) don't want to expose all 
the business logic to the user of that object.

And yes, these are used as 'data records'. I only put logic in there 
that works with the data in the object or its relations. Like 
TodoList.add_todo Subscription.expired? or User.encode_password


Data Access Objects: UserManager, TodoManager, or simply a global 
EntityManager

These objects contain all the 'base' operations on the domain model. 
Things like createUser, disableUser, findUsersByCountryCode, 
deleteUser. They do not contain application logic. They typically 
interact with the persistence layer, wether it is contained in an 
ActiveRecord style or an O/R mapper like TopLink.

These are all build on interfaces. UserManager is an interface, 
UserManagerImpl contains the actual implementation.


Application Logic Objects: AddressBookLogic

(These are what I confusingly called the 'Service Layer' in my previous 
email)

Just as the DAOs these are all coded against interfaces. This is great 
because when I for example want to test if a mailer object works ok 
then can I simply change the reference from MailerImpl to 
MailerMockImpl which instead of actually sending email through SMTP 
will simply log its actions to a file. Plug and play. Great for 
testing. The IoC container takes care of this, there are NO references 
to actual implementations in the code, just references to the 
interfaces.

These objects contain all the 'strategies' of the application. Things 
like signupUser (unit of work: createUser, createHomepage, 
createProject, send an email) or createDefaultProject (unit of work: 
createProject, createDefaultProjectCategories).


Service Objects:

(Not what Fowler describes)

Usually I need to expose Application Logic to an external system 
through some kind of web service or remoting API. What I do then is 
build a thin layer in what I call a Service object. These interact 
directly with the Application Logic.

For example say we have a Todo application. In the Application Logic 
domain i would create a TodoLogic object like this:

  TodoLogic.createTodo(user, todo_name, todo_priority)
  TodoLogic.listTodos(user)

While this could be wrapped in the TodoService object like this:

  TodoService.createTodo(username, password, todo_name, todo_priority)
  TodoService.listTodos(username, password)

In this case it simply adds username/password to the service.


Frontend:

The frontend consists of Controllers, Commands and Validators. Much 
like rails except that Validators are not directly tied to the domain 
objects are (form) commands are plain objects. I like to seperate the 
different concerns.


> I'd suggest that transaction demarcation is typically a UI thing

Many of my applications don't have a GUI. Or are simply a GUI on top of 
a bigger system, a backend that works independent of the web app. So I 
would say the GUI (the form's submit action) is one point of 
transaction demarcation and strategies within an Application Logic 
object are another place.

  S.



More information about the Rails mailing list