The Abstractor, as Greg and his team liked to call him, was a contractor at their company. The Abstractor had built a C# framework architecture (affectionately called Big Momma) that quickly went from being the company's framework, to being his personal baby. At the heart of Big Momma were abstract "Values" collections that wrapped the normal microsoft.net collections. This was so that any time The Abstractor decided that using arrays, XML or List<T> was bad, he could easily change "Values" to store data in some other data structure, and the code using it would be none-the-wiser. After all, enlightened developers use encapsulation, right?

While The Abstractor tended to stay away from any code that involved business logic due to his time being too valuable to be spent researching anything, he was eventually forced into creating a service that populated a database table for the new e-commerce website. The table would be used as a quick "real time" check for determining if a product was available at a location for in-store pickup. The records for each and every product needed to be updated every 30 minutes. Using Big Momma and armed with his "Values" collections, The Abstractor quickly had a solution in place. Unfortunately, it took 3 days to process 500,000 rows in the database - once. Greg was amazed that it could run that slowly. That was until Greg saw this error exception:

Inner Exception ---> System.Threading.ThreadAbortException: Thread was being aborted.
  at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32length, Boolean reliable)
  at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32length)
  at System.Valuess.ArrayList.CopyTo(Array array, Int32 arrayIndex)
  at System.Valuess.ArrayList.InsertRange(Int32 index, IValues c)
  at MS.Internal.Xml.XPath.Function..ctor(FunctionType ftype, ArrayList argumentList)
  at MS.Internal.Xml.XPath.XPathParser.ParseMethod(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParsePrimaryExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseFilterExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParsePathExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseUnionExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseMultiplicativeExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseRelationalExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseEqualityExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseOrExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParsePredicate(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseStep(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseRelativeLocationPath(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParsePathExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseUnionExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseMultiplicativeExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseRelationalExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseEqualityExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.XPathParser.ParseOrExpr(AstNode qyInput)
  at MS.Internal.Xml.XPath.QueryBuilder.Build(String query, Boolean allowVar, Boolean allowKey)
  at System.Xml.XPath.XPathExpression.Compile(String xpath, IXmlNamespaceResolver nsResolver)
  at System.Xml.XPath.XPathNavigator.Select(String xpath)
  at System.Xml.XmlNode.SelectSingleNode(String xpath)
  at DataStructures.Values.ValuesXml.GoGet(String name) in
C:\Development\trunk\Common\DataStructures\Values\ValuesXml.cs:line 274
  at DataStructures.Values.ValuesBase.Get(String name) in
C:\Development\trunk\Common\DataStructures\Values\ValuesBase.cs:line 1170
  at DataStructures.Values.ValuesBase.get_Item(String name) in
C:\Development\trunk\Common\DataStructures\Values\ValuesBase.cs:line 239
  at BaseObject.GoGet(String name) in C:\Development\trunk\Common\BaseObject.cs:line 81
  at DataStructures.Values.ValuesBase.Get(String name) in
C:\Development\trunk\Common\DataStructures\Values\ValuesBase.cs:line 1170
  at DataStructures.Values.ValuesBase.get_Item(String name) in
C:\Development\trunk\Common\DataStructures\Values\ValuesBase.cs:line 239
  at DataStructures.Values.ValuesBase.GoFilterString(String name, String value, Boolean breakWhenFound) in
C:\Development\trunk\Common\DataStructures\Values\ValuesBase.cs:line 872
  at DataStructures.Values.ValuesBase.GoSearchString(String name, String value) in
C:\Development\trunk\Common\DataStructures\Values\ValuesBase.cs:line 955
  at DataStructures.Values.ValuesBase.GoSearch(String name, Object value) in
C:\Development\trunk\Common\DataStructures\Values\ValuesBase.cs:line 934
  at DataStructures.Values.ValuesBase.Search(String name, Object value) in
C:\Development\trunk\Common\DataStructures\Values\ValuesBase.cs:line 310
  at GetVendorDeliveryTime(String vendorId, String storeNumber)

The GetVendorDeliveryTime method simply looked up when a vendor delivers their product to a particular store. The Abstractor had stored the 400 some odd values in his "Values" collection which, in reality, was storing it in XML beneath the covers. Not only did it take 10 fairly complex method calls to get through all the layers of abstraction to the implementation of: ValuesXml.GoGet, but then the XML Search method The Abstractor implemented dove 27 layers deeper to grind through layers of abstraction around XML processing, before it finally died.

With the e-commerce go-live date quickly approaching, Greg decided to quickly rewrite the service, this time using generic Dictionaries for lookups, rather than Big Momma's abstracted "Values" collection. Amazingly with his first attempt, Greg was able to get the whole update down from 3 days to 90 minutes. Greg asked The Abstractor for a little help on multithreading the service. Once The Abstractor saw the new code, he blew up saying that using generic Dictionaries was sh*tty code and refused to help Greg any further.

Greg spent a few hours looking at the Task Parallel libraries documentation and after a little bit of trial and error, had the whole service running in under 15 minutes, just in time before the new website went live.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!