What Financial Softwares, Martin Fowler, Uncle Bob and Alexander Hamilton have in common?
Published: 2021-05-24 12:57:12

As Martin Fowler said in his article about _Patterns of Enterprise Application Architecture_ (https://martinfowler.com/eaaCatalog/money.html):
> "A large proportion of the computers in this world manipulate money, so it's always puzzled me that money isn't actually a first class data type in any mainstream programming language."

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/e4slck3pp4fdmaa8nwdw.png)

Well, I didn't read the book _Patterns of Enterprise Application Architecture_, but I do know that he suggests the implementation of a class _Money_, with the attributes _currency_ and _amount_, as well as a method called **allocate** that receives a list of proportions and **distributes that money without leaking values with rounding**. In this article I'll show how we've implemented our _Money_ to solve a real problem of losing cents in apportionments, and also solve the mystery of this article's title.

We already had a _Money_ class, which made it really easier to write the _Money Pattern_. So, if I am to give you a first hint, it is: **DO NOT use _Double_ or _Big Decimal_ to financial values**. Build your "Value Object". After having financial values spread all over your system, it's gonna be harder - but not impossible - to refactor.

Our _Money_ class doesn't have the attribute _currency_ because we don't have the need for a internationalization, at least not yet. And we are not going to implement _currency_ until we actually need it. Just like we didn't have the _allocate_ method. Until we needed it. So, our _Money_ was like this:


```Java
public class Money implements Serializable {

  private final BigDecimal amount;

  private Money(BigDecimal amount) {
    if (amount == null) {
      throw new AmountCantBeEmptyException();
    }
    this.amount = amount;
  }

  public static Money of(BigDecimal amount) {
    return new Money(amount);
  }

  public Money plus(Money addition) {
    return Money.of(this.amount.add(addition.amount));
  }

  public Money minus(Money discount) {
    return Money.of(this.amount.subtract(discount.amount));
  }

  public Money times(BigDecimal factor) {
    return Money.of(this.amount.multiply(factor));
  }

  public BigDecimal getAmount() {
    return amount;
  }

  @Override
  public boolean equals(Object obj) {
    if (obj == null || !(obj instanceof Money)) {
      return false;
    }
    return this.amount.compareTo(((Money) obj).amount) == 0;
  }

  @Override
  public int hashCode() {
    return this.amount.hashCode();
  }

}
```

This used to solve most of our financial problems. Until the day we needed the **allocate** method. A **debit worth of $ 1000.20 should be apportioned between several accounts** with the following rules:

|   #   | Proportion | Gross Value | Rounded Down | Rounded Up | Rounded Half Even |
|:-----:|-----------:|------------:|-------------:|-----------:|------------------:|
|   1   |      22,9% |    229.0458 |       229.04 |     229.05 |            229.05 |
|   2   |      27.7% |    277.0554 |       277.05 |     277.06 |            277.06 |
|   3   |       7.8% |     78.0156 |        78.01 |      78.02 |             78.02 |
|   4   |      22.6% |    226.0452 |       226.04 |     226.05 |            226.05 |
|   5   |        19% |     190.038 |       190.03 |     190.04 |            190.04 |
| Total |       100% |     1000.20 |      1000.17 |    1000.22 |           1000.22 |

As you can see, applying the apportionment percentage on every item, we'll never get to **1000.20** - this happens because **cents** are an indivisible unit, so the financial value represented by Money can't be 229.0458, for example. If we round down, 3 cents are lost in the end. If we round up, we get 2 extra cents. Even using Round Half Even will have precision loss.

And guess who faced a problem like this? George Washington himself and one of the proposed solutions came from Alexander Hamilton, one of the Founding Fathers, and first United States Secretary of the Treasury, using his Largest Remainder Method.

The problem faced at that time, described in [U.S. Census Bureau](https://www.census.gov/history/www/reference/apportionment/methods_of_apportionment.html), was shortly:

A country with 4 states, each one with its own population, and 20 Seats at the House of Representatives. How many senators each state should have so they are represented proportionally? A senator, just like a penny, can't be divided in pieces. Right? Just double checking...

| State | Population | Seats by State | Seats by State before Hamilton's method | Seats by State after Hamilton's method |
|-------|-----------:|---------------:|----------------------------------------:|---------------------------------------:|
| 1     |       2560 |           4.31 |                                       4 |                                      4 |
| 2     |       3315 |       5.**58** |                                       5 |                                      6 |
| 3     |        995 |       1.**67** |                                       1 |                                      2 |
| 4     |       5012 |           8.44 |                                       8 |                                      8 |
| Total |      11882 |             20 |                                      18 |                                     20 |

Hamilton's method consists in calculating the proportion between the population of **11882** and the number of **20** seats, resulting in the quota of **594.1**. Now, for each state, divide its population for the quota. For example in the state **1**, **2560/594.1** getting a quotient of **4.31**.

As we have agreed, **we can't have 4 senators and 0.31 of a senator** for a state. So the number of senators for the state 1 is 4, which is the **whole part** of the result. That happens for every state. In the end, because of the rounding, the **number of senators allocated in the states is 18**. Which states should the other **2 senators** go to? That's when **Hamilton** comes with a possible solution. His idea is that we distribute these 2 seats to the states that had the **largest decimal part before the rounding**.

I'll explain. If we suppress the whole part of the **Seats by State** column and desc order by the decimal part, we get:

1. 1,**67**
2. 5,**58**
3. 8,**44**
4. 4,**31**

Since we have a total of **2 seats to redistribute**, the states that will receive these senators are the **first 2 of the list**. Resulting in the column **Seats by State after Hamilton's method**.

There's a paradox to be noticed that was discovered by applying Hamilton's method in the population of Alabama, reason it is called the [Alabama Paradox](https://en.wikipedia.org/wiki/Apportionment_paradox#Alabama_paradox). That will not be covered here. But this is when **Uncle Bob** comes in the article.

Amongst his **countless contributions** to the software development community, Uncle Bob spread the **SOLID principles**. They were relevant in the 90's, they are relevant now. The principle we are focusing now is the Open-Closed Principle.

We need to change our **Money** class to implement the **allocate** method to distribute its values in ratios without losing any cents. So we created it like:

```Java
public class Money implements Serializable {
  private static final BigDecimal ONE_HUNDRED = new BigDecimal(100);

  public List<Money> allocate(List<BigDecimal> ratios, RemainderDistribution distribution) {
    long amountInCents = toCents();
    List<Quota> quotas = new ArrayList<>();
    for (BigDecimal ratio: ratios) {
      quotas.add(new Quota(amountInCents, ratio));
    }
    distribution.distribute(quotas, amountInCents);
    return quotas.stream().map(Quota::toMoney).collect(Collectors.toList());
  }

  public long toCents() {
    return this.amount.multiply(ONE_HUNDRED).longValue();
  }
}
```

```Java
public class Quota {
  private static final BigDecimal ONE_HUNDRED = new BigDecimal(100);

  private long amount;
  private long total;
  private BigDecimal ratio;

  public Quota(long total, BigDecimal ratio) {
    this.total = total;
    this.ratio = ratio;
    this.amount = ratio.multiply(BigDecimal.valueOf(total)).longValue();
  }
}
```

```Java
public interface RemainderDistribution {
  void distribute(List<Quota> quotas, long total);
}
```

Remember the Alabama Paradox? Even having validated with our Product Manager that we would adopt Hamilton's method we still have some doubts about how this will behave in the user's hands. So we didn't want to have this hard-coded in **Money** class. We wanted to have it changeable whenever needed. We wanted to make our **Value Object** Opened for extension but Closed for modification. That's why **RemainderDistribution** is an interface. One of its possible implementations, the one we used, is **HamiltonApportionmentDistribution**:

```Java
public class HamiltonApportionmentDistribution implements RemainderDistribution {

  @Override
  public void distribute(List<Quota> quotas, long total) {
    long remain = total;
    for (Quota quota : quotas) {
      remain = remain - quota.getAmount();
    }
    List<Quota> sortedQuotas = quotas.stream().sorted(Comparator.comparing(Quota::getFractionalPart).reversed()).collect(Collectors.toList());
    Iterator<Quota> iterator = sortedQuotas.iterator();
    while(remain > 0) {
      remain = remain - 1;
      iterator.next().addRemain(1);
    }
  }

}
```

This way we **solved** that initial problem. where **rounding down we lost 3 cents** (remember that rounding down is due to the cents, similar to when we round a senator down). **The calculation must be done using the smallest unit, in this case, cents**. And we got this result:

|   #   | Proportion | Gross Value | Gross Value in Cents | Final Value |
|:-----:|-----------:|------------:|---------------------:|------------:|
| 1     |      22.9% |    229.0458 |         22904.**58** |      **229.05** |
| 2     |      27.7% |    277.0554 |             27705.54 |      277.05 |
| 3     |       7.8% |     78.0156 |          7801.**56** |       **78.02** |
| 4     |      22.6% |    226.0452 |             22604.52 |      226.04 |
| 5     |        19% |     190.038 |         19003.**80** |      **190.04** |
| Total |       100% |     1000.20 |               100020 |     1000.20 |

At this point I hope I have demystified the intersection between **Alexander Hamilton**, **Martin Fowler** and **Uncle Bob** with the **Financial Systems**. And, as bonus, you get some code to apply in your favorite language. Ah, all this **code was covered with Unit Tests**.

**Bonus**: if you don't know who **Alexander Hamilton** was, there is a musical movie available in Disney+, called Hamilton. It tells the story of this who was the **American First Secretary of Treasury** recorded with rap, hip hop and jazz, directly from the Broadway in 2016. Here's the trailer of this amazing film:

{% youtube DSCKfXpAGHc %}