10 ms·
Twenty five thousand dollars of funny money
- richard_mcp 4y agoI'm confused how this was able to give out money before the new code was submitted to production. The author claims that both she and her coworker tested it before the code was submitted and they ended up with the extra $25k. Was this code only executed on the front end? Were there no checks in the backend to prevent employees from just pulling out whatever money they wanted?
- dmix 4y agoThe way she said it ‘crashed’ and you could just reload the page, and that it was frontend work also points to browser js code? So yeah I’m curious how that worked too.
- hk__2 4y agoAs I understand it the code gave you $25k credit, not $25k actual money.
- tartoran 4y agoYeah but you missed the funny part in front of money.
- kleinsch 4y agoFor some systems in that environment, the back-end for dev was actual production. Keep in mind that wasn’t handing out actual money, it was creating ads credit.
- justinator 4y agoLocal was front end stuff, back end was still talking to production.
- rockinghigh 4y agoAs I understand, the frontend and backend code run in a development environment but the funds available were stored in a production database.
- adamsb6 4y agoThe way that things work at this particular company is that you typically test changes in this codebase on your dev machine, but usually the dev machine talks to a prod database. The prod database is too large to practically have a second copy sitting around for testing. Also, if you tested on some pristine small test database you're going to end up missing bugs that would only manifest with actual prod data.
- hermanradtke 4y agoScalars like this are so dangerous. A New Type would help here, but this is much easier to say in hindsight.
- Marazan 4y agoOne of the benefits of learning to program with Ada as the teaching language at University was the instinct to sub_type all the things. IF you're using a raw int you are probably doing it wrong.
- neilv 4y ago> This is yet another reason why I say bare numbers can be poison in a sufficiently complicated system. In Racket, I tended to use keyword arguments, and include the units in the keyword argument. For example, one library used `:velocity-mm/s`. (The `/` character is an identifier constituent, not some special operator syntax.) In Rust, I'm going to try out using language features for static checking of some units (with 0 runtime cost).
- stevedonovan 4y agoYes, the newtype pattern in Rust works very well, say to wrap a string. The somewhat annoying thing is that it is born without any properties so you have to teach it to be comparable, etc from scratch. The newtype pattern in Go is easier to use, but isn't strict enough - your wrapped string can still appear directly in a string concatenation without a cast. Any wrapped integer can still be used to index a slice! Considering how careful the language is with mixed arithmetic (can't add uint8 to uint16 without casting) this feels like an oversight.
- WrtCdEvrydy 4y agoI'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.
- sneak 4y agoI'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.
- deleted 4y ago[deleted]
- disgruntledphd2 4y agoTry to avoid looking at any scientific/data science code then. Almost every function has 6+ arguments.
- JohnBooty 4y agoSeriously, since everything I work in is denoted as "cents" from backend to frontend, I personally had never understood the need This matches my experience. Obviously actual strict typing has its benefits, but as far as developer ergonomics are concerned, IME you can get about 95% of the benefits just by following a convention of including unit names in identifier names. It's easy to see why this Ruby code might fail: def launch_rocket(distance) # what units are we expecting? end launch_rocket(42) But this is virtually impossible to screw up, and reduces developer cognitive load: def launch_rocket(distance_km:) # blahblahblah end # not happening unless developer consumes a large number # of drugs distance_miles = 42 launch_rocket(distance_km: distance_miles)
- Swizec 4y agoEasy! # not happening unless developer consumes a large number # of drugs distance_miles = 42 launch_rocket(distance_km: distance_miles*1.6) Aaaand we're off by 0.3924km. Enough to fit 4 football fields with a few meters left over. Oopsies Units are hard. Never under-estimate the ability of programmers to think they're converting but get it slightly wrong.
- Waterluvian 4y agoI think I like the duck typing in TypeScript more than I dislike it. But I still wish I could say “this function accepts a type called RobotName. It’s a string, but so is RobotUuid, and we don’t want that. So only accept, strictly, objects typed as RobotName.”
- malf 4y agotype robotname = string & {_robotname_marker:true} or some variation. The marker does not actually need to exist.
- jzig 4y agotype RobotName = string; function foo(r: RobotName) {} ?
- chpatrick 4y agoIn TypeScript any type that's structurally the same is considered equal, type just gives it a different name.
- Waterluvian 4y agoYep. But that function will accept type RobotUuid = string; const bar: RobotUuid = “abc…”; foo(bar); This is what duck typing is and specifically my curiosity about being able to de-duck on demand.
- roflyear 4y agoYeah just means you have to rely on linting and your ide to catch those errors. And hopefully the rest of your team does the same thing. Tho I suppose if it is really important you can put an assert there but I'm not familiar with that wrt typescript, maybe the transpiler would kill that? I've done the occasional type checking in that way in similar languages, it is kind of self documenting too. 90% of the time duck typing is what you want.
- tazard 4y ago
- Konohamaru 4y agoType systems are to programmers what dimensional analysis is to physicists.
- ok123456 4y agoYou can do dimensional analysis with type systems. It's part of the F# standard library, at least for integral dimensions.
- dragonwriter 4y ago> Type systems are to programmers what dimensional analysis is to physicists. Dimensional analysis is to data in other domains what dimensional analysis is to data in the domain of physics. Type systems are a tool in which dimensional analysis can be done, or, alternatively, which with which you can restrict data to be being dimensionally aware, allowing dimensional analysis to be done outside of the type system.
- justinator 4y agoI understand this whole scenario is simplified for story's sake but, if there's old_func and new_func, and the new_func call in the else was added that morning, why would the same error of new_func getting the wrong amount of arguments happen weeks before?
- bombcar 4y agoI suspect the new function was an attempt to fix whatever was the backend problem (because before it would work the second time, but give the correct $250).
- denton-scratch 4y agoI wondered that. I thought the bug had been around for a while; I suppose the morning checkin was a failed fix for the pre-existing bug.
- psim1 4y agoThis blogger occasionally seems to throw in stories that are made up for the sake of making a point; this is likely one of them, given the inconsistencies.
- MostlyInnocent 4y ago
- latchkey 4y agoWhere are the unit tests?
- friedman23 4y agoPeople writing unit tests for internal tools? A lot of companies don't even having tests for production code.
- latchkey 4y agoEspecially yes. A unit test would have caught this instantly. It is code that deals with $'s... something you'd really want to test, since it'll cost the company money. Instead, you've got multiple engineers writing code multiple times (my euphemism for fixing buggy code), which also costs the company money.
- friedman23 4y agoI'm just saying people don't do it in practice.
- lovecg 4y agoOh I’m sure there are unit tests for new func and old func that test them separately just fine. The if statement is probably thought of as a temporary switchover kind of thing.
- fbdab103 4y agoI could believe there were unit tests, but not at a high enough level. new_func input:$25,000, output:$25,000. Test passes.
- javajosh 4y ago>I say bare numbers can be poison in a sufficiently complicated system Indeed. It's interesting that the de facto solution to this is to key value pairs, where sometimes the key can be an array (e.g. json, xml, etc), and then one can (kinda) infer units from the key. But even this is insufficient, because inevitably the value is pulled out and it's context is lost. This is, I think, a(nother) powerful argument for immutable values, and accreting structure losslessly with pointers. Like in Clojure. In general we our runtime should support values that have monotonically increasing amounts of metadata added to them during runtime, for example units, or more paths, such that any user of the value can interrogate that structure and find out what it meant to the last people to read or write the value.
- tapvt 4y agoI 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.
- aeyes 4y agoFor 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.
- jacobn 4y agoHad 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 and they'd gotten an overdraft notice. At first I was incredulous ("how is that even possible!?"), then I remembered that we'd just version bumped ActiveMerchant. My endocrine response as I realized what must have happened was amazing to experience - the sinking feeling in my gut, hairs standing up, sweaty palms, dread, pupils dilating, and my internal video camera pulling back poltergeist-style in a brief out-of-body experience. Fun times. Live and learn.
- Eleison23 4y ago>internal video camera pulling back poltergeist-style That cinematic technique is called a "dolly zoom" and it's totally dramatic, if used correctly!
- cratermoon 4y agoAlfred Hitchcock famously first used it in his movie Vertigo, after one of his camera operators, Irmin Roberts, came up with the effect.
- HappySquirrel2 4y agoI made an account just to tell you that I was able to almost feel & experience what you 're describing just by reading your comment. There should be a market for this hah
- mbell 4y ago> 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 expect(account2.balance).to eq 2500 Unfortunately I've run into a lot of folks that take major issue with the later because of 'magic numbers' or some similar argument. In tests I want the values being checked to be be as specific as possible.
- Akronymus 4y agoOne of the things I really like about f# is thar you can tag even raw numbers with types. And even multiply/divide on those types.https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
- fbdab103 4y agoNim as well, they even have an example[0] with currencies. [0] https://nim-lang.org/docs/manual.html#distinct-type-modeling-currencies https://nim-lang.org/docs/manual.html#distinct-type-modeling...
- cb321 4y agoOne can, of course, go much further than simply distinct number types in Nim: https://github.com/ringabout/awesome-nim#science https://github.com/ringabout/awesome-nim#science (Unchained seems maybe the most featureful of those units packages.)
- zdragnar 4y agoThis is probably the one feature from F# that I truly miss in other languages.
- aembleton 4y agoKotlin has type aliases. This means you can write something like: typealias Cent = Int and then use a type Cent just like you can an Int, with multiplication and everything else. More info: https://kotlinlang.org/docs/type-aliases.html https://kotlinlang.org/docs/type-aliases.html
- dragonwriter 4y agoYes, you can, but you shouldn’t to solve this problem, because typealiases aren’t new types, just–as the name suggests–aliases, so anything aliased to Int is interchangeable with Int and everything else aliased that way, so you still have exactly the same problem. Also, cents * cents shouldn’t be cents (though cents * unitless ints should be).
- fefe23 4y agoHad they had unit tests, this would never have gotten that far. Have unit tests!! Could you do other things with those credits, like use them in the cafeteria or resell them? Why were they so frantic to close the loophole?
- fbdab103 4y agoMaybe we are misinterpreting the urgency of the messaging. I could just as easily read it as, "Hey guys having a problem with the pseudo-money credit. Shutdown until further notice."
- wrigby 4y agoNo, the credits could only be used to run ads. However, the ads were run publicly, and competed in ad auctions with campaigns from actual customers paying actual money. If employees had a $25k ad budget, that would mean increasing the demand for ad placement by $25k, which could actually affect the ad campaigns of real customers - definitely not ideal.
- bornfreddy 4y agoTo be pedantic, you would need integration tests to catch this. Both of the units (probably) worked just fine. So: Have unit tests and integration tests!! :)
- mgraczyk 4y agoI encountered a similar bug at the same company with far worse results. Won't say any specifics about the product impact, but our backend passed around two different kinds of user IDs. Each user had two different IDs, and the ID spaces overlapped. User Alice could have an ID in space 1 that is the same as Bob's ID in space 2. At some point, at least one function expected a "space 1" ID but was being passed a "space 2" ID. This meant that content meant for Alice was shown to Bob and vice versa. None of the data was private in this case, so there was no legal problem, but it was pretty embarrassing. I suggested using strong types for the ID spaces instead of `int`, but left the company before implementing any of that.
- Quekid5 4y agoOof, I'm happy it was just non-private data! Regardless, this makes an excellent case for strongly typed wrappers as you mention at the end. Our general approach is to use UUIDv4 for identifiers (so the chance of mistaking-one-for-another instantly leads to "not found"), but sometimes you don't have a choice. In those cases it's super-important to have strongly typed wrappers.
- Twirrim 4y agoSimilar kind of thing, one company I worked for we had two smart-card/badges, I can't remember why. It may have been nothing more unusual than one was the building card, one was the company one. They had an overlapping ID space. Swipe the wrong one on the printer and you got someone else's print job. In my case I accidentally caused a Senior Director's print job to be printed, and luckily it wasn't anything sensitive. I had no end of trouble trying to get IT to accept that this was actually a problem.
- raydiatian 4y agoCritical things come with critical stickers: Transformer boxes, Nuclear waste, Highly acidic compounds, High energy lasers, choking hazards. The oldest debate: should there be a money primitive in the type system? I mean, availability breeds use, use breeds awareness, awareness breeds or enforces proper use. A currency/money type would be a pretty clear label to ward off a whole suite of stupid bugs like the one described in this post.
- mxz3000 4y agoor just units of measure a more general solution than what you're suggesting, implemented by languages like F# https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref...
- raydiatian 4y agoWow that is a cool feature, thanks for sharing. I think there are some other things like fixed-point rather than floating-point decimals for storing/manipulating currency. IIRC, the number 0.1 cannot be precisely represented with floating point system, but that just may be an old wives tale at this point.
- fguerraz 4y agoI thought it was going to be an article about fiat currencies. USD is funny money after all...
- Salgat 4y agoReminds me of in C# how you can pass either an integer for time (usually in milliseconds) or pass in a TimeSpan object. I always use TimeSpan instead of an integer for exactly this reason.
- TillE 4y agoSimilarly, C++11 added a chrono::duration type. It's a massive improvement over the mess of C APIs which might expect anything from nanoseconds to whole seconds.
- cpursley 4y agoI feel like we could avoid some of this if we just allowed databases to do what they're good at. Looking at you Rails...
- cratermoon 4y agoThere are several things happening here worth breaking down. The first is what I've seen called a "gettier"[1]. The idea of "justified true belief" which ends up being true, but not for the reason you thought it was true. That's the case of the first of the bug fixes: She'd exposed the problem with the first change, but it wasn't really the problem. The second item of note is that one paper found 92% of catastrophic system failures come from buggy error-handling code.[2] Arguably this doesn't count as catastrophic, but $25K adds up. The third and final item is the failure relating to the use of a primitive, number' instead of a domain-relevant type, like Money, Dollars, or Pennies. This concept came up as Value Object three days ago[3], which Ward Cunningham's CHECKS Pattern Language of Information Integrity, published in 1994, called Whole Value[4]. I've seen (and, as a young code, written) programs that are full of strings for everything, because that's how the they are represented to users and passed over (some kinds of) network services. This "stringly typed" code infests a project I'm currently engaged with, simply because the back end depends on a bunch of REST/JSON apis and never bothers to deserialize them, but passes them throughout large parts of the code completely unrelated to the api calls. 1 https://jsomers.net/blog/gettiers https://jsomers.net/blog/gettiers 2 https://www.eecg.utoronto.ca/~yuan/papers/failure_analysis_osdi14.pdf https://www.eecg.utoronto.ca/~yuan/papers/failure_analysis_o... 3 https://news.ycombinator.com/item?id=33792874 https://news.ycombinator.com/item?id=33792874 4 https://c2.com/ppr/checks.html#1 https://c2.com/ppr/checks.html#1
- firloop 4y agoWorked 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.
- paulirish 4y agoMy 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.
- SideburnsOfDoom 4y agoDurations 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.
- kevan 4y agoIn a similar vein, in the early days of launching Relay[1] I ended up spending a couple weeks in total squashing timestamp bugs. We were integrating with a few existing systems that used epoch seconds or milliseconds for timestamps and they usually didn't have a hint in the field name to tell what it was so it was really easy to miss in code reviews. Our problems were caused by a mix of serialization format (JSON numbers) and not always converting into the language's date/time types at the boundary (sometimes raw epoch seconds/millis were passed around layers of code and only parsed into a date for display. That created opportunities for misinterpretation at every function call. My general rules for non-performance critical code are 1. Always Parse into a first-class date/time/duration type at the serialization boundary. 2. Always use an unambiguous format (e.g. ISO-8601) for serialization It's not the most efficient but lets you rely on the type system for everything in your code and only deal with conversion at one place. [1] https://relay.amazon.com/ https://relay.amazon.com/
- SAI_Peregrinus 4y agoOne of the first programming languages I learned was TI BASIC on the TI-89. It had an excellent units (refinement types) system: you could define an expression as a "unit" by prefixing a variable with an underscore, and it came with a bunch of built-in units. A unit expression could thereby automatically convert between types as needed, outputing the base unit. E.g. `5_dollars + 8_cents` would output `508_cents`. There was also a conversion operator you could use to change the output unit, so `5_dollars + 8_cents→_dollars` would output `5.08_dollars`. It even worked for more complicated derived units, so e.g. `8_m * 5_kg / (3_s * 4_s)` returns `3.333_N`.
- ant6n 4y agoLooks neat. Of course you can do this in c++.
- SAI_Peregrinus 4y agoOf course, templates are sufficiently complex metaprogramming to achieve this. But it's not a language built-in, or even part of the standard library. F# has a refinement type system built in (which allows this), and of course Haskell and Idris are sufficiently capable in their type systems to trivially support it, but none of those are particularly mainstream general-purpose programming languages. Mainstream languages pretty much all need some sort of library for it, which is unfortunate since they're extremely useful in many common programming problems.
- ant6n 4y agoIn C++, you can do this with custom literals, not meta programming: https://en.cppreference.com/w/cpp/language/user_literal https://en.cppreference.com/w/cpp/language/user_literal One would have to make a library with various classes representing various units, plus the (implicit) conversion between them. It´s probably something that exists somewhere.
- wtallis 4y agoI think TI probably copied that from the HP 48, which used more or less the same syntax. The only difference is that the calculation you show would not have been automatically reduced to _N, but you could use the CONVERT or UFACT commands to get Newtons from kg*m/s^2. In practice, HP's UI made it a lot easier to manipulate quantities tagged with units: hitting the softkey for a unit would multiply the current value by that unit, and using the two shift keys you could either divide by that unit or convert to that unit. If you made a custom menu to put the handful of units relevant to your current problem domain all close at hand, you would need very few extra keystrokes compared with calculating without using the units system. That ease of use is vital; opt-in type safety should be as easy to use as possible, so that users aren't tempted to fall back to the simpler, less safe method.
- caseysoftware 4y agoI was working with [top 5 bank in the US] and hit the same issue with regards to their interest rates between products. Some represented interest rates as a simple number "5%" others as a decimal "0.05" and others as basis points (500). It caused some HUGE problems internally as less clueful loan officers were plugging 0.05% interest rates into formulas for customers. The naming was just as bad. We had columns and fields called intRate, int_rate, interest_rate, and of course iRate. I asked people if they were irate over the problem. No one laughed. :D
- chasing 4y agoJust 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.
- rtlfe 4y agoUsing types that encode the units, as suggested in OP, is strictly better.
- l0b0 4y agoYou're both right, but not all languages give you the choice. And a lot of types are implemented badly. For example as a subclass of a number class, so that `amountDollars + timeSeconds` and other nonsensical statements aren't errors.
- nyanpasu64 4y agoI'm not optimistic on unit types myself. I've found that unit-named variables often with transparent type aliases as documentation (type Sample = usize, type Amplitude = i16/f32) have many of the advantages of distinct units, without their downsides compared to bare numbers. In several projects where I've used naming and transparent aliases comprehensively, I don't recall ever letting a unit mistake escape from my local tree into master, since I reread my own code when committing and merging. In one case (https://gitlab.com/exotracker/exotracker-cpp/-/blob/dev/src/doc/timeline.h https://gitlab.com/exotracker/exotracker-cpp/-/blob/dev/src/... used to have two EXPLICIT_TYPEDEF) I did add distinct units because I found I was mixing together two types too often during development. Though I find that unit types come with significant disadvantages (ergonomic and semantic flaws), making them far from strictly better than bare numbers (much like Rust is far from strictly better than C/C++/Zig): - You need an implicit conversion to eg. size_t, otherwise you can't pass (smp: Sample) into array indexing like (amplitudes[smp]) or data slicing, without an extra conversion or accessing the underlying value like (smp.v). But you can't allow (smp += midi_pitch) to convert both arguments to int, then cast the result to Sample when assigning. - You need some conversion to allow (smp + 1) with type either integer (convertible to Sample) or Sample, unless you want to annotate all arithmetic with boilerplate like (smp + (Sample)1), or (smp.v + 1). I've experienced this problem in my own code, and had to write (smp.v) when my compiler saw (smp + 1) and told me it didn't know whether to wrap 1 or unwrap smp. - Expressions of type Amplitude * 2 should have type Amplitude. Go's time library gets this wrong, where multiplying Duration * Duration = Duration, which makes sense if Duration is an integer like i32 or i64, but not if Duration is a unit system dimension. - (not a regression but a limitation) Units won't stop you from adding two temperatures in Celsius. To fix this you need separate coordinate and displacement types, which is a new pile of complexity. - You may want distinct types for "samples/sec" and "cycles/sec". Modeling this in type systems has multiple current approaches, all of which rely on language support (F#) or complex type machinery I've had issues with. - You can't easily convert between slices of f32 (like an audio buffer provided by the OS), and slices of Amplitude<f32>. Or worse yet vectors of f32 and Amplitude<f32>. (This problem affects bulk data in collections, more than scalar types generally passed and returned in the stack.)
- drpixie 4y agoMakes a good case why most programing languages should not provide simple numeric types - being the types we're so used to using that we don't even think about it. Squashing everything into one or two numeric types leaves us wide open to misinterpretation and confusion. Instead, provide types for length, time, currency, age, angle, count, etc. And provide suitable operations on those types. Then inadvertently passing a pennies as dollars, or adding a time to a length, would be flagged as an error early. (To my mind, the only languages that should provide a "number" type are systems specialised for mathematical use, where it's the mathematicians' fault if they shoot themselves in the foot.)
- bigDinosaur 4y agoF# has units of measure types which seem fairly pleasant: https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref... along your ideas. You can also do your own version easily in something like Haskell. At first thought it'd be much more challenging in everything else assuming you don't want to encapsulate everything in voluminous custom classes or something.
- kristianp 4y agoThis discussion reminds me that F# has units of measure support in the language. For example constants can be annotated with units[1]: 1.0<cm> 55.0<miles/hour> Tangentially, it also reminds me that some popular languages don't have a binary coded decimal type for example go and java(?). C# and standard sql support decimals, so your $1.02 doesn't get approximated as $1.01999999 Go has at least 25 community decimal packages[2], but who knows which is a good one to use. [1] https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/units-of-measure https://learn.microsoft.com/en-us/dotnet/fsharp/language-ref... [2] https://pkg.go.dev/search?q=decimal&m= https://pkg.go.dev/search?q=decimal&m=
- credit_guy 4y agoWhat amazes me is the software running the banking accounts. Whenever I go to an ATM machine, and I get the receipt, I never for a moment think they can be wrong by even one cent. Because they've never been wrong. From time to time you hear of a case where someone found a million dollars in their account, but this gets to be reported in newspaper. And to be honest I don't even remember how many years ago I read such a story. I imagine there are tens of millions of people accessing their bank accounts every single day. A bank like Chase or Bank or America, or Wells Fargo probably processes millions of transactions per second. With essentially zero errors. Meaning 99.99999999% correctness, with too many nines to count. How is that possible? Not to mention, these guy are probably under hundreds of hacker attacks per day.
- bokohut 4y agoThis one brought up yet another tech memory to share from the past. I was the founding architect of a real-time payments company in the mid 1990s which at the time was processing for a very well known, even to this day, ‘use your email to pay’ company. My position as the architect and critical core software developer brought me into many problems that were others, both in business and in technology. As the leading technology based payment processor at that time along with our large volume we had a relationship with a bank that had another smaller processor which suffered a breach, one of the first widely reported. This smaller processor was "consumed" by us, unknown why nor can I recall atm but back then it was much different working with the large card brands and banks, and we therefore were transferred all their assets including source code. I was tasked with finding the areas of compromise within the software systems designs having already rearchitected our core systems to XML and microservices long before such ideas were even considered. In performing a source code review of what was a monolith written entirely in Visual Basic 6 I discovered whoever had written it decided that they would treat themselves to much greater than 25K of real fiat currency. Someone had added to the if statement on checking the credit card number that upon matching a specific series of numerics no outbound card brand API call was made and this transaction was auto approved, no other checks, and this code was in production. Those reading this far can likely deduce the potential of such a single if statement.