Search
Sitecore defensive coding practices
I recently inherited a Sitecore solution which, after some review, I found to contain what I like to call "Future Adam is going to hate me" code, i.e. code which is easy to hammer out for a deadline, but often quite brittle, difficult to maintain, and which I will ultimately kick myself for writing.
As I begin to remedy the solution I've taken over, some patterns have started to emerge that I thought would be good to share. These are very simple practices that are easy to adopt and employ on a regular basis. Obviously you, dear reader, already write flawless code, but perhaps you have a "friend" who may find some value in the tips below.
1. Always check if an item is null
This is just good practice in general, but even more so when writing code for Sitecore as it is often the #1 reason for a YSOD. Any time you use Database.GetItem() or any other item-retrieval methods, you should always check whether or not the retrieved object is null. For instance:
Item item = Sitecore.Context.Database.GetItem("MyItemGUID or MyItemPath");
if (item == null)
return;
//continue on safely
Never (ever) assume that the item you are retrieving exists (yes, even that static, fixed item that no one is supposed to touch). Other users can and will delete or move the item you thought was there but now isn't.
2. Use the Sitecore.Data.Items.Item field collection indexer to retrieve field values instead of Field.Value whenever possible
If you just need the string value of a field, use the Item field collection indexer like so:
string fieldValue = item["FieldName"];
as opposed to
string fieldValue = item.Fields["FieldName"].Value;
The former will always return a string value, even if the field doesn't exist. Basically, this shortcut null checks the requested field for you. The latter will throw a null exception if the field you're requesting doesn't exist in the item's field collection.
So unless you're also checking a field for existence before attempting to access it's value, it's safer (and requires less code) to use the item's field collection indexer to retrieve a field value. Here are expanded examples to demonstrate the efficiency of the first approach vs the second approach:
string fieldValue = item["FieldName"]; if (fieldValue == string.Empty) return; //continue on safely
vs
Field f = item.Fields["FieldName"]; if (f == null) return; string fieldValue = f.Value; if (fieldValue == string.Empty) return; //continue on safely
Again, this approach is largely relevant when you just need the string value of a field. If you need strongly-typed access to field values, then you'll need to cast the field to the proper field type and retrieve the value using the relevant field type properties.
3. Minimize usage of hard-coded field names and item GUIDs
Hard-coded field names and item GUIDs make for hard-to-maintain code. For instance, if a field name changes for a given template, you need to find all references to that field name in ALL of your code. Sure you can try to use find and replace but that's a process which is tedious, cumbersome and often leads to unhandled runtime errors.
At the very least you should have a single reference point for all field names and item GUIDs in your code. While it's hard to avoid hard-coded field names and item GUIDs completely, having them in one place means you only have to change them in one place when the time comes (and it will). A better approach, though, is #4:
4. Use object mapping, domain modeling, item decorating, etc..
If you're not using some form of object mapping, domain modeling or item decorating for your Sitecore solutions yet, I strongly urge you to spend some time getting familiar with the various patterns/approaches and consider using one for all future projects. Any of these patterns/approaches will help you write cleaner, more maintainable code. There are a number of tools available to help you on your way, which I've listed below. Keep in mind these are just the tools I'm aware of, there are probably more.
- Custom Item Generator (my personal favorite)
http://trac.sitecore.net/CustomItemGenerator - Glass Sitecore Mapper
http://trac.sitecore.net/GlassSitecoreMapper - CorePoint.DomainObjects
http://trac.sitecore.net/DomainObjects - DataItemGenerator
http://trac.sitecore.net/DataItemGenerator - CompiledDomainModel
http://trac.sitecore.net/CompiledDomainModel
This isn't an exhaustive list by any means and I'll keep adding to it as I think of more. In the meantime, if you have a suggested practice please post a comment and I'll consider adding it to the list.