Recommended Practises, Search

Why does my Sitecore website perform so badly?

After many years of doing a lot of reviews on Sitecore I would conclude that it more or less always comes down to one single thing when pages perform badly: bad code. And when I mean bad code, I mean code iterating an excessive amount of items.

Iterating A LOT of items

Previously we used to see a lot of calls to descendants when solutions were using axis, xpath or Sitecore Query, but luckily this is a disappearing trend with the introduction of Sitecore Search in Sitecore 7. This does not mean that there are less bad code – maybe even on the contrary. The use of ORM and abstractions in many solutions means that layers of code can easily hide item iterations. Neither of the two patterns or technologies are inherently bad, but they do provide means to hide “bad code”.

The ARGH! Example

The example in the diagram below is from a customer here in Australia which had a problem with a very slow running product search. The diagram breaks down the different parts of the search page and describes the functionality and number of items hit by each part. It was part of the presentation to the client to highlight where the performance bottleneck was (and that Sitecore itself was not cause of the problem).

After looking through layers and layers of code (3000+ lines to be more specific), we discovered that the code in the different layers were searching Lucene and iterating search results, loading the items individually and recursively running business logic.

A simple search resulting in a page of 50 links would easily take up to 5 minutes, simply because the code was iterating in excess of 1.7 mio items from the Sitecore database –  which would take time in any solution 🙂

Excessive Item Iterations

To cut the very long story short: always keep an eye on number of items being iterated – and never rely on caching to do the trick.

Standard
.NET, New releases, Sitecore

Will dynamics in .NET 4 change the way we do Sitecore?

I am spending my time these days walking the halls of Berlin Messe at the Microsoft TechEd 2009. One of the interesting upcoming features of .NET 4 is the introduction of dynamic language support in the .NET Language Runtime. This does not only mean that you can write your .NET code in dynamic languages such as Python (IronPython) and Ruby (IronRuby), but also that you can use some of the dynamic features from C#. With the introduction of the dynamic type keyword, method calls and member access can be evaluated at runtime instead of at compile time (previously known as late-binding). This does not mean that C# is no longer a type safe language, it merely means that the language now provides a more “syntax correct” way of accessing those dynamic types of data, we previously used to access via strings, invokation, reflection etc. Examples of dynamic data models includes COM, the HTML DOM and XML.

Another one of the dynamic types of data we all works with each day, is Sitecore. The structure, i.e. templates and fields, we are coding up against changes constantly, and Sitecore provides a string based way to access specific items and fields and values in fields. Some of these dynamic types are exposed via classes in the Sitecore API, e.g. the fields type classes in the Sitecore.Data.Fields namespace. In Pentia we have a concept we call Sitecore wrapper classes, i.e. classes which we custom write to provide a proper interface to items of a given template. Writing these classes are tedious and potentially error-prone, which is why we are working on code generator for generating these classes (similar to e.g. LINQ to SQL). But with dynamics in .NET 4, we have a way of eliminating these classes completely, while still maintaining a proper syntax – and hopefully Sitecore will implement this to our common advantage. Here is an example of how code from the current version could look in a future version of Sitecore:


//BEFORE: .NET 3.5 Framework, Sitecore 6
public string GetContextItemDocumentImage() {
  Item item = Sitecore.Context.Item;
  ImageField field = ((ImageField)item.Fields["DocumentImage"]);
  return field.Src;
}

//AFTER .NET 4 Framework, Sitecore 7?
public string GetContextItemDocumentImage()
{
  dynamic item = Sitecore.Context.Item;
  return item.DocumentImage.Src;
}

Note that although the syntax differs, the actual functionality executed in both example would be the same. So, what does it require from Sitecore to do this? The secret lies in the System.Dynamics. IDynamicMetaObjectProvider interface or more easily, the DynamicObject class. This interface and class allows the derived class to provide its own resolving to e.g. members access and method calls via a number of virtual methods. The methods are Try based, which means that you should return false if the functionality is not supported, or e.g. a method with an invalid method is called. Some of the most important virtual methods which can be implemented via DynamicObject are:

TryConvert

A cast is attempted, trying to convert the dynamic type to a static.

TryGetIndex

An indexer is called, trying to get a value with a given id or index.

TryGetMember

There is an attempt to get the value of a named member (e.g. a field or property)

TryInvokeMember

A method with a given name and parameters is invoked.

TrySetIndex

There is an attempt to set the value in an indexer with the given id or index.

TrySetMember

There is an attempt to get the value of a named member (e.g. a field or property)

 

An example of the above Sitecore 7 (:-)) implementation could therefore be:

namespace Sitecore.Data.Items
{
  public class Item : DynamicObject //...and other interfaces
  {
    //...
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
      dynamic field = Fields[binder.Name];
      if (field != null) {
        result = field;
        return true;
      }
     	return base.TryGetMember(binder, out result);
    }
    //...
  }
}

Let this be an inspiration to Sitecore for the next version – I for one truly hope we see something like this in the product.

Standard