BT
x Your opinion matters! Please fill in the InfoQ Survey about your reading habits!

Presentation: Making Roles Explicit

by Abel Avram on Apr 09, 2009 | NOTICE: The next QCon is in San Francisco Nov 3-7, Join us!

In this presentation recorded during QCon London 2008, Udi Dahan, The Software Simplist as he calls himself, explains why sometimes it is not enough to apply good OOP and patterns lessons. He introduces a new principle: make roles explicit.

Watch: Making Roles Explicit (1h)

The entire presentation is about the need to make explicit what one knows about the system. Dahan uses a concrete code example which has some weak points when it comes to flexibility, and demonstrates what it means to make roles explicit and how to do that.

He also responds to questions from the audience during the last third of the session.

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

clarification...... by jack donn

in the code fragment "... ORM.Get<IMakeCustomerPreferred> (customerId)"

is the method .Get<>() a form of generic..? I get the idea but was not familiar with the syntax

Thanks for an outstanding presentation!

<></imakecustomerpreferred>

Re: clarification...... by Udi Dahan

Yes, that's a generic method.
Glad you liked it.

Relation to DCI by Sebastian Kübeck

The approach seems to be similar to DCI...

www.artima.com/articles/dci_vision.html

However, you apply the roles permanently, not context specific as DCI does. As a result, you need workarounds not to loose cohesion. Your naming is different too. You would call the role "TransferMoneySink" "ITransferMoneyFromSource" but the idea is the same. From what I see, DCI could be your next step in enhancing OOP with roles.

Expression problem by Yardena Meymann

I am only about half-way through the presentation, but it reminds me a lot of the expression problem (revisited by Mads Torgersen) and Odersky/Zenger's Scala solution using traits.

Sounds like Qi4J too me by Geert Pante

www.qi4j.org

Principles

Composite Oriented Programming builds on some principles that are not addressed by Object Oriented Programming at all.

* Behavior depends on Context
* Decoupling is a virtue
* Business Rules matters more.
* Classes are dead, long live interfaces.

What is value gained by the coupling... by Pete Kirkham

between the thing which you get from the environment which has the role 'make a customer preferred' and the customer? (the UML diagrams show Customer implements IMakeCustomerPreferred) Why does 'Customer' implement this? Do you ever down cast to 'Customer'? There's an obvious overhead in terms of all the ORM stuff to marshal the orders in and out of the DB to mutate them rather than implementing the role in terms of of the DB, as well as the obvious disadvantages of making the Customer less cohesive. Are there any advantages?

Re: What is value gained by the coupling... by Udi Dahan

> Why does 'Customer' implement this?

