BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Presentations Making Roles Explicit

Making Roles Explicit

Bookmarks
58:51

Summary

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.

Bio

Udi Dahan is The Software Simplist, a Microsoft Solutions Architect MVP. He is a member of the International Speakers Bureau of INETA, an International Association of Software Architects (IASA) associate, an editor for the SOA and .NET communities on InfoQ, and a Dr. Dobb's sponsored expert on Web Services, SOA, & XML.

About the conference

QCon is a conference that is organized by the community, for the community.The result is a high quality conference experience where a tremendous amount of attention and investment has gone into having the best content on the most important topics presented by the leaders in our community. QCon is designed with the technical depth and enterprise focus of interest to technical team leads, architects, and project managers.

Recorded at:

Apr 09, 2009

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.

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

Community comments

  • clarification......

    by jack donn,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

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

  • Relation to DCI

    by Sebastian Kübeck,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    > 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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    > > 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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Alexey, thanks very much for sharing your experiences.

  • IWonderAboutInterfaceNames

    by Steve Freeman,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    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,

    Your message is awaiting moderation. Thank you for participating in the discussion.

  • Nothing new is under the Sun

    by Vadim Samokhin,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I guess that's what Rebecca Wirfs-Brock told about in her book Object Design: Roles, Responsibilities, and Collaborations. Though she hasn't stated that one should define an interface for each role, but it's an inevitable and absolutely reasonable consequence of applying the technique she introduced to find good objects.

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

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

BT