The art of efficient code

In my last post, I’ve written a simple method to retrieve the youngest child. Lars, colleague Sitecore evangelist, pointed me on my usage of iterators and indexes. So’ve decide to do some optimising on the code. The results when running the code 100 times where unbelievable:

Timing of section ‘Unoptimized’: 436,523636383954
Timing of section ‘Optimized1’: 24,8905936369008
Timing of section ‘Optimized2’: 34,3272678510816

Optimasation1 generally uses only iterators to loop trough the children:

IEnumerator children = parent.Children.GetEnumerator();
children.MoveNext();
Item youngestChild = children.Current as Item;

while (children.MoveNext())
{
if ((children.Current as Item).Publishing.PublishDate < youngestChild.Publishing.PublishDate)
{
youngestChild = children.Current as Item;
}
}

return youngestChild;

I generally dislike the casting of the objects. Guess this could be resolved by taking advantage of the Generics model in the CLR2.0, but for now, collection converting is to expensive.  Introducing a help variable in the while-loop isn’t an option as poping another reference on the stack which will only re-used in 1 of n times will only slow down…

The second optimalisation is written based on the first experiences, but now as main goal constructing readable/manageble code:

Sitecore.Collections.ChildList children = parent.Children;
Item youngestChild = children[0];
foreach(Item child in children)
{
if (child.Publishing.PublishDate < youngestChild.Publishing.PublishDate)
{
youngestChild = child;
}
}

return youngestChild;

The meaningless iterator is replaced by a the ChildList which implements IEnumerable and the while is replaced with a nice foreach loop. Altough you would expect the code to be less optimized(as I walk twice trough the first item, etc), this code is actually faster :P. Results after a rerun (100.000 cycles this time):

Timing of section ‘Unoptimized’: 499207,361270776
Timing of section ‘Optimized1’: 33562,6385476366
Timing of section ‘Optimized2’: 32503,9732703458

The message Sitecore produces because of the page did load a long time was also quite funny ;): 11980 11:10:48 WARN Timing threshold exceeded for web page. Milliseconds: 592527,96. Threshold: 1000. Page URL: /Dummy.aspx

The coolest stuff about this bench is definitelly that I haven’t done any codepath optimalisation. Haven’t looked at a way to improve the algorithm, etc. Guess I can win some additional time altough I can imagine the time spent on those last optimalisations aren’t interesting when you win just below the 2% of this code piece…

Still interested anyway in ways to improve this piece of code / functionality 😛

Selecting your youngest child

In this thread on the SDN5 Forum someone is asking for a way to select the youngest child of an item. I’ve written a quite simple code snap for this:

 

public static Item GetYoungestChildUsingApi(Item parent)
{
if (parent == null)
{
throw new ArgumentException(“The object ‘parent’ cannot be null”);
}

//Check for children
if(parent.HasChildren)
{
//I know the parent has at least one child, select it
Item youngestChild = parent.Children[0];

//Walk trough children starting with child 2
//When tyheir publishing date is lower then the current selected youngest child, set as youngest child
for (int i = 1; i < parent.Children.Count; i++)
{
if (parent.Children[i].Publishing.PublishDate < youngestChild.Publishing.PublishDate)
{
youngestChild = parent.Children[i];
}
}

return youngestChild;
}
else
{
return null;
}
}

 

 But now I’m wondering, is there a way to do the same using XPath :D? Does anyone know? Help me, please!

 

public static Item GetYoungestChildUsingXPath(Item parent)
{
if (parent == null)
{
throw new ArgumentException(“The object ‘parent’ cannot be null”);
}

//Check for children
if (parent.HasChildren)
{
Item youngestChild;

youngestChild = parent.Axes.SelectSingleItem(“query“);

return youngestChild;
}
else
{
return null;
}
}

Notation of templates based on multiple inheritance

So far I’ve seen several people do have a hard time to design their new Sitecore solutions with support for multiple inheritance in templates. Actually, I haven’t got the time to find out some best practices. But so far I’ve found out a way to document Templates and Master  in an easy way. __Standard Values and predefined values in masters aren’t include yet.
Click on the image below and find out how you are able to easily document your solutions. Ideas and suggestions are welcome :)!

You might be wondering if there is a possibility to do this in a structured way with something like Visio? So far? No! Near feature? Possibily. Take a look at this topic, on the brand new SDN5 Forum, and please provide me feedback on building a Sitecore Template and Sitecore Shapes for Visio 2007. 🙂