Because the 'Customer' class is responsible for if/when it can be made preferred - for instance, if the customer is already in the 'delinquent' state (doesn't pay their bills), it cannot be made preferred. There are other rules encapsulated in that class.

> Do you ever down cast to 'Customer'?

Haven't had to yet.

> rather than implementing the role in terms of of the DB

It sounds like you find that implementing this kind of logic in the DB is preferable. I've found that keeping the logic in code makes it easier to unit test (which is very valuable when one has many interacting rules).

Hope that's clearer.
-- Udi

Re: What is value gained by the coupling... by Pete Kirkham

> > Why does 'Customer' implement this?

> Because the 'Customer' class is responsible for if/when it can be made preferred - for instance, if the customer is already in the 'delinquent' state (doesn't pay their bills), it cannot be made preferred. There are other rules encapsulated in that class.

That information should be in the data model. I'd tend to make such rules explicit. It's the customer's handler which decides that, not the customer (ie the customer does not have autonomous responsibility for deciding whether it is delinquent).

> > Do you ever down cast to 'Customer'?

> Haven't had to yet.

That's a big clue that you don't need the coupling. I prefer objects which do one thing and one thing only; if nothing in the logic says it's a customer, and its only role is to apply a rule to a customer's orders, then it can be separate.


> It sounds like you find that implementing this kind of logic in the DB is preferable.

Not particularly, but much of the discussion was how to work around the overheads in terms of (memory) performance which are associated with making the thing which is performing the transformation on the data relating to a customer, how you then had to duplicate the mapping code, then tell the mapping code about what was calling the mapping code and what would be done with the objects it returns. That seems a very large number of hoops to go through for a very simple data update.

In a good OO design, the client code shouldn't care where that functionality is implemented. Since the code doesn't need it to be a Customer, and there is a performance problem, moving the implementation closer to the data would eliminate the problem with minimal work.

I do tend to use loosely-coupled active, autonomous objects for the process, and leave data as data. In the pre-computer world, the customer doesn't have orders - orders are recorded in a file, and if the company makes the customer prefers, some clerk updates the orders to add a discount. The clerk checks the customer's status, and does the work. Nothing in the system cares about the clerk's identity - she could be a temp taken on just for that single task (ie a temporary object). It's not the customer's role to update the company's record of the customer's orders or check the customer's credit record - if a customer could could do that, they all would have perfect credit and 100% discounts.


> I've found that keeping the logic in code makes it easier to unit test (which is very valuable when one has many interacting rules).
Moving code for performance reasons sometimes doesn't always fit with unit tests. On the other hand, I've found the single responsibility rule very valuable in managing complexity - unit testing an object with a single responsibility is usually easier than unit testing several interacting rules.

"Making Roles Explicit" style when working with legacy code by Alexey Sorokin

What I want to share with you - is that this style of explicitly
describing of what your code is in the code itself has also great
advantages when you're working with legacy code.

Of course, I'm writing all new code using this style, but actually I
realized the great benefits of such approach when I were working with
legacy code. And in the meaning of term "legacy" I rather agree with
Michael Feathers - "people are writing legacy code right now" and "the
main thing that distinguishes legacy code from non-legacy code is
tests, or rather a lack of tests".

My story is: I've joined to existing .NET project. It is a GUI desktop
application that, simply speaking, able to subscribe to some kind of
messages from some server and to show this messages in grid. And my
task was to implement some new kind of subscription.

The example:
Within the project we have the class named Controller. But after I
analyzed this class I realized that it's a much more than a Contoller
(in a bad sense of course). The code in that class also establishes
connections and sends some bytes and manipulates some UI controls
directly. So as a TDDer I never change code without changing first (or
writing from the ground in this case) a unit-test. But as you can see
there is no way that you can write unit-test on such a piece of code.
And also there is no way that you can refactor this code without test
and do not break something. This code is so complex that you cannot
fully understand it and you even shouldn't try - because you easily
miss something and it will be the illusion of understanding. But the
task must be done. And it is exactly where the interfaces come to
help.

With help of interfaces I able to write a unit-test on some piece of
behaviour of that huge complex class with very small changes. And
these changes is rather "just some typing" as you said in your
presentation, not some big efforts (because big efforts can easily
break existing behaviour). And very first step to this - is to admit
all bad things in our code and express it in the code itself. So I did
it (in context of my current task of course):

public class Controller : ISubscriptionService, ISubscriptionView
{
ISubscriptionService subscriptionService;
ISubscriptionView subscriptionView;
...
}

and in the code that creates the Controller class:

Controller controller = new Controller();
controller.RegisterSubscriptionService(controller);
controller.RegisterSubscriptionView(controller);

Some crazy code at first look. Yes it is, but it is only the admitting
of what already exists.

After that I used a few "extract method" refactorings to separate
thing. I think it is quite safe refactoring, and doing it carefully
you don't break anything. But the key point here, is that in method
Subscribe (that I'm going to cover by unit-test and change after that)
I'm using extracted method through these interfaces. For example:


...
try
{
subscriptionService.SendSubscribeCommand();
subscriptionView.ShowSuccessMessage();
}
catch
{
subscriptionView.ShowErrorMessage();
}
...
subscriptionView.AddRowToGrid();
...

and now I'm able to write unit-test to cover behaviour of just
Subscribe method using NUnit and NMock for interfaces for example.

So all of this became possible when I explicitly express the roles in
my code, even if they badly intermixed. Going further I can
step-by-step separate all responsibilities - now it's only the matter
of moving pieces of code from class to class, or maybe re-arranging
method within interfaces.

Re: by Udi Dahan

Alexey, thanks very much for sharing your experiences.

IWonderAboutInterfaceNames by Steve Freeman

A nice talk and good to see a focus on Roles presented to a new audience.

I'm wondering about the style of the interface names, in that they bind the functionality to the Customer by name, so they lose context-independence without the benefit of compilation checking. Are you doing that to help the ORM pick up the right object?

Longer version at www.m3p.co.uk/blog/2009/04/27/spreading-the-wor...

S.

Web application by Tom Revans

Hi,

Great web presentation. Do you have any code examples, even very basic ones you could post? For instance, if I have a home page of a website obviously I want to display lots of different information, do I expose many services and call them from the application or do I call a single service e.g. something like IGetHomePage - What would advise here?

Re: Sounds like Qi4J too me by Rickard Öberg

Yes, Udi just made a great sales talk for Qi4j. I realized that this is the only way to make sense of a complex domain model back in 2002. Now those ideas are implemented in Qi4j, and it allows you to model your entities using only interfaces, implemented by mixins.

And this is a big difference between Udi's version and Qi4j: it seems like Udi will get multiple physical objects, which will map to the same id, but are not really one object, runtimewise or modelingwise. They are just a bunch of completely separate objects which happen to map to the same id in the database.

In contrast, in Qi4j each Entity Composite that has all of these interfaces (in my current project each Entity has about 10-15 interfaces, easily) is a single object, so you can cast from one interface to another if you have to. Using .equals() works properly. And many other things. What Udi is saying is a good way to wake up from this (as he put it, quite correctly) egocentric way of modeling without explicit roles, and look for other ways to do it. Qi4j I think is a logical next step after you do what Udi talks about, and as others have pointed out, DCI is then the logical next step to get a more formalized way of thinking about it. My next talk at the Oredev conference is "DCI in practice", showing how to use Qi4j to implement DCI principles. Please stop by if you have the chance :-)

slides by Martin Menke

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

14 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT