Friday, 23 January 2009

Returning an empty list or null?

In my data access classes, which is using Linq2Sql I have functions like GetAllTournamentsByGuid().
A Tournament is a set of competitions in golf, see www.invitationaltour.com if you want to know what this project is all about.

Well, at first I wrote the test for this function, from a TDD perspective, like this;

The test is pretty straight forward, it saves two tournaments to the database with a specific owner, created earlier, then it calls the data layer and tries to get these two tournaments from the database.

[Test]
 
public void CanGetAllTournamentsByOwner()
{
  //Save two tournaments to db
  User owner = tournament.Owner;
  dataManager.SaveTournament(tournament);
  dataManager.SaveTournament(tournament2);
  
  //The actual test
  System.Collections.Generic.List<Tournament> tournaments = 
   dataManager.GetTournamentsByOwnerGuid(owner.Guid);
 
  Assert.That(tournaments.Count,Is.EqualTo(2));
  
  //Clean up is performed in the teardown routine
}

This test works well and passes when run, but what if there are no tournaments in the database, what if I want to get tournaments for a owner that does not have any tournaments? Should the function return an empty List<Tournament> or null? Or should the function return a Boolean value telling the caller if the call to the database was successful and the returning List as an output parameter or as a ref List?

I have struggled with this question for a long time during the development of various systems, and I have two ground rules, which are them self fights with each other.

1) Never throw exceptions if not needed.
Exceptions are resource intensive, compare to regular code. If you know that something can go wrong you should be able to create code that prevents that error, with validation etc. I’ve started to reconsider this rule. If the system I’m building is not that performance intensive. But I still apply this rule through out my systems.

2) Don’t return null.
Actually, I’ve adopted this rule while reading the book Clean Code by Robert C. Martin (Uncle Bob) where he writes that functions should never return NULL. Well, I’m starting to disagree.
The book states very clearly that the book is not the law, it is a book about clean code and suggestions, and there is nothing wrong with making other rules than stated in the book, so this is not a flame about the book, I love that book!

I’m rambling again….. Back to the problem

What if the function doesn’t return any tournaments? Should i return an empty List<Tournament> with a count of 0? I think I’ve decided that the return value should be NULL. The main reason for that is if this function is called via a service, a NULL value is less to serialize than an empty List of Tournaments.

What if an exception occurs? Well, I will re throw it in the function, but wrap the exception in an own exception class, which is better for serializing. This will make up the signature for the core function of gettournaments. It will be the callers responsibility to handle any exceptions.

What about returning a Boolean value indicating if the operation was successful. No problem! If I need a function that never throws an exception back to the caller I will create a wrapper function, but I will only make that function if I need it. One of the pillars in agile development is not to code functions until you need it, and it is also the third rule of TDD; only create code to pass the unit test. It also apply to the rule, from Clean Code, that a function should be responsible for one, and only one, thing!

So, to summarize:

- The functions that get entities from the repository will return null if no result aren’t found.

- The functions that get entities will throw exception if any thing goes wrong, it is the callers responsibility to handle exceptions.

- If a function is needed that doesn’t throw any exceptions, instead it should return a Boolean telling if the operation succeeded a wrapper will be created around the core getter function with an out parameter for the entity or the list of entities.

Labels: , , ,

kick it on DotNetKicks.com

5 Comments:

Anonymous Anonymous said...

Wrong, wrong, wrong. So wrong. Absolutely wrong.

You're deciding to go against standard, accepted programming practices because of some supposed performance gain by sending back null rather than an empty collection?

Why not just drop the connection? You don't have to send back anything. Save on tons of bandwidth, right?

Knuth is coming to kick your ass, and I'm bringing the popcorn.

23 January 2009 15:42  
OpenID sirrocco said...

+1 for Anonymous :)

23 January 2009 15:51  
Anonymous Paul A Houle said...

I'm with Anonymous on this one.

Null is nothing but trouble in mainstream languages. It forces you to either (i) write more code, or (ii) have to deal with exceptions because you didn't write the extra code.

23 January 2009 16:04  
Blogger Christian Engel said...

Well, the example with services was just an exampel. There are also cases where it is a windows application with a local repository. What the interface is to the service is another thing, I meant that the low-level function should return null. Then, when and if, I apply a service layer i will have a wrapper function for this function. In this case I might have specific functions to ask the system if a user has any tournaments, if there are any tournaments at all etc. But I still think that the low level function will return null.

23 January 2009 16:05  
Blogger Christian Engel said...

I do get, and in some ways agree, with you, returning Null, as you said, forces you to write more code to check for null values. But returning a list with zero items also demands code to check if the list contains any thing. It depends what you want to do with the list. In this project, which is a hobby project, I tend to use null values the closer I get to the database, and empty lists the closer I get to the GUI. What do you think about single entities? If I want to get a single entity, and there is no one. Say that I want the top 1 tournament for a user, and there is none. What would you return?

23 January 2009 16:18  

Post a Comment

Links to this post:

Create a Link

<< Home