
Moonpig: a billing system that doesn't suck - phaer
http://blog.plover.com/prog/Moonpig.html
======
bowlofpetunias
> No fucking floats

<rant> Every time I see floats being used for stuff like currency, which is
still more often than not, I'm reminded how very immature and unprofessional
the business of programming still is. This situation has barely improved in
the 25+ years I've been in IT.

For fuck sake, we're not talking "advanced" stuff like architecture,
algorithms, unit testing, SOLID, or whatever, but basic use of simple tools
that's equivalent to understanding that you don't use a hammer to drive in a
screw.

I can't imagine any other profession where basic stuff is executed so
cluelessly unless it's a deliberate scam.

Right now, as we speak, clients and/or employers are paying many thousands of
dollars/euros/whatever to have brand new software build by programmers who
will use floats for what are supposed to be exact amounts of money the core
business of their employer/client depends on.

It's a pathetic state of affairs which makes the phrase "software is eating
the world" an utterly terrifying idea.

And now there's a movement that wants to teach everyone "how to code".

The apocalypse will be caused by a rounding error. </rant>

~~~
ams6110
So how does the latest darling of the webapp world, nodejs, handle this? In
javascript, the only numeric type is float.

~~~
bryanlarsen
The same way you do it in Perl: you store rounded millicents. If there's never
any fraction in your float, your math will never have floating point issues,
and your Javascript VM will use integers internally.

------
gizmo
Although I agree with most of the article, I think the moment the words
"millicents" and "billing system" are used in one sentence you should stop,
drop, and ask yourself what the heck you're doing.

Just save billing stuff in cents and do internal billing math using arbitrary
precision integer math and round to %0.2f at the end. Nobody cares about
mistakes that involve fractions of a cent, or whether their subscription lasts
1 year or 365 days or 52 weeks of 7 days. Just pro-rate in the easiest way
possible and round in favor of the customer. You just don't need any of this
fraction-of-a-cent BS.

If your billing math is easy you can even explain how it works in the FAQ so
customers won't feel cheated. If your billing is complex and uses millicents
in an misguided attempt to "do the right thing" then you can't explain to your
customers how it works and why it's fair. That's no good from the customer's
point of view.

Billing systems are easy to over-engineer and in my experience you just want a
system that's straightforward and correct. That way you can focus your energy
on more important stuff.

~~~
EdwardCoffin
He gave good reasons why they used millicents, one of the best reasons was
that it prevents things like a customer owing $0.006 and therefore getting a
"past due" bill for $0.00. Another was that it prevents real errors from
hiding as possible round-off errors. I found the reasoning convincing myself,
and yes, I have worked in the financial industry.

~~~
gizmo
I agree that using regular floats for money is insanity. Aside from that I'm
not convinced at all, because the situation never arises where you want to
charge people 0.01 cents or 17c for that matter. Who in their right mind is
going to generate an invoice for 17 cents?

If people have a small amount of credit just give them an extra day of
service. If they have a small negative credit either ignore it or subtract one
day the next time they renew.

If there is a case for using milicents I sure haven't seen it.

~~~
dmethvin
As I understood it, the basis for their system was that each customer's
account contains the actual current balance (remaining value) at any point
(any given day). If you charge $10/year for a service that's 2.739726027 cents
per day. You can't have a system like that and round to pennies without some
serious error at the end of a year.

I'm not sure I understand the value of a system like that though. In the
systems I've used and built, most customers see their service as an annual
thing that renews on a particular date every year, for which they pay an
annual fee. Doing it as a daily fee simplifies the special cases like
converting between plans but makes it harder to deal with "your annual plan
always renews on this date".

~~~
EdwardCoffin
The way I understood it is they chose the resolution of millicents because it
was precise enough to allow an annual plan that was never converted to have
this behaviour, yet be cleanly convertible.

------
coherentpony
The naming of this is unfortunate [1].

