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