2025-04-27

Why did all the numbers move to the back of my credit card?

One of my credit cards has a feature that baffles me: all the numbers are on the the same side1 of the card.

Now, credit cards present an interesting trade-off problem between security and convenience. Bruce Schneier spends some time on the matter in one of his books. Maybe Liars and Outliers. A certain level of loss to fraud is accepted to ensure that the system is convenient and ubiquitous; and the history of the technology is an epic tale of continual re-tuning of the risks.

In the very early days the system was surprisingly simply, relying on people and paper. Really. By the time I came on the scene, the cards had raised numbers on the front to impress multiple copies of the transaction record on carbon papers. The "chunk, chunk" of the cashier making the impression was the sound track of eighties retail. Later we got smart cards and now touchless payment.2

Hey, Ma! Look at me! I'm living in the future!

And somewhere along there (late '90s) the "card security code" was added to the back. It didn't show up on the mechanical impressions (still in use then in the US, if not in really advanced parts of the world) or in a single-sided xerox of the card, so it made it slightly harder for bad actors to capture enough information to create fraudulent charges. Not really hard, mind you. Just hard enough. That's one of the surprising things about this story.

But now I have this card that has the CSC printed right next to the main card number and expiration date.3 Huh? Is that Okay because merchants are now using billing zip code as an additional (if very weak) authenticator? Or is it something else?


1 The side with the magnetic strip and opposite the conductive pads which I would describe as the back, but it's the fact that they're all on the same side that bothers me.

2 The touchless systems marks one of the first moments I started to feel like technology was leaving me behind. Another unanticipated milestone.

3 It also has the main numbers printed flush on the surface of the card: they're not raised.

2025-04-16

This hard programming problem keeps butting its head into my workflow!

The design (sometimes architecture) of a non-trivial program's source code and build is replete with problems. Multiple books are written on the matter every year. The code goes into many different files which are stashed in multiple folders. If you're paying attention the folders represent elements of a modular build. Mostly.

Architecture level problems come in lots of kinds, but the ones I want to focus on today are excessive interconnectedness of logical units, and excessive interconnectedness of build-time units. The former makes the code hard to reason about because when I'm look at a bit of code here I may not know if some bit of code in a different folder is going to reach in and change something when I least expect it. The latter driving up build times. Both can make changes that looked initially confined to a single file cause adjustments in many other files.

So now we have two things to keep in mind:

  1. The organization of files in the file-system should parallel the build organization.
  2. File should know as little as possible about other code units and especially about units in other build modules.

So, when one bit of code needs to know a lot about another bit of code it goes nearby. Maybe in the same file, and almost certainly in the same build module. Fine.

Now consider the "extract function" feature of your programming environment.1 It's a shining example of good tooling as it encourages and helps with refactoring. But it usually crashes me right out of the zone. Because if I'm creating a new "piece" of code and I have to find it a home. And that can be hard.

Some cases are easy.

  1. If it's coming out of object's instance function (AKA method), and it needs to access instance state then is must live in the object.
    1. If it does not respect the class invariants then it must be private. Except that if it is virtual then you may want it to be protected2
    2. Otherwise it can be public. But start with it private until you know of a use case: every API you expose is one you have to maintain.
  2. If it is reaching into another class's object, then consider moving it to that class.

But after that it starts getting tricky. I mean, it can be a free function or a class static, but where should it live?!? If it is highly specific, perhaps keep it in the file it's in (and perhaps even private), just with a name now. If it represents a specific behavior within the domain modeled by this module, make it it accessible throughout the module (new files, class static, who knows?). If it's very general purpose, first look to see if you missed it in the standard library or any frameworks you're using, and if not put it in your project wide utility code. Maybe?

In any case, having to make these decisions often knocks me out of my flow. And since it doesn't have a name that I know of I haven't been able to google advice.


1 Obviously you don't actually need a tool for this. I got on fine with cut-n-paste for decades. Still do when certain IDEs (no names, Qt Creator you .... you ... wonderful program) just refuse to have it enabled for some mysterious reason. But I will sure as heck use the tool if present.

2 I'm largely using the C++ nomenclature here because that's the sea I swim in daily, but I think the considerations apply more broadly.

JSON Update

A followup to a recent rant.

First an admission. At least one thing I complained about was not a feature of JSON per se but of the library (nlohman::json AKA JSON for Modern C++) that we're using. In particular the behavior of serializing a floating point IEEE-754 special to null, and then throwing when trying to deserialize a null into a floating-point variable is library specific. And they stand by it. Grrrr!

Second, by defining a strong-typing wrapper I was able to (de)serialize those values from-and-to strings. I even provided multiple acceptable spellings on the deserialize path. Then by writing explicit to_json and from_json routines for my objects (rather than relying on the handy-dandy macros in the library) I was able to apply the strong-types only at the point of (de)serialization reducing what initially looked like a major intrusion into the code. Yeah.

It's not a complete win, however, because I have a std::variant in the code-base. The usual advice for deserialize a variant with the library is to detect the json-type of the value1 and use that to know which member type to set. Only the number can give rise to a string value. So I had to explicitly (de)serialize the current-type, too. Bletch!

Long story short. We're going ahead with this and I may replace ny custom interchange format after all. Just because other users will stand a better chance of decoding the JSON.

But the lack of infinity and not-a-number is still a bug and still renders the format poorly suited for use in numeric computing.


1 JSON for Modern C++ uses a domain-model object as an intermediary, so this is relatively easy.

2025-04-11

No really. Should I use that library function that I shouldn't use?

The world would make more sense had it happened this way:

Shoot in grainy black and white.

Scene: a sprawling cellar lit by torches and candelabras. Brick archways lead in multiple direction. All the spaces we see are filled with abandoned experiments, strange equipment, and untidy storage. Some of the bits spark. Others bubble. Here and there tables are covered with books, notes, and abandoned comestibles.

Richiestein: "Igor, the world degenerates. Many programmers loose their edge, hiding every day behind strong guarantees from safe environments.1 We must bring LIFE back to the demons and dragons of yesteryear!"

Igor: "Yes Master"

Richiestein: "I needs a way, Igor; a way to trap programmers. To make it easy for them to err; easy to use memory they do not intend."

Igor: "Oh, master. Igor knows. Igor is sure master. You must use sentinel terminated strings, master!"

Richiestein: "Will that help?"

Igor: "Oh yes, master!"

Richiestein: "Will they not see that it is a bad design?"

Igor: "Master must tell them it is for simplicity. And show them correct code saying that it is elegant and basic. Maybe write a book?"

Richiestein: "I suppose."

Richiestein: "But can I get them to overrun their buffers that way?

Igor: "Oh yes master, let Igor show you!"

Igor hurries to a crowded corner of the room and digs frantically through trunks and shelves before returning triumphantly to show the good doctor what he has found.

Igor: "See here, master, I have gets!"

The doctor squints at the jagged and rusty artifact before looking sharply at his assistant.

Richiestein: "Would anyone accept something so obviously cursed as this? Surely not?"

Igor: "They will, Master! They will! You need only put it in the Standard Library master!"2

Richiestein: "Hmmm. We'll try it. But we also need something more subtle. Something that looks like it would work. Maybe something that only brings disaster occasionally. Do we have that, too?"

Igor: "We do, Master!"

Igor roots through another corner of the cellar before bringing a many-geared contraption of only slightly tarnished brass.

Igor: "See master: snprintf. A powerful tool, but if it runs out of space no sentinel is placed, making their string a trap!"

Richiestein: "Oh, that one is better. It almost works."

Exuant. Laughing.

Sadly it's so much more likely there were making only what they really, really needed (and would fit in the very small machine they had on-hand) and intended to come back and fix it later. That's the way these things usually happen.

I do know the danger

The standard library function snprintf3 guarantees to not overwrite the buffer (assuming of course that the programmer passed the right length). Which looks so promising, but they don't guarantee to write a terminal '\0'. They only add that if there is room left in the buffer.4

So, if you use snprintf to fill in a buffer and run out of room without noticing (always get the young man's name and address check the return value!), and are later so incautious as to try to measure the length (with strlen) there'll be no terminator and you read off into random memory until you encounter a zero byte. Or a seg-fault. Or nasal demons, of course.

And it can get even worse.5 Say you think you want to perform an in-place tokenization with strtok.6 Now you can be writing past the end of the buffer.

And, yet, I still use the function

And yet, when I exhibited my nifty "safe" string builder for c, I used vsnprintf. Twice. Even though it's a trap. What gives?

grug quite satisfied when complexity demon trapped properly in crystal, is best feeling to trap mortal enemy!

The answer, of course, is that by using it very carefully in just one place I intend to relieve future programmers (including my future self) from the need of using it repeatedly elsewhere.

I also put prominent comments in, not so much to convince future readers as to make sure that I was paying attention, though they should serve as a alert for future readers too. They'll have reason to read the docs with "how long" and null termination in mind. I hope.

When is it a good idea, again?

So ... it's sometimes okay to mess with the magic lamp? Really?

Honestly, that function is dangerous, and the comments don't fix it. If I were developing a non-trivial code in c as a green field project, I'd give real consideration to not using big parts of the c standard library starting with string.h. But the use case that drove me to thinking about it in the first place was maintenance on a statically-linked launcher for a C++ project.7


1 Okay, so strong guarantees were few and far between in the early 1970s. but, this is Hollywood! Work with me here.

2 And don't call ne Shirley!

3 Or its variadac sibling vsnprintf.

4 Cue Admiral Ackbar.

5 As far as the standard is concerned this is exactly as bad as before—undefined behavior—but from a practical point of view it is more immediately destructive.

6 You probably don't, really. For several reasons, but take it arguendo.

7 It is harder to write a C++ program you know will "just work" on a target machine, then to do the same with a C program. Especially on windows. So we have a little program written in c that should "just work". It is suppose to detect the environment, set up the prerequisites for the big C++ code, produce a clear error message if it can't, and then launch the main app. It does a lot of string manipulation. But it's been there a long time and it works; there is no way I could justify switching string libraries wholesale.