NMoneys. Bumped to 2.5

Why 2.5?

Previous to 2.5 came 2.2. But to highlight that changes between the two versions are pretty “dramatic” I chose to bump the version number. Fear not, not everything has been turned upside down.

Breaking changes

Everyone hate breaking changes.

  • Fellow developers hate them because they make their working applications stop working when the library is updated
  • Users hate them because it takes time for their application to be updated with “the next killer feature” and the developer is busy changing a bunch of broken unit tests
  • Business people hate them because they cost money and precious development hours
  • Author developers hate them because it is a sign that they did not thought the API through enough

But we cannot live in a world of infinite stability or being Microsoft to put up with rotten APIs. Environmental forces change and an author of a software library has one of three options:

  1. do not break it, even though we all know we were wrong
  2. offer an alternative API with the new design while we slowly deprecate the previous one
  3. suck it and assume you were wrong before (and risk being wrong again)

With NMoneys we have the luxury of not having a massive user base. Besides, our users are great fellows that understand that there are breaking changes and Breaking Changes (note the capitals).

The breaking change we are talking about could be one of the worst: changing an interface. A change like that usually means breaking custom implementations of that interface. A royal pain in the neck for the developers that took the steps to implement it.
In our case it is an extension point interface, meaning that we have provided some default canonical implementations of that interface, but allowing injection of custom behavior when that was needed. I chose to believe that there are not a lot of custom implementations of that interface lying around.

Furthermore, an interface change could mean than not only implementations break, but consumers of that interface might break as well (depending on whether the change affects interface’s return types).
In that extent, I choose to believe me lucky as well, for the damage is minimized by returning a type that somehow extends the previous return type (cursive extends as they are not substitutable, from inheritance point of view, only that the way of interacting with the type is pretty much the same).

Alright, enough justification, what is that breaking change everyone talks about?

The Change(s)

version 2.2 version 2.5
Money[] Money.Allocate(int) and Money[] Money.Allocated(int, IRemainderAllocator) Allocation Money.Allocate(int) and Allocation Money.Allocated(int, IRemainderAllocator) more
void Allocate(Money remainder, IList<decimal> alreadyAllocated); Allocation Allocate(Allocation allocationSoFar); more
NMoneys.Allocators NMoneys.Allocations more

Split allocation return type

In 2.2, a feature to calculate split allocations was added (Money.Allocate(int)). It returned an array of Money to represent the quantity allocated to each recipient. It turns out that using a primitive type (and array) is not enough (how many times have seen this?) to represent several situations, for instance: a quantity so small that cannot be allocated; or a quantity that can be evenly allocated, but it has some remainder that is itself too small to be distributed.

The solution is return something that can be used like an array (can be enumerated, indexed and its length interrogated), but communicates more information about the result of the allocation operation:


Interface change

And the interface change we talked about before is IRemainderAllocator. As I mentioned before, I do not expect many custom implementations of that interface; but comparing both signatures one has to conclude that we are much better off with the newer version.

Namespace change

Another breaking change is a namespace change. In 2.2 we only had implementations of IRemainderAllocator and the internal EvenAllocator, so it made sense to call it .Allocators. With the new features, new types and “surfaced types” it makes so much sense that everything allocation-related “lives” under .Allocations.

New Features

But sure a version bump deserves new features on top of breaking changes. And we indeed have more features.

Pro-Rated allocations

Undoubtedly the star feature of the release are pro-rated allocations. If previously we could allocate a certain quantity amongst n recipients evenly, now we are able to allocate it unevenly, that is, each recipient might get more or less of their even share depending of a ratio (a fraction between 0 and 1) passed to the operations. Such operation could help solve the mildly famous Foemmel’s Conundrum (or how to split 5 cents amongst two parties where the first one gets a 30% and the second the remaining 70%):

[sourcecode language=”csharp”]Money scarce = .05m.Usd(); var ratios = new RatioCollection(.3m, .7m); Allocation allocated = scarce.Allocate(ratios); Assert.That(allocated, Is.EqualTo(new[] { .02m.Usd(), .03m.Usd() }));[/sourcecode]

But that problem does not have only one solution, as it depends on the order in which remaning quantities are allocated:

Money scarce = .05m.Usd();
var ratios = new RatioCollection(.3m, .7m);

Allocation allocated = scarce.Allocate(ratios, RemainderAllocator.LastToFirst);
Assert.That(allocated, Is.EqualTo(new[]

Incomplete allocations

Besides try to do complete allocations one can now opt in for incomplete allocations, meaning that one can distribute just the fair amount of a quantity, to discard the remainder if one choses so:

Allocation unfair = new EvenAllocator(8.3m.Usd()).Allocate(4);

Assert.That(unfair, Is.EqualTo(new[] { 2.07m.Usd(), 2.07m.Usd(), 2.07m.Usd(), 2.07m.Usd() }));

Assert.That(unfair, Must.Be.Incomplete(a =>
    a.Allocated = 8.28m.Usd();
    a.Remainder = .02m.Usd();

Words of Thank you

Just as I thanked Berryl Hesh for his contribution in 2.2 of split allocation, I have to thank him twice this time: one for the contribution of the pro-rated allocations feature and another one for being patient and assertive when I literally turned his code inside out to simplify the resulting code (I believe) from his contribution. Looking forward for that article.

An extra one comes to show me an interesting way of splitting tests of chunky classes (such as Money) into partial classes. We will be able to see more of those in further releases.

It ain’t going anywhere

So you can get the latest version in the usual Google code’s Downloads, Nuget’s Gallery or RubyGems.org.

Categories: Udvikling

Tagged as: ,

Skriv et svar