Live data from Hacker News

Twenty five thousand dollars of funny money

rachelbythebay.com

91–100 of 175 posts

Re: Twenty five thousand dollars of funny money

#91
post #40

I put myself in this very position with some cache expiration times. Almost everything in the server-side that is related to times for a particular client uses milliseconds. Of course, redis’s `SETEX` does not. It uses seconds. The data got quite stale. But, much like this post, other bugs were uncovered and usefully fixed.

For some time the redis-py library had the increment and member argument order of ZINCRBY switched from what standard Redis uses. Of course we didn't notice this small difference.

Debugging this was harddd.

They later switched this around, luckily I read the changelog.

Re: Twenty five thousand dollars of funny money

#92

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.

That won't always work unfortunately, particularly if you have to work globally. For example the fiscalization requirements for cash reporting in Germany specify that all of your transactiona have to be done to 6 decimal places (for things like discounts.)

Re: Twenty five thousand dollars of funny money

#93
Worked somewhere with an admin tool that did something similar. The code had denominated money in cents, except for the Japanese Yen, which has no cents so the number used was just the number of yen. After someone refactored some related code, for a short period of time Japanese users got refunds 100x the amount they were supposed to be.

Re: Twenty five thousand dollars of funny money

#94
My primary codebase ingests data with a mix of seconds, milliseconds, and microseconds. We've held it at bay for a while, but it requires some mental overhead unless we've baked the unit into each variable name.

We're likely to normalize on milliseconds, but at the same time, the implication of floating point arithmetic on all our μs numbers isn't ideal.

Re: Twenty five thousand dollars of funny money

#95
post #88
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…

> 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.baz.omg.wtf.bbq twice) as some crime against humanity exacerbate things. Properly DAMP tests are stupid-simple to fix when the requirements change.

Re: Twenty five thousand dollars of funny money

#96

My primary codebase ingests data with a mix of seconds, milliseconds, and microseconds. We've held it at bay for a while, but it requires some mental overhead unless we've baked the unit into each variable name. We're likely to normalize on milliseconds, but at the same time, the implication of floating point arithmetic on all our μs numbers isn't ideal.

Durations aren't ints, so find or make a type suitable for storing them.

For a similar issue (cache durations that were expressed as a mix of milliseconds, seconds, and minutes) I now insist that the framework type `TimeSpan` is used instead for expressing these durations - as that's exactly what it was designed for.

Re: Twenty five thousand dollars of funny money

#97

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 ...)

BCD is simply "work in base ten on a base two digital computer". What made it good is that it enforces a discipline with the same pattern of rounding errors as base ten arithmetic on pencil and paper. This was particularly attractive when computers were new and replacing "doing it by hand". Bankers were nervous about the new systems screwing everything up, and they wanted the new system to demonstrate it would produce the exact same results as the old system.

To give an illustrative example, what's 2/3 of a dollar? 66 cents or 67 cents, one or the other, choose the same one you would choose with pencil and paper. Now add 33 cents, did you "overflow" the cents and need to increment the dollars?

Yeah, you can achieve the same thing with binary by constantly checking ranges of numbers, but the difference is, BCD when you screw up your code produces errors similar to adding numbers by hand, errors recognizable by your non computer literate accountant; binary screwups will produce a different unrecognizable pattern of errors.

the way it worked was pretty straightforward, just like 4 bits is hex 0-F and 8 bits is 0x00 to 0xFF, a BCD byte is 00-99 and you just never have the patterns for A-F. This was enforced in hardware, in the CPU/ALU

in terms of multi-currency, same thing, you'll see the same familiar rounding problems as traditional pencil and paper currency changing systems.

Also the same set of issues extends to fixed point implementations of "floating point"/"decimal fraction"/"rational number" systems more common in engineering. 1/3 is a .33333.... repeating fraction; 1/5 is .2, no repeat, because 2x5=10 base 10. In binary, 1/5 is a repeating decimal, not good for comparing results, rounding, etc. And you can easily see that the same issue does apply to currency too (it was my example above with 67 cents), it's just a bit less visible because it's less common to use extended fractional amounts.

Re: Twenty five thousand dollars of funny money

#98
post #25

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.

I'm also in the camp that believes that functions or methods that take more than 2-3 (positional) arguments should really take a structure with named keys to avoid this. Humans are bad at lists. Seeing functions with 5-6 positional arguments makes my skin crawl even if they have strong types.

Try to avoid looking at any scientific/data science code then. Almost every function has 6+ arguments.

Re: Twenty five thousand dollars of funny money

#99
post #88
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…

> 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.

Re: Twenty five thousand dollars of funny money

#100
post #88
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…

> 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…

I fend off the "magic numbers" people with a variable with a name that describes what the magic number is for.

  var expectedAccountBalance = 2500
  expect(account1.balance).to eq expectedAccountBalance
  expect(account1.balance).to eq account2.balance
Post reply on HN