The check was one line.
If the customer on the order
is the customer on the session,
let them see it.
Two Long values,
compared with a double equals sign.
It passed review.
It passed every test.
It ran for months.
Then the customers
with large account numbers
started getting told
they could not see their own orders.
Not all of them.
Only the ones
whose number was above 127.
Nobody had a customer above 127
in the test data.
The fixtures used one, two, three.
The developer's own account was seven.
In Java a Long is not a number.
It is a box with a number in it,
and the double equals sign
does not ask
whether the numbers match.
It asks whether
you are holding the same box.
For small values
the runtime keeps a shelf of boxes
and hands out the same one every time,
so the same box is what you get,
and the comparison looks correct.
Above that shelf,
every value gets a fresh box.
Two boxes.
Same number inside.
Not equal.
The code was never right.
It was right for small numbers,
and small numbers
were all anybody tried.
That is the part worth keeping,
whatever language you write in.
A comparison that works
on the values you happened to test
has proved something
about those values
and nothing else.
So compare values as values.
Equals,
or the null safe helper,
or unbox to a primitive
before the comparison
and let the compiler
keep you honest from there.
Turn on the static analysis rule
that flags reference comparison
on boxed numbers,
and make it fail the build,
not leave a yellow mark
somebody scrolls past.
Then fix the fixtures.
Test IDs should look like
the IDs in production.
Large.
Long.
Not one, two, three.
Give the test customer
an account number
in the hundreds of millions,
and a whole class of bug
that only lives
above some small threshold
has nowhere left to hide.
Your test data is a claim
about what the world looks like.
Make it a true one.
– Serguey Asael Shinder
Top comments (0)