Community update: SDN5 Forum!

“A small step for a techie a big step in the community!”, with those words, Alexey Rusakov, developer @ Sitecore, opened the brand new community forum on SDN5.

Thank you Alexey and Sitecore for this initiative! Hope we can fully migrate the community from the Yahoo Group to its new place!

Please  fill in your signature, so we know who we are talking to ánd we, implementation partners, can compete a little ;).

You do like XSLT? Use it proper!

One of the most annoying behaviours for a programmer is when someone is using a

language or a method which he isn’t familiar and he directly finds out it’s done in a ugly way. So don’t leave the trash behind you for maintainers bu write proper, nice solutions. Some examples for XSLT, simple stuff to do, but common forgotten are listed below:

  1. xsl:output should be configured correctly
    By default, on creation, the xsL:ouput line, look like this:
    <xsl:output method=”html” indent=”no” encoding=”UTF-8″ />
    When building a valid xhtml you should change the output-method to xml. And do not forget to change the encoding when you create chinese or vietnamese sites ;-). But when you change the encoding, do not forget the encoding in the first line(<?xml ?>)…
    For western sites, this following output line is the most likeliest:
    <xsl:output method=”xml” indent=”no” encoding=”iso-8859-1″ />
  2. Remove unused variables
    By default Sitecore delivers the ‘$home’. When it is unused, remove it. Same for unused parameters. Altough the 4 default Sitecore parameters can be left  there.
  3. Avoid comments in templates
    As templates are most of the time already full with advanced presentation logic, tests, etc, leave comments out of it. Just describe your template above the method.
  4. Avoid templates longer then 10-12 lines
    Xslt is itself more then complex. Guess nearly everybody agrees on that vision. But, as you are able to read here, in some circumstances, it is definitelly usefull. Still, and this one also applies to C#/VB  methods, try to create simple templates, with the simpel guideline that between 10 and 12 lines are the absolute maximum for a template.

Hope this will help you guys a little while using,debugging, documenting and maintaining XSLT-renderings.

5.3 Experiences – Day 2

11:00: Finally got to the work I’ve to do today. Insert templates in our solution. Direct found out that we’ve to document our templates and masters in a different way. Will come back on that topic in a post later today.

11:30: Strange, but it’s definitelly hard to change the base template of a template. You can do it by selecting the template, switch to the ‘View’-tab and unselect ‘Editor’. For those folks who have the same problem. Going to submit it to the support desk. This should be easier.

11:40: Building the template can also be done using CTRL+S.

11:50: Standard Values are applying the same rules as Items created from the Template. This means that validation if a field is filled will also apply to standard values. Grrrr…. Quite annoying!

11:55: Standard Values count as 1 usage of the template. Interesting… 😉

12:10: There are some problems with our design. We are used to the multilink-control which is a control similar to internal-link control, but allows you to select more then 1 link. All of them in a popup. The main advantage against multilink was that it looked visually 10 times better. The treelist is a good replacement, but there are some wishes left:

  1. Source: Possibility to define an XPath query
  2. Bool: show full tree but only allow selected items using the source selected
  3. Startposition of the tree mentioned above

Hope I’ll be able to inherit from the TreeList.

Update:

This afternoon I’ve been busy implementing the template and master design in Sitecore. This took some time as the template manager worked sometime a bit unexpected. A later post , tomorrow, will show how you are able to create a clear notation for templates which take advantage of multiple inheritance.

Getting my 5.3 Playground ready

This article might be only interesting for folks who work with XP…

  1. Create a website called ‘Sitecore 5.3 Playground’
  2. Start installing the latest version of 5.3 on your machine, in for me:
    D:\NET Development\Sitecore project\Sitecore 5.3 Playground\
  3. Point the webroot of the site, created by 1 to your %installdir%/Website/
  4. Launch the site, do some trouble shooting depending on which database should do the tric.
  5. As a best practise, create a new account for yourself and set the admin password to some othervalue then string.Empty :).
  6. Create an Web Application project in your default VS2005 folder(for me: C:\Documents and Settings\agr\My Documents\Visual Studio 2005\Projects) with the name: SitecorePlayground.
  7. Exclude the Default.aspx and Web.config from the project.
  8. Now create a Windows Class Library ‘SitecoreXamlPlayground’.
  9. Exclude Class1.cs from your project.
  10. Just shutdown VS2005 or close the current solution.
  11. Open the VS 2005 standard folder
  12. Find the folder ‘SitecorePlayGround’ with Subfolder ‘SitecorePlayground’. Open it.
  13. Copy the Properties-folder, SitecorePlayground.csproj and SitecorePlayground.csproj.user naar %installdir%/Website/
  14. Do nearly the same for just the SitecoreXamlPlayground.csproj.
  15. Now doubleclick SitecorePlayground.csproj to start Visual Studio. A new solution ‘SitecorePlayground’ is created by VS2005.
  16. Right-click on the solution > Add > Exsisting Project > SitecoreXamlPlayground
  17. Now close the solution in Visual Studio, the IDE will ask you where to place the .sln-file. I recommend %installdir% over %installdir%/Website.
  18. Ready!

