October 2008 - Posts

I'm a huge fan of Domain Driven Design (DDD) (links here, here and here) and this post is the first in many, all about enforcing your domain model using Spec#.

So What Is Spec#?

Spec# is a super set of C# 2.0 (no, unfortunately not 3.0 yet). This means that Spec# has all the features as C#, and all the Spec# stuff on top of that.

Spec# is about specifying, and because the guys at Microsoft probably explains it better than I do, I have stolen copied this from the Spec# web site:

  • The Spec# programming language.  Spec# is an extension of the object-oriented language C#.  It extends the type system to include non-null types and checked exceptions.  It provides method contracts in the form of pre- and postconditions as well as object invariants.
  • The Spec# compiler.  Integrated into the Microsoft Visual Studio development environment for the .NET platform, the compiler statically enforces non-null types, emits run-time checks for method contracts and invariants, and records the contracts as metadata for consumption by downstream tools.
  • The Spec# static program verifier.  This component (codenamed Boogie) generates logical verification conditions from a Spec# program.  Internally, it uses an automatic theorem prover that analyzes the verification conditions to prove the correctness of the program or find errors in it.

This first post explains the non-null operator, so let's get to it.

The Non-Null Operator

The non-null operator is probably the most simple operator in Spec#, yet I find it very effecient to express e.g. value objects or aggregates in the domain.

The non-null operator is in a way the opposite as the nullable operator in C#, which allows value types to be nullable. The non-null operator allows you to specify reference types as being non-nullable by using an exclamation mark (!).

The C# way:

   1: public string Foo(object o)
   2: {
   3:     return o.ToString(); // NullReferenceException
   4: }
   5:  
   6: public void Bar()
   7: {
   8:     object o = null;
   9:     string str = Foo(o);
  10: }

The Spec# way:

   1: public string Foo(object! o)
   2: {
   3:     return o.ToString();
   4: }
   5:  
   6: public void BadBar()
   7: {
   8:     object o = null;
   9:     string str = Foo(o); // Spec# warning
  10: }
  11:  
  12: public void GoodBar()
  13: {
  14:     object o = null;
  15:  
  16:     if (o != null) // We're ok
  17:         Foo(o); 
  18: }

If o was initialized to something else than null in GoodBar() the Spec# compiler would be happy too.

In a domain example an implementation could be something like this:

   1: public class OrderLineItem
   2: {
   3:     ...
   4:  
   5:     // We're making the product property non-nullable as an order line item without a product
   6:     // does not make much sense, it would just be a quantity of nothing.
   7:     public IProduct! Product
   8:     {
   9:         get; private set; 
  10:     }
  11:  
  12:     public int Quantity
  13:     {
  14:         get; set;
  15:     }
  16:  
  17:     ...
  18: }
  19:  
  20: public class PurchaseOrder
  21: {
  22:     ...
  23:  
  24:     public OrderLineItem AddProduct(IProduct! product, int quantity)
  25:     {
  26:         // Add product - no need to check for null
  27:     }
  28:  
  29:     ...
  30: }
  31:  
  32: public class Cart
  33: {
  34:     public void Add(IProduct product)
  35:     {
  36:         if (product != null)
  37:             PurchaseOrder.AddProduct(product, 1);
  38:         else
  39:             // Handle null product        
  40:     }
  41: }

In the example above, the caller of PurchaseOrder.AddProduct is forced to check for null before calling the method. This really encapsulates clean business logic in the PurchaseOrder and OrderLineItem classes. In C# you would create a guard clause at the top of the AddProduct method, but in order for a developer to know about this, he has to read the implementation of the method. By using Spec# the developer is made aware of this when calling the method.

Please feel free the leave a comment or contact me of you have any questions or comments!

Part 2 is all about preconditions... Coming up!

If you're a small team or a single person and find the need for some source control and backup, I can highly recommend ProjectLocker. It includes Trac for management, and BuildLocker can be added for CI. The uptime is amazing too! I use the VisualSVN client for Visual Studio along with TortoiseSVN, but it supports most tools.

I use the lowest service level which includes unlimited repositories, 1 GB space and 2 users - the price is $2.50 pr month.

And no, I don't get any royalties :)

Not too long ago we had to do some performance profiling for a Commerce Server site that went into production a couple of months before. We knew we had some performance issues, but because of some inventory issues at the client, we had to rush the site into production.

The first couple of days the performance was acceptable, but as more and more customers started hitting the site, some of the nasty issues we addressed started showing up. The site was stable though, just not the fastest one out there.

The site is a pretty standard e-commerce site, not much fancy stuff on this one. The only exception is some very large categories rendering 500+ products on a single page.

First Things First: HTML Ad Libitum

Generating HTML for a category containing 500+ can be pretty tough on both the server and the client side. On the server side, the basic category layout was built using a couple of ASP.NET user controls and each product view consisted of a couple of user controls too. This provided a very flexible and configurable layout, but the performance for generating all those server controls and related markup was pretty tough for the server. The HTML output (without images) was about ~1.6 MB, which the browser wasn't too happy about either.

So removing a lot of user controls and only one user control per product resulted in an HTML output around ~400 kb tops. No need to say that this had a major impact on performance.

With the HTML all nice and cleaned up, we can start digging in to the inner workings of the site.

Next up: Tracing For Bottlenecks

To get a basic idea of where bottlenecks could be found, we turned to the ASP.NET Output Trace. It's pretty simple stuff, and I wrote some stuff the trace we I knew we had some issues. When displaying categories we had to do a lot of heavy filtering on product variants. Each product having about 10+ variants, a product list with 500 products would generate ~5.000 products to filter!

However, the trace showed that this wasn't nearly as time consuming as I had imagined. A bigger problem was in a user controlle called CatalogTopMenu.ascx.

At the top of the site the user can navigate through the catalogs available in the catalog set, implemented in CatalogTopMenu.ascx.

Bring In The Profiler

Of course, you could add stuff to the trace, compile, deploy, test, check trace, write down result, remove trace code, add more trace code, compile, deploy and so on. Instead we used ANTS Profiler from Red Gate. I really love this tool, it fairly easy to use, but it provides some real useful result. If you find yourself in need of a performance profiler I can highly recommend trying this one - there's a 14-day free trial available on their web site.

Setting Up ANTS Profiler For Commerce Server

When profiling an ASP.NET site, ANTS Profiler starts a new instance of the worker process (w3wp.exe), which runs the site you're profiling. Because Commerce Server requires a seperate application pool, running the site outside IIS proved a bit difficult. The profiling worker process is being executed by a service called "ANTS Profiler 3 Server", so setting the log on identity for this one to the same identity as the application pool used to host the site resolved this issue. You can find the service under Control Panel > Administrative Tools > Services. Here's my setup:

Identity

 

Next up, start the profiler from the site, and browse around. When you're done browsing, hit the "Take Snapshop" button in the profiler.

The Profiler Results

The main window displays slowest lines of code (top) and slowest method (bottom):

AntsProfiler

Looking at the slowest method you can see it's a lot slower than the second slowest! Taking a look at the source method we find the following line, which is the sinner:

AntsProfiler2

It kind of surprised me that the cause of our slowest methods is a call to the Commerce Server API. We did a lot of additional tests to prove this right, and they all confirmed this issue, even though catalogs are being cached. I would imagine it would have taken a lot of Trace.Writes to find this one.

Dllhost.exe Consuming A Lot Of Memory

As a side note, we had issues with the dllhost.exe service on the server would consume a lot of memory! After a short visit to Google, it turned out that there's a known memory leak in a COM+ component, causing the dllhost.exe to run wild when performing many catalog imports. We're using BizTalk to import a lot of products, so applying Commerce Server Service Pack 2 should resolve this issue.

The Results

Fixing the issues mentioned above had a major positive impact on the performance. Other thing we did was:

  • Improving the algorithm for filtering variants
  • Removed some unnessecary calls to the catalog and inventory system
  • A bit more caching
  • And a lot more

The server side generation went from ~25 seconds to ~4 seconds the the single heaviest page on the site. With the HTML being all slim, the rendering on the client side improved a lot too.

Next up is to open up Reflector and SQL Profiler to find out why getting a catalog is such a tough operation, and maybe do a blog post about it, unless Brian beats me to it...

More Posts