Jenny had been perfectly happy working on a series of projects for her company, before someone said, "Hey, we need you to build a desktop GUI for an existing API."

The request wasn't the problem, per se. The API, on the other hand, absolutely was.

The application Jenny was working on represented a billing contract for materials consumed at a factory. Essentially, the factory built a bunch of individual parts, and then assembled them into a finished product. They only counted the finished product, but needed to itemize the billing down to not only the raw materials that went into the finished product, the intermediate parts, but also the toilet paper put in the bathrooms. All the costs of operating the factory were derived from the units shipped out.

This meant that the contract itself was a fairly complicated tree structure. Jenny's application was meant to both visualize and allow users to edit that tree structure to update the billing contract in sane, and predictable ways, so that it could be reviewed and approved and when the costs of toilet paper went up, those costs could be accurately passed on to the customer.

Now, all the contract management was already implemented and lived library that itself called back into a database. Jenny just needed to wire it up to a desktop UI. Part of the requirements were that line items in the tree needed to have a special icon displayed next to them under two conditions: if one of their ancestors in the tree had been changed since the last released contract, or if they child was marked as "inherit from parent".

The wrapper library wasn't documented, so Jenny asked the obvious question: "What's the interface for this?"

The library team replied with this:

IModelInheritFromParent : INotifyPropertyChanged
{
        bool InheritFromParent {get; set;}
}

"That covers the inheritance field," Jenny said, "but that doesn't tell me if the ancestor has been modified."

"Oh, don't worry," the devs replied, "there's an extension method for that."

public bool GetChangedIndicator(this IModelTypeA);

Extension methods in C# are just a way to use syntactic sugar to "add" methods to a class: IModelTypeA does not have a GetChangedIndicator method, but because of the this keyword, it's an extension method and we can now invoke aInstance.GetChangedIndicator(). It's how many built-in .Net APIs work, but like most forms of syntactic sugar, while it can be good, it usually makes code harder to understand, harder to test, and harder to debug.

But Jenny's main complaint was this: "You can't raise an event or something? I'm going to need to poll?"

"Yes, you're going to need to poll."

Jenny didn't like the idea of polling the (slow) database, so at first, she tried to run the polling in a background thread so it wouldn't block the UI. Unfortunately for her, the library was very much not threadsafe, so that blew up. She ended up needing to poll on the main UI thread, which meant the application would frequently stall while users were working. She did her best to minimize it, but it was impossible to eliminate.

But worse than that, each contract item may implement one of four interfaces, which meant there were four versions of the extension method:

public bool GetChangedIndicator(this IModelTypeA);
public bool GetChangedIndicator(this IModelTypeB);
public bool GetChangedIndicator(this IModelTypeC);
public bool GetChangedIndicator(this IModelTypeD);

To "properly" perform the check, Jenny would have to check which casts were valid for a given item, cast it, and then invoke GetChangedIndicator. It's worth noting that had they just used regular inheritance instead of extension methods, this wouldn't have been necessary at all. Using the "fun" syntactic sugar made the code more complicated for no benefit.

This left Jenny with another question: "What if an item implements more than one of these interfaces? What if the extension methods disagree on if the item is changed?"

"Good question," the team responsible for the library replied. "That should almost never happen."

Jenny quit not long after this.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.