Now it’s time to have a cup of coffee and start playing!

Configuring Log4net so the sysop stays happy

Maintaining larger solutions is always hard, as unexpected occur(for example, your server contains a 300GB HDD for logging which is filled after 2 week of running).. I’ve seen the same problems. Today I’ll discuss how to configure Log4net in the way the system operator stays happy. This should become a part of the deployment proces or even before ‘go live!/finishing touch’ of the project.

Looking at the web.config(SC5.3) you will find the following node:

<log4net>
<!– LOGGING SETTINGS
The file element defines the location of the log files. This location must
be the same as the setting in LogFolder. The file element is a relative or
absolute path that always uses slashes (/) as separators. A valid file
element for a relative path would be:
<file value=”/data/logs/log.{date}.{processid}.txt” />
A valid element for an absolute path would be:
<file value=”C:/inetpub/wwwroot/data/logs/log.{date}.{processid}.txt” />
For further information refer to the Log4Net documentation.
–>
<appender name=”LogFileAppender” type=”log4net.Appender.SitecoreLogFileAppender, Sitecore.Logging”>
<file value=”D:/NET Development/Sitecore Projects/Sitecore 5.3 Playground/data/logs/log.{date}.txt”>
</file>
<appendToFile value=”true”>
</appendToFile>
<layout type=”log4net.Layout.PatternLayout”>
<conversionPattern value=”%4t %d{ABSOLUTE} %-5p %m%n”>
</conversionPattern>
</layout>
</appender>
<root>
<priority value=”INFO”>
</priority>
<appender-ref ref=”LogFileAppender”>
</appender-ref>
</root>
</log4net>

Log file names:

The first thing what show up is the way logfiles are created. Sitecore provides a little feedback on it where they explain you can easily add paramaters to the names of the files:

{date} – Date in YYYYMMDD-format
{procesid} – Return the WindowsProcesId which is writing. Could be usefull when you’ve got conflicts on locked files.
Other patterns can be found here: http://logging.apache.org/log4net/release/sdk/log4net.Util.PatternString.html

AppendingtoFile?

Yes, that’s the question, append to file or overwrite. As Sitecore produces so many lines of logs, and most of the time, jsut one logline is useless: do mot change this.

A line of logging:

A single line of logging is formatted by the layout/conversionPattern-node. For a full description how to configure this section, take a look at the detailed API dump of Log4Net.

Priority based logging:

Normally, you can define the priority of a the lines you want to be logged, as specified in the priority-node, but so far I haven’t been able to change it to any other value. I’ve tried ‘WARN’ and ‘ERROR’ so far. Does someone have a clue why changes to this attribute only result in an empty logfile? 

Resources on the web:

Specific siteConfigurations in 5.3

Just created a small but very useful tool for nearly every Sitecore 5.3 developer: a specific Site configuration option which can update keys without recycling the application pool(appSettings will cause a full Application Pool Recycle which can be very annoying).

I’ll walk trough together with you guys trough the steps which are required to use this small extention:

Create a SiteSettings.config:

Create a new blank SiteSettings.config-file in App_config-folder.

Fill the file with contents:

The structure of the file  is very simple:

<?xml version=”1.0″ encoding=”utf-8″?>
<configuration>
<siteSettings name=”website”>
<add key=”Sitecore” value=”Alive and kicking!” />
</siteSettings>

You can simply create more siteSettings-nodes and ofcourse more config-values.

Define the file in the web.config:

Just after the starttag you can include the file:

<sc.include file=”/App_Config/SiteSettings.config” />

Retrieving the settings in your code:

You can easily retrieve the settings using this small class:

public static class SiteConfigurationManager
{
/// <summary>
/// siteConfig position within the web.config
/// </summary>
private static string siteConfigNode = “/sitecore/siteSettings”

/// <summary>
/// Retrieves configValue by provided website and key.
/// </summary>
/// <param name=”site”>Name of the website</param>
/// <param name=”key”>Config key</param>
/// <returns>The value of the configkey or null</returns>
public static string GetConfigValue(string site, string key)
{
string xpath = SiteConfigurationManager.siteConfigNode + “[@name='” + site + “‘]/add[@key='” + key + “‘]”
return SiteConfigurationManager.GetValueByXPath(xpath);
}

/// <summary>
/// Retrieves configValue based on the site loaded in current context and the provided key.
/// </summary>
/// <param name=”key”>Config key</param>
/// <returns>The value of the configkey or null</returns>
public static string GetConfigValue(string key)
{
return SiteConfigurationManager.GetConfigValue(Sitecore.Context.Site.Name, key);
}

/// <summary>
/// Retrieves configValue by XPath query.
/// </summary>
/// <param name=”xpath”></param>
/// <returns></returns>
private static string GetValueByXPath(string xpath)
{
XmlNode aNode = Sitecore.Configuration.Factory.GetConfigNode(xpath);
if(aNode != null)
{
XmlAttribute anAttr = aNode.Attributes[“value”];
if(anAttr != null)
{
return anAttr.Value;
}
}
return null;
}

You now simple can use the config keys by using these methods:

//Use the Sitecore-Site in the current Context
//Returns: ‘Alive and kicking’
SiteConfigurationManager.GetConfigValue(“Sitecore”)

//Use the Sitecore-Site defined by yourself
//Returns: ‘Alive and kicking’
SiteConfigurationManager.GetConfigValue(“website”, “Sitecore”)

Wasn’t so hard, was it? No it’s time to submit this small piece of code in our Ole-workflow: let’s see if Ben, our quality dude, approves my class so it will be in the next built of the LECTRIC-Library :).

5.3 Experience – Day 1

10:10: Quite annoying behaviour of the installer, it keeps boosting my CPU usage to some figure around the 100 percent. This is killing my Outlook experience ;).

10:15: When creating different websites on your XP machine, I noticed you’ve to create the site before going to the site selection screen in the installer. This screen will be fetched only once. Have to notice Sitecore about this.

10:30: Got some arguments with databases in the installer. Easy way tyo fix this: setup your local machine to host the database so you can pass the database step. After that, reconfigure your files. Writing feedback on this now…

10:40: Installer… grrr, it places the stuff everywhere on my machine, but not on the recommed place. Gues sit has something todo with my default settings in my IIS. Investigation right now…

10:45: Seems that the installer only allows you to quit after clicking 4 times on finish when the checkbox ‘Start Sitecore’ in unchecked.

11:00: Starting IE7, initializing the site….

11:10: Welcome to Sitecore…. After some small replacements in the web.config is it working. Having some coffee now.. Support are you guys ready for a bunch of tickets :P?

Update:

12:20: As we are working on 3 projects which are all based on 5.3 at the moment, lots of bugs appear on 1 day. So guess the Sitecore Ukraine office has some problems with capacity for reproducing these bugs ;-). Now it’s time to start working with 5.3. My first task will be finding out how we can easily configure some stuff using the new config-options so we don’t have to change the web.config. As a web.config change results in a Application Pool recycle, we’re looking for better ways.

12:40: Visual Studio Solutions for Sitecore 5.3 are really a new type of sport. Interesting point for investigation as this directly affects our procedures(project startup).

14:30: Just an hour looking at the best way to configure the data folder in the right way so everybody is happy. The problem is that I’m using d:\net development\sitecore project\[customer name] as project root, someone else in our team uses d:\inetpub\[customer name], someone else… etc etc. Two possible solutions:

  1. Create a virtual directory to ../data, refer everything in web.config to /data/* (won’t work with Cassini / Builtin Webserver VS2005)
  2. Define together with your colleagues that the datafolder becomes: D:\data\[customer name]\

Both aren’t ideal. The hardest part is that you’ve to define it over and over. So far option 1 is the best as it seem to be less time expensive. Another support-ticket upcoming…

16:15: It’s time to stop working on 5.3 today. Have to do some licensing stuff and have a beer. The results from the configReader can be found here. Monday I’ll be back! Have a nice weekend and a beer :).