Monday, February 14, 2011

An application or a set of resources?

My last post about DCI and Rails triggered many interesting discussions. One of the topics that came up very often can be summarized to this question:

Do you think of your web application as an application or as a set of resources?


My answer is clear: it's an application.

I noticed that not everyone agrees with it.

In the Rails world a resource is a very popular word. Mostly because of the REST architecture that we follow in our apps. Whenever I can I use the REST approach, but I think of it as a way of using URL's and accessing the application. I find it a nice way of structuring my controllers. REST is just an interface. From outside and for my users it's an application, not a set of resources. They use resources but they access them through an application which to me is an important distinction.

This topic caused that I decided to publish the assumptions that are needed for a DCI architecture, at least how I understand it:

1. As developers we model the real/business world.
2. If a concept appears in the model we reflect it in the code.
3. Most of the web apps scenarios has the pattern of "a user does something with the app"
4. If user and app are so important in the domain then we make them classes/objects.
5. It results in big user/app classes.
6. The problem of big classes can be solved by using the idea of "injecting roles" runtime.

Usually point 5. discouraged people from reflecting the user/app importance in the code. The alternative is chosen which is things like this in the controller:

@discounted_products = Product.discounted

whereas I prefer this:

@discounted_products = shop.discounted_products 
# shop is like the application object here

Anyway, point 5 can be now solved by the idea of injecting roles and DCI as described in my last blog post and in my opinion we can start using the user and application objects more often. Once you start using them, many of the OOP decisions you need to make become easier, because you just reflect the domain in the code.

6 comments:

taw said...

A student of Zen once asked Buddha "Do you think of your web application as an application or as a set of resources?".

Buddha replied "Do you think of your online resources as resources or parts of an application?"

At that moment, the student was enlightened.

Gernot said...

After I really understood the REST philosophy (at least I think I got it), I see my applications as a set of resources and URIs to access these resources.
Users are resources, too. I do not model my applications user centric. Instead, I restrict the accessablility of resources based on an authorization model.
The authorization model defines what a user can see and do.

The business logic is implemented in command classes. Only commands can change the state of objects. The controllers talk to commands, never directly to the domain model.

This is a common architecture and it works really well for me, especially using the Rails framework. It scales well, is easy to understand and test.

Andrzej Krzywda said...

"The business logic is implemented in command classes. Only commands can change the state of objects. The controllers talk to commands, never directly to the domain model."

It sounds interesting. Could you show an example of controller-command-model communication?

Gernot said...

The rule of thumb is that there is a command for each CRUD operation on a resource.

Here's an example from my problem domain, a rental contract. We have a resource rental_contracts. To create a new rental contract, we have a view that allows the user to select one or more people (the tenants), one or more objects to rent and several attributes for the contract.

Since the construction of such a contract is quite complex and carries a lot of business logic, we have a create_rental_contract command. The command accepts a params hash for its constructor, just like a model. Furthermore, it includes ActiveModel::Validations so it can validate the params.

In short, a command behaves like a model from the controller's point of view. The controller simply passes the params hash to the command, executes it and redirects to the "new"-view if there were validation errors. All validations are implemented in the commands, not in the models.

The create_rental_contract command then orchestrates the required state changes in the domain model. It creates the contract, adds the tentans and objects to the contracts, sets the contract objects to "not available for rental" and so on.

This approach imho has several advantages:

- Commands are easily testable
- Commands add context
- Commands encapsulate business transactions
- Commands do the transformation from the view model to the domain model (the view model is oftentimes simplified and hierarchical (Parent/Child) while the domain model is object oriented)

Andrzej Krzywda said...

@Gernot

I like it very much!
I think you're using the Context part from the DCI approach, see my previous blog post:

http://andrzejonsoftware.blogspot.com/2011/02/dci-and-rails.html

I want to experiment with it as well.

I think your Commands part is something that is popular in the Java/.Net world as the Application Logic. It's not very popular in the Rails world, though.

As for the application vs resources discussion - when you want to display all the users from your app, you simply call User.all directly from the Command?

Gernot said...

Hi Andrzej

Commands are only used to modify data. For index and show actions we access the models "the rails way" directly in the controller (in simple cases) or we use presenters to transform complex object graphs from the domain model to the view model.

I think that the command pattern is not really needed if you have a very simple application. But when your domain model and business logic reaches a certain degree of complexity, it helps to manage that complexity.

Another benefit: Power users can use our commands directly within a "console" in our web application. They love it.

Best regards
Gernot