Thursday, February 12, 2009

Prefer IEnumerable<T> to IList<T> for Public Members

A coworker of mine knew vaguely of my preference for IEnumerable<T> over IList<T> for exposing collection members of a class. He needed to expose a collection and its count somehow, and asked me what I thought. Here it is:

I prefer IEnumerable<T> to IList<T> for the following reasons.

IEnumerable<T> is the lowest common denominator of collections, but still very useful as it is foreachable.

Because it is the lowest common denominator, my backing collection can be any number of specific collection types, including an array.

It is easy to return an empty, ad hoc, 'light-weight' enumeration: Enumerable.Empty<T>().

I can even not have a backing collection, and instead implement the enumeration in code using the yield keyword.

IList<T> has methods like Add() and Insert() and in most API situations I don't want clients adding members to my collection - IEnumerable<T> is immutable.

IEnumerable<T> is easily managed by Linq extension methods, e.g.

IEnumerable<IWidget> widgets = someObject.GetWidgets();
int count = widgets.Count();


Note that Count() is a method, not a property. It is an extension method (C# 3.0) that you have access to when you use System.Linq. The implementation, which you can see in Reflector, amounts to foreaching over the enumeration and incrementing a counter. It is efficient as it can be and we don't have to write it over and over.



It is simple to get an IEnumerable<T> into a List<T>:



List<IWidget> widgetList = new List<IWidget>();
widgetList.AddRange(widgets);



IEnumerable<T> is very composable - the new Linq extension methods allow you to do all sorts of magic with them - filtering, sorting, grouping, aggregation all chained together in a single line of code. IList<T> gets that too because it descends from IEnumerable<T>, but its pretty cool that the lowest common denominator collection gets this stuff.



The most persuasive argument is the one regarding clarity of the API. In every case I can think of, a collection property should present immutable interface, and IList<T> is mutable. If I thought I had a scenario where the client should be able to futz with my internal collection, I'd revisit my design because I probably have it wrong. IEnumerable<T> wins because it is clearly immutable.



There are alternatives that permit an IList<T> implementation that doesn't permit appending or inserting, but they're liars. For example List<T>.AsReadOnly() returns a ReadOnlyCollection, which implements IList<T>. But it lies. It has Add() and Insert() methods, but they always throw NotSupportedException. For me, it's a non-starter because the interface is misleading.



You could also just return a copy of your internal collection, something like this:



public IList<IWidget> Widgets
{
get
{
IList<IWidget> temp = new List<IWidget>();
temp.AddRange(_widgets);
return temp;
}
}


But I think this is just as misleading. Sure, you can honestly add and remove items, but it implies that it is the internal collection when it really isn't. Again, IEnumerable<T> wins because it makes the API clearer.



You may have a nagging concern that you are getting your Count by iterating through the enumerations rather than having and storing it somewhere. I wouldn't worry about it. It all the cases I can think of, this is trading cycles for clarity in the API. Clarity always trumps performance until we know or at least have a realistic expectation of a performance issue.

But even then, you needn't worry. Because wherever possible, these extension methods on IEnumerable<T> try cast it to a higher level collection to optimize the code. So the Count() extension method tries to cast the target to ICollection<T> so it can use the Count property. Only if it can't do that does it actually iterate through the enumerable to get the count. Check it out in Reflector.



IEnumerable<T> is a clear first class citizen with the addition of all those nifty new extension methods in System.Linq. And even without those, it should be the first choice for exposing an immutable collection.

Thursday, January 29, 2009

Clean Code

One of my refrain's at the recent SoCal Code Camp was "Simple Code."  I was inspired by Scott Bellware's recent appearance on Hanselminutes where he equated simplicity with easy testability.  It is a great podcast, and highly recommended.  Ultimately the point is that we want the code we touch to become more simple.  That is, more easy to understand, more easy to explain, more easy to change and more easy to test. 

CleanCode  Well, Robert C. Martin (Uncle Bob) recently published a new book called Clean Code: A Handbook of Agile Software Craftsmanship which seems to be concerned with similar themes.  I'd had it on my radar since Uncle Bob did a .NET Rocks a few months ago but hadn't gotten a copy yet.  There's always more books than I have time for, particularly lately.

But after my code camp sessions, Vladimir mentioned that he was participating in a study group going through Clean Code.  I had never heard of programmers doing such a thing, but it sounded great.  I liked the notion of the added accountability that comes of joining a group project.  "Hmmm," I thought, "that might be a great way to really learn a book." 

A couple of days later when I asked Vladimir to let me know how the study group went, he surprised me with an invitation to join.  So I went out and got a copy and started in on it. 

My first 'meeting' was today, over the phone.  And it was great.  The whole conference call thing isn't real high on my list, but the book is solid and the discussion really added to it. 

One meeting down and I think this has real promise.  Uncle Bob is great, but Uncle Bob supplemented by a roomful of experienced software developers is a real treasure.

So I'll be attending, every Thursday at noon.  Since I want to make sure I keep up my end of the discussion, I'll be taking copious notes as well.  I'd like to find some way to turn them into blog posts too.  so stay tuned and see what unfolds.

Monday, January 26, 2009

SoCal Rock and Roll Code Camp 01/2009

Thanks to all of you who made it to my Dependency Injection sessions at the code camp.  I really enjoyed doing the presentation.  This was the third time I've presented this stuff and I've finally got the content into the neighborhood of where I want it, so I'm particularly satisfied. 

I've gotten my slides cleaned up and saved off my sample code so I can post it on the code camp website.  You can download slides and sample code for each session from its page.  Here they are: Dependency Injection - Why Bother and Fun with Dependency Injection Containers.

I promised some links as well.  Here they are:

Google Testing Blog - This is a great blog with vast amounts of solid practical advice.  It is focused on Java rather than C#, but in most cases that won't be a problem.  The principles are pretty much the same. 

Particularly recommended here is the Guide: Writing Testable Code which appears to be the standards Google uses in code reviews.  It is full of specific guidance and before and after examples both of code and unit tests.  Again, mostly Java, but for the most part it shouldn't be a problem for C# developers.

The StructureMap site is full of good guidance on Dependency Injection Containers in general as well as StructureMap in particular.

You can find more about Autofac at Google Code.  The wiki is a good source of guidance for Autofac's various features.  Assuming the lambda syntax doesn't still make your brain hurt the samples are pretty easy to comprehend.

Don't forget Castle Windsor.

I spent a lot of time on the Single Responsibility Principle and the Open/Closed Principle.  Robert C. Martin's (Uncle Bob) original articles are available from his web site:  SRP and OCP.

Finally, a few great books:

Agile Principles, Patterns, and Practices in C#

Working Effectively with Legacy Code

Refactoring: Improving the Design of Existing Code

As I said in the sessions, feel free to contact me if you have a question you think I can help you with.  It is a big topic.

Thank you again for attending.  I had a lot of fun.