Mark Needham

Thoughts on Software Development

OOP: What does an object's responsibility entail?

with 5 comments

One of the interesting discussions I've been having recently with some colleagues is around where the responsibility lies for describing the representation of an object when it is to be used in another bounded context – e.g. on the user interface or in a call to another system.

I believe that an object should be responsible for deciding how its data is used rather than having another object reach into it, retrieve its data and then decide what to do with it.

Therefore if we had an object Foo whose data was needed for a service call to another system my favoured approach would be for Foo to populate the FooMessage with the required data.

public class Foo 
{
	private string bar;
 
	public Foo(string bar)
	{
		this.bar = bar;
	}
 
	public void Populate(IFooMessage fooMessage) 
	{
		fooMessage.Bar = bar;
	}
}
public interface IFooMessage 
{
	string Bar { get; set; }
}
public class FooMessage : IFooMessage
{
	public string Bar { get; set; }
}

The advantage of this approach is that Foo has kept control over its internal data, encapsulation has been preserved. Although we could just expose 'Bar' and make it possible to build the FooMessage from somewhere else, this violates Tell Don't Ask and opens up the possibility that Foo's internal data could be used elsewhere in the system outside of its control.

The question to be answered is whether or not it should be Foo's responsibility to generate a representation of itself. In discussion about this it was suggested that Foo has more than one responsibility if we design the class as I have.

Uncle Bob's definition of the Single Responsibility Principle (SRP) in Agile Software Development: Principles, Patterns and Principles describes it thus:

A class should have only one reason to change.

In this example Foo would need to change if there was a change to the way that it needed to be represented as an IFooMessage as well as for other changes not related to messaging. Foo is not dependent on a concrete class though, only an interface definition, so the coupling isn't as tight as it might be.

It might just be my interpretation of SRP but it seems like there is a trade off to be made between ensuring encapsulation and SRP in this instance.

The other way to create a FooMessage is to create a mapper class which takes the data out of the Foo class and then creates the FooMessage for us.

We might end up with something like this:

public class FooMapper 
{
	public FooMessage ConvertToMessage(Foo foo) 
	{
		return new FooMessage { Bar = foo.Bar; }
	}
}

Whereby Foo needs to expose Bar as a property in order to allow this mapping to be done.

This is somewhat similar to the way that NHibernate handles the persistence and loading of objects for us – unless we use the Active Record pattern an object is not responsible for saving/loading itself.

What I don't like about this approach is that it doesn't strike me as being particularly object oriented – in fact the mapper class would be an example of an agent noun class.

A cleaner solution which allows us to keep encapsulation in tact would be to make use of reflection to build the FooMessage from our mapper, probably by creating private properties on Foo as they are easier to reflect on than fields. The downside to the reflection approach is that code written in this way is probably more difficult to understand.

I know I've oversimplified the problem with my example but ignoring that, where should this type of code go or do we choose to make a trade off between the two approaches and pick which one best suits our situation?

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • HackerNews
  • StumbleUpon
  • Twitter

Written by Mark Needham

February 9th, 2009 at 4:52 pm

Posted in OOP

Tagged with

5 Responses to 'OOP: What does an object's responsibility entail?'

Subscribe to comments with RSS or TrackBack to 'OOP: What does an object's responsibility entail?'.

  1. Hee hee – good old object orientation. Clearly you should trade and trade and trade. Then go with the supportive one.

    In practice, I

    a) rarely rely on one pattern to guide a design (no, really Mark), or
    b) consider design to be a static thing.

    So if you can evolve comfortably from literal message creation to domain model, then you're going in the right direction. Whatever path you took to go there will be reflected in your design. Each path is valid.

    My main concern is that you focus on one design pattern. I think that having parallel class hierarchies is a smell. If I find myself creating class A and class AMapperForSystemX, and AMapperForSystemY, I'll probably look for duplication, and remove it.

    DRY may be SRP's natural enemy…

    However, I think it's fine to use mappers too, except I'll delegate to a communication strategy:

    class A {
    CommunicationPolicy cp;
    populate( Message msg){
    cp.populate( this, msg )
    }
    }

    where the communication strategy knows how to map and send the message.

    So clearly you can have your cake and eat it.

    My preferred option is to drive everything from the domain object, and use layers of abstraction to remove duplication or defer committing to a particular design.

    Regarding SRP:

    Does it just mean I have to encapsulate what I mean by "One thing?", so rather than "it changes if A or Msg changes", I phrase it as "it changes if the relationship between A and Msg changes" (which is still one thing).

    Nick Drew

    9 Feb 09 at 10:45 pm

  2. [...] Is What I Work For and OOP: What Does an Object's Responsibility Entail? and Agile: What Is It? (Mark [...]

  3. I personally think that the SRP is a poor principle for object orientation in general. Part of the problem is that it's too vague. There are certainly objects that represent 2 distinctly different concepts and should be split, but take strictly, I think SRP leads to objects that are overly simplistic and break encapsulation (you'll often notice this when you see object's who's name ends in a verb or agent noun).

    That being said, if having an object create representations of itself gets too complicate, either messages or for the UI, then I would try to split it out in some way (like using presenters for views).

    In general, I dislike using reflection in java. The reason we suffer it's verbosity is for it's static analysis and typing, and if we take that away, we end up with some half crippled bloat language that doesn't do either static or dynamic well.

    Kris Kemper

    10 Feb 09 at 3:48 am

  4. @Nick Drew

    To use this strategy, you will still have to change the encapsulation and make bar public.

    Karsten

    12 Feb 09 at 12:03 am

  5. Perhaps this would be useful?
    http://www.codeplex.com/AutoMapper

    Karsten

    12 Feb 09 at 10:50 pm

Leave a Reply