Live data from Hacker News

Twenty five thousand dollars of funny money

rachelbythebay.com

121–130 of 175 posts

Re: Twenty five thousand dollars of funny money

#121

Earlier quoted context omitted.

Could you expand on BCD? What made it good for multi-currency work? (a quick google did not help, managed to lead to examples of COBOL manipulating the first five letters of the alphabet ...)

Binary Coded Decimal allows for perfect representation of numbers by not restricting you to 4 or 8 bytes. It trades speed and memory efficiency for precision and simplicity. https://en.m.wikipedia.org/wiki/Binary-coded_decimal

It allows, like all encodings, a perfect representation of some subset of real numbers but not the rest.

In particular it perfectly represents numbers which are commonly used in modern commerce, like 19.99 or 1.648 (the current price per litre of fuel near me). It's not great at other numbers like pi or 1/240.

Re: Twenty five thousand dollars of funny money

#122

Just to say it, for measurements that take a unit I am hardcore that you should include the unit in the variable time: `timeSeconds` `distanceMeters` `amountDollars` Have unit tests and everything, but also write your code so that when someone reads it they know as precisely as possible what's going on without other documentation.

Using types that encode the units, as suggested in OP, is strictly better.

Re: Twenty five thousand dollars of funny money

#123

Earlier quoted context omitted.

You don't need "strict typing" to handle money; in the old (COBOL) days, we used BCD to represent monetary amounts with arbitrary precision. When they took away BCD, we were stuck, if we wanted to build a system that could represent a large sum correctly in both dollars and yen. COBOL was pretty good for dealing with money.

Could you expand on BCD? What made it good for multi-currency work? (a quick google did not help, managed to lead to examples of COBOL manipulating the first five letters of the alphabet ...)

I appreciated BCD because the in-memory data represented in hex (as by an 80's era debugger) was exactly the decimal value. As I recall, debuggers of that time only understood two datatypes: ASCII characters and hex octets.

On consideration, I think my COBOL compiler's ability to define arbitrary-precision fixed-length numerical variables wasn't down to the use of BCD; you can do that with other binary encodings. But I worked for Burroughs at the time; their processors had hardware support for BCD arithmetic, so it was fast. The debugging convenience came with no great cost.

Re: Twenty five thousand dollars of funny money

#124
post #95
post #88

Earlier quoted context omitted.

> Our test harness didn't catch it (weird combination of reasons, too long ago for me to remember the details) & it rolled out. This is why I'm pretty dogmatic about variable comparison in tests. This is dangerous and stuff like this has caused a lot bugs to slide though in my experience (and maybe ops): expect(account1.balance).to eq account2.balance This is safe and specifc: expect(account1.balance).to eq 2500 expe…

One of the tenets of unit testing, I don’t know if I derived this for myself or got it from someone, is that you get a lookup on the right side of the expectation or the left, but not both. There are too many yahoos out there writing impure functions or breaking pure ones that will mangle your fixture data. And the Sahara-DRY chuckleheads who see typing in 2500 twice (but somehow are okay with typing result.foo.bar.b…

I get the intention, but a simple x = 2500 would satisfy both worlds.

Re: Twenty five thousand dollars of funny money

#125

Just to say it, for measurements that take a unit I am hardcore that you should include the unit in the variable time: `timeSeconds` `distanceMeters` `amountDollars` Have unit tests and everything, but also write your code so that when someone reads it they know as precisely as possible what's going on without other documentation.

At that point, why not have dedicated types and get rid of primitive ones? It shifts all that work to the compiler, whose job it is to excel at this kind of stuff (adding cents to penny types does the right thing automatically etc).

Re: Twenty five thousand dollars of funny money

#126

Earlier quoted context omitted.

You should define separate types for “cents” and “dollars”. And, probably operations to convert between the types.

You can have a single type for “money” (or maybe just “us_money”) with separate cents/dollars/mills factories and accessors, and no access to a numeric value except through the accessors. You can do similar things with other dimensions like “length”. Or you can go whole hog, and have a single “type” for unit-aware values from which you can only successfully extract a unitless number by specifying a unit which is dime…

In physics, dimensionality makes sense. How would one handle money? Can it be represented the same way? A new dimension, next to length, time etc? It would allow to express money per time, eg dollars per second, for example.

Re: Twenty five thousand dollars of funny money

#127
post #41

Had exactly that bug in production, was using ruby on rails & active merchant, and some version change in ActiveMerchant switched from cents to dollars for one of the integrations. Our test harness didn't catch it (weird combination of reasons, too long ago for me to remember the details) & it rolled out. Shortly thereafter I get an anxious customer call that we'd charged their debit card $2500.00 instead of $25.00 a…

Reasonableness checks are nearly absent these days. Warning the user "that's a lot of money/a date far in the future/a large quantity.[1] Are you sure?" detracts, I suppose from the UX. Except it really doesn't. 1. "Reasonable" varies according to the particular situation (customer's order history, credit rating, the normal range of quantites for the product, etc.)

I think it's more that it's a game of whack-a-mole. There are an infinite number of possible scenarios you could warn about, and each one carries a small cost to implement, a small cost to maintain, and a risk of false-positives. Which ones are worth implementing can be hard to know ahead of time (implementing ones that have actually caused problems would be one strategy for narrowing it down, but the point remains that it's not as simple as "just check for all the unreasonable states")

Re: Twenty five thousand dollars of funny money

#128
post #87

I'm gonna be honest, I had never understood the "strict type" argument until right now. Seriously, since everything I work in is denoted as "cents" from backend to frontend, I personally had never understood the need so I'm part of today's lucky 10,000th.

Strict types have little to do with this. Unless your type system validates bounds , this sort of things happens regardless of types.

At the very least, strict types:

1) make you do the check

2) only require you to do the check once

Re: Twenty five thousand dollars of funny money

#129
post #88

Earlier quoted context omitted.

> Our test harness didn't catch it (weird combination of reasons, too long ago for me to remember the details) & it rolled out. This is why I'm pretty dogmatic about variable comparison in tests. This is dangerous and stuff like this has caused a lot bugs to slide though in my experience (and maybe ops): expect(account1.balance).to eq account2.balance This is safe and specifc: expect(account1.balance).to eq 2500 expe…

Various things like "manual to change them" that make "magic numbers" bad in regular code make them good for testing (or at least less bad, a constant for that is still what I'd usually use, but a pretty specific constant, sometimes at the unit test level - shared ones get dicey). Agreed on the ease of having problems of using variables on both sides.

One of the biggest ways that test code is not production code is that test code is only read by humans when the tests are failing. Whereas any time I'm working on a regular feature I am likely to be looking at log(n) lines of our codebase due to the logic that exists around the code I'm trying to write, and changing loglogn lines of existing code to make it work - if the architecture is good.

Code that is write once read k < 10 times has very different lifecycle expectations than code that is constantly being work hardened.

Re: Twenty five thousand dollars of funny money

#130
post #88

Earlier quoted context omitted.

> Our test harness didn't catch it (weird combination of reasons, too long ago for me to remember the details) & it rolled out. This is why I'm pretty dogmatic about variable comparison in tests. This is dangerous and stuff like this has caused a lot bugs to slide though in my experience (and maybe ops): expect(account1.balance).to eq account2.balance This is safe and specifc: expect(account1.balance).to eq 2500 expe…

thanks. i do the same and consistently have to push back on reviewers (why don't they learn?) that the hardcoded number is there for a reason

What the complainers often like to do is hoist variable declarations out of the local scope. So to them having a test suite that uses 1500 in four places is wrong, and up to that point they are perfectly right.

The trick with the constants is that if they are declared and used in the same test scope, then the data is a black box. Nobody else 'sees' it, nobody interacts with it. The only time that's not true is when there's false sharing between unit tests and those tests are fundamentally broken. In that case the magic number is not the problem, it's the forcing function that makes you fix your broken shit.

Post reply on HN