[1]: [https://moonpig.com](https://moonpig.com)

~~~
triplesec
Quite! I and any others from the UK are likely to assume it's something to do
with an annoying virtual/printing greetings card company.

~~~
bencollier49
Further to which, I suspect this might run into trademark difficulties.

~~~
dangrossman
There's no likelihood of consumer confusion between a billing software package
and a greeting card store. Trademarks are not total ownership of words.

~~~
coherentpony
Those two sentences are completely unrelated. The first sentence is false if
the two companies have the same name. The second is true.

~~~
dangrossman
First, the companies don't have the same name. It's the name of a software
package, not the company that created it.

Second, that's not relevant, but is relevant to the rest of my comment.
Trademark law does not bar two companies from having the same name. There are
_tens of thousands_ of companies with the same name. Most words have hundreds
of separate listings in the trademark registry. Ever heard of Delta the
airline, Delta the faucet company, Acme the laboratory, Acme the furniture
company, Acme the grocery store chain, Apple the computer company or Apple the
record label?

Trademarks are limited both regionally and by the categories of goods and
services the marks are registered under. If there is no likelihood of consumer
confusion, there is not going to be infringement. Moonpig's trademark is
limited exclusively to "printed matter, namely, books in the field of humor,
stationery, greeting cards, and calendars".

------
ams6110
_Times and time zones suck ... Floating-point arithmetic sucks ... Rounding
errors suck ... Relational databases suck_

Guess what, any decent relational database will have a MONEY or at least a
fixed precision DECIMAL type, as well as DATETIME and all the ancillary
functions for computing intervals and adding and subtracting time. Half of
your problems were because you weren't using a data store that properly
represented your data.

------
SideburnsOfDoom
The first time that I heard an annoying advert for the card company
"moonpig.com" I pretty much heard it as
"all_the_good_domain_names_are_taken.com"
[http://www.youtube.com/watch?v=MEBy67ZUrxQ](http://www.youtube.com/watch?v=MEBy67ZUrxQ)

But apparently "moonpig" is not just a totally random name, if two different
groups can come up with it.

~~~
retube
moonpig.com is an interesting startup and exit story. Moonpig was his nickname
at school. He was a rotund child and not terribly popular. he had the last
laugh though exiting for several hundred million.

~~~
tim333
Well £120m. Still pretty good for selling a few greetings cards.

[http://www.bbc.co.uk/news/business-14275632](http://www.bbc.co.uk/news/business-14275632)

------
sime
A relational database would have been a much better fit for this system.

The author initially states that all relational databases are good for is
speed but then goes on to highlight flaws in their object store that could all
have been mitigated by using an RDS:

* schema changes without needing to write programs to update all your data

* data aggregation (and in fact any sort of adhoc reporting)

* data storage independence.

There's also no mention of data integrity but this is a big risk as soon as
the original authors are no longer involved.

Object oriented data stores are hierarchical/network databases. Relational
databases were introduced to replace these years ago and for good reason.

~~~
cmircea
But... if your data is hierarchical in nature, then trying stuff it into a
relational database results in a giant clusterfuck.

Just use the right tool for the job.

~~~
sime
How so? Modern RDBMS' are more than capable of manipulating hierarchical data.

------
moron4hire
I'm not sure I can take seriously anyone who thinks an ACID-compliant RDBMS
sucks for ledger accounting. Is it the RDBMS' fault that you don't know how to
do extremely basic transaction recording? This isn't reinventing the wheel
here, you don't have to design your own schema, there are plenty of examples
readily available on the 'net.

------
madaxe_again
"Happily, Moonpig did not have to deal with multiple currencies. That would
have added tremendous complexity to the financial calculations, and I am not
confident that Rik and I could have gotten it right in the time available."

Yeah, so, that tells me that sadly, regardless of the rest, it sucks (sorry).
Not supporting multiple currencies, as he says, _does_ vastly simplify things,
but is also a massive feature-gap, as any merchant of scale _will_ deal in
multiple currencies. Now try doing it _with_ multiple currencies, and still
avoiding floating point arithmetic. Oh, and also ensure that it'll deal with
charging sales tax/VAT on transactions of £0.01 correctly.

~~~
Borogove
The crazy thing about software is that when business requirements change, you
can change it. If they don't need to support multiple currencies today, it's
silly for them to put in the effort now.

~~~
madaxe_again
Very true, however design decisions made at an early stage can make changes of
that ilk challenging, and even nigh on impossible without significant rewrite,
down the road.

------
zdw
It's interesting to see the differences in design decisions they used vs. the
"ledger" program that I've used for a while ([http://ledger-
cli.org](http://ledger-cli.org)).

Specifically, that ledger internally uses an arbitrary precision library to
store data, then only cuts down or rounds numbers at the display level, and
the use of libraries and a database vs. a file format and highly optimized
code.

------
draegtun
Here's the video of the Pittsburgh Perl Workshop talk this post was _mostly a
rehash of_ \-
[http://www.youtube.com/watch?v=lp2z_ZbLE_I](http://www.youtube.com/watch?v=lp2z_ZbLE_I)

~~~
zellyn
Ugh, he mentions in the post that it was a write-up of the talk.

~~~
draegtun
Yes but the link to the Youtube video isn't provided in his post :)

------
flurdy
Due to the formatting and the use of Perl I had to check the date of the
article as I thought it perhaps was a 10 year old article. But it was from
last week.

But that is current me being a slight code snob as I did use Perl as my prime
language for a few years but that was 13 years ago.

As someone who have worked with many payment and billing systems I can see
some of the pain addressed. But also reinventing the flat wheel is something I
try to avoid and keeping things simple so for example these days I use
BigDecimal, BigInteger datatypes and similar in more modern languages.

Ps. as someone who just ordered cards from moonpig.com, the name was initially
confusing.

~~~
tim333
Yeah it seems kind of an odd choice to write the thing in Perl. I guess they
have some other Perl stuff they want to link it with perhaps?

~~~
seiji
Perl has the most libraries and most active extension system of any
programming language available. It runs the entire Internet.

------
Codhisattva
More a discussion about why not to use PERL than anything else.

Also, hire a branding expert - "moonpig" is awful in every way possible.

