Mark Needham

Thoughts on Software Development

Coding: Missing abstractions and LINQ

with 8 comments

Something which I've noticed quite a lot on the projects that I've worked on since C# 3.0 was released is that lists seem to be passed around code much more and have LINQ style filters and transformations performed on them while failing to describe the underlying abstraction explcitly in the code.

As a result of this we quite frequently we end up with this code being in multiple places and since it's usually not very much code the repetition goes unnoticed more than other types of duplication might do.

A typical example of this might be the following:

public class SomeFooHolder
{
	public List<Foo> Foos { get; set }
}

An example of how this might be used is like so:

var someFooHolder = new FooHolder(...);
someFooHolder.Foos.Select(f => f.Completed);

That code would typically be repeated in other places in the code where we want to get all the completed foos.

Although it's a simple change, as a first step I prefer to make that concept more explicit by putting 'CompletedFoos' on 'SomeFooHolder':

public class SomeFooHolder
{
	public List<Foo> Foos { get; set; }
	public List<Foo> CompletedFoos 
	{ 
		get { return Foos.Select(f => f.Completed); }
	}
}

Perhaps an even better solution would be to create an object 'Foos' to encapsulate that logic further:

public class Foos
{
	private readonly List<Foo> foos;
 
	public Foos(List<Foo> foos)
	{
		this.foos = new List<Foo>(foos.AsReadOnly());
	}
 
	public Foos Completed
	{
		get { return new Foos(foos.Select(f => f.Completed)); }
	}
}

As I've written about previously I prefer to wrap the list rather than extend it as the API of 'Foos' is more expressive since we don't have all the list operations available to any potential users of the class.

Written by Mark Needham

January 17th, 2010 at 7:09 pm

Posted in Coding

Tagged with ,

8 Responses to 'Coding: Missing abstractions and LINQ'

Subscribe to comments with RSS or TrackBack to 'Coding: Missing abstractions and LINQ'.

  1. [...] Coding: Missing abstractions and LINQ – Mark Needham looks at encapsulating the business logic that often leaks out with the power of Linq, capturing it inside classes rather than having Linq statements dotted around your code. [...]

  2. Interesting post – I agree that we tend to duplicate LINQ expressions quite often. If I find I'm re-using a LINQ expression I usually write a custom filter (extension method) and then simply re-use the extension method. The cool part about this approach is that you can unit test the filter and your code also becomes much more readable.

    For example, you might write

    users.WithId(5) instead of users.Single(u => u.Id == 5)

    Jaco Pretorius

    18 Jan 10 at 9:52 am

  3. I agree with Jaco. When the LINQ expression is fairly simple and used frequently, then writing an extension method makes good sense. However, when the expression is complicated or composed of multiple, perhaps reusable parts, I like the Specification pattern: http://martinfowler.com/apsupp/spec.pdf

    For example:

    someFooHolder.Foos.Meets();

    or

    someFooHolder.Foos.Meets(new CompletedFooSpecification());

    That may seem more involved – and it is. However, the specification pattern can give you (more) Separation of Concerns and composability, if you *need* it. If not, then extension methods is an good choice.

    Jordan Terrell

    18 Jan 10 at 3:55 pm

  4. Looks like the commenting engine striped out some of my example. This first example should be:

    someFooHolder.Foos.Meets ();

    Hope this doesn't get striped out also!

    Jordan Terrell

    18 Jan 10 at 3:57 pm

  5. Maybe there is a good opportunity for Dynamic here :)

    Something that converts the method name into the appropriate lambda dynamically… too magical?

    Aaron Erickson

    18 Jan 10 at 3:57 pm

  6. And it did! DOH! One more time, with HTML escape sequences ;-)

    someFooHolder.Foos.Meets<CompletedFooSpecification>();

    Jordan Terrell

    18 Jan 10 at 3:58 pm

  7. @Aaron yeh that would work quite well in this situation as you say. How would this type of thing work in Ruby?

    Mark Needham

    18 Jan 10 at 10:58 pm

  8. No idea – I don't write Ruby often :/

    But inheriting your base from DynamicObject I can easily imagine how this will work.

    Aaron Erickson

    19 Jan 10 at 2:24 pm

Leave a Reply