Sunday, August 21, 2011

Quantity Pattern - Lessons Learned from Implementing Complex Domain Model – part 2

 

Analysis Patterns: Reusable Object Models is a book by Martin Fowler, first published in 1996. It is not new nor it is an easy reading. As much as I like Fowler’s style of writing I struggled trough some of the chapters. Do I recommend the book – yes. Why? Because each time I am involved in a project with complexity above the average, dealing with real world business cases, I find the patterns described in the book helpful.

The project I mentioned in part 1 is all about real world business cases and it is a serious business – oil&gas business. In this post I will focus on Quantity Pattern that played a key role in a success of the project.

In our domain we had to deal with values expressed using various units and their derivatives. The formulas used for calculations were pretty complex and involved unit arithmetic. For example you want to be sure that calculated daily oil production rate is expressed in  mbbl/day (thousand oil barrels per day) or any unit that can be converted to OilVolume/Duration.

Quantity pattern tells you to explicitly declare a unit for every dimensioned value instead of just assuming the unit (representing the value as a bare number). This part is easy:

public class Quantity
{
public decimal Amount { get; private set; }
public Unit Unit { get; private set; }
}


Next there is Parsing quantities and units from strings and converting them to strings. This is not the hardest part but there are things you have to watch for. There are prefix units ($) and suffix units (most of them). Some of them require space after the amount, some look better concatenated with the amount. Examples could be: “$10.5m” and “42 km”.



The hardest part was implementing arithmetic on Quantities with support for all operators, compound units, conversions, reductions, etc. But it was worth it. Now we can write code like this:



var oilVolume = Quantity.Parse("100 mmbbl");
var duration = new Quantity(1, Units.Year);

var productionRate = (oilVolume/duration)
.ConvertTo(Unit.ThousandOilBarrels/Unit.Day);

Console.WriteLine(productionRate.Round(2)); // Gives us "273.97 mbbl/d"


When we thought we were done with the implementation, we had discovered that the performance of Quantity*Quantity is far worse then decimal*decimal. Profiling showed that operations on units (mostly reductions and conversions) caused Unit.Equals method to be called so many times (especially when looking for conversions between compound units) that despite the fact that a single Unit.Equals execution would take 1 ms the final result was not acceptable. We were crushed. Of course the first thought was to go back to using decimals, but we really did not want to give up all the Quantity goodness.



It took us a while to come up with the solution that depended on making sure we only ever have a single instance of any unit. That allowed us to compare any two units (including compound units) for equality using Object.ReferenceEquals.



This was easy for base units – we just made them singletons, i.e.:



public class Unit
{
public static readonly Unit OilBarrel = new BaseUnit("bbl", ... );

// ...
}


All other units were the problem. There are many ways one can create an instance of an unit, some examples:



var a = Unit.Parse("100 mbbl/d");

var b = (Unit)BinarySerializer.Deserialize(BinarySerializer.Serialize(a));

var c = Unit.ThousandOilBarrels/Unit.Day;


At the end we covered all of them using lookups, unit operation cache, conversion cache, implementing IObjectReference and such. The result was surprisingly good. We were able to achieve performance close enough to this of operations on pure decimals (after all caches got populated). What made us really happy was the fact, that we were able to solve the performance problem just by changing the implementation of the Unit and Quantity classes. Public interfaces used by all the code already written was unchanged.



The summary is that if you’re to work with a domain that deals with a lot of dimensioned values using a number of base units and their derivatives, implementing even the simplest form of Quantity pattern will make your life much easier. Implementing the full featured Quantity class will take time and depending on your performance requirements may or may not be worth it.



End of part 2



I strongly recommend reading Analysis Patterns. Even if you don’t remember the details of the patterns after the first pass, don’t worry – just keep the book around – you will read it again when the time comes. Other patterns from the book we used in the project were many of the Accounting Patterns.

1 comment:

recless said...

The ruby-units.gem for handling SI (and many other) quantities in Ruby solves the equality check performance problem more simply by using bit patterns to represent the combination of underlying measurement types.

The author originally cited a paper from the '90s in his comments about this compact representation, but I can't find that cite at the moment. An advantage is that this package can calculate compound quantities (e.g., barrels per hour) easily.