“First in, first out” may seem fine at first sight, but if your access pattern is periodic, it may mean you just threw away the data you need, and kept around data you won’t need for 11, 10, 9, 8,… months. Also, why throw away data that’s needed, statistically, once a second, and keep the data that was read in for that one of a time query?
Also, quality of service might affect caching choices. If you need room on a factory floor, you don’t move the fire extinguisher to the back room, even though you know you likely will not use it.
Similarly, you might want to prefer caching data of web pages more likely to be visited, or even that of customers paying more.
Properly ensuring that when a value changes (and thus any cached copies become invalid) then every place where that value might be cached properly and timely invalidates [that part] of the cache, because otherwise other parts of the system will see stale/wrong/conflicting data which generally results in 'fun'. And it appears everywhere from memory reads in a single multicore processor (where one core might change a variable that the other core has cached) to globally distributed data storage systems with eventual consistency to state shown on the user's screen as the underlying data is getting mutated by someone/something else.
To me, the original quote, "There are 2 hard problems in computer science: cache invalidation and naming things" is intended to be striking by putting naming things at the same level of difficulty as cache invalidation, while naming things might seem an easy problem… at first. The point of the quote is to be a warning on the fact that while cache invalidation is notoriously hard, naming things is hard too.
Ah, that makes sense to me, thanks. I just figured the difficulty levels the other way around, so the “punchline” couldn’t work. Guess I’m glad the most complicated caches I work with are mostly “if it’s at least this old, refresh it” ;)
etc, etc, etc.
Even that simple example is not remotely easy if "if it's at least this old, refresh it" is an actual requirement. Thankfully most of the time it's not, and the requirement is actually "refresh it every once in a while, about this often, but none of this is particularly important so it doesn't have to always work"
https://www.martinfowler.com/bliki/TwoHardThings.html
If you're not careful with what you cache, you end up with bugs unless you invalidate the cache carefully. And doing that carefully is in itself surprisingly difficult and error-prone, unless you come up with a comprehensive scheme, at which point you probably no longer have a what we call a cache but more like a secondary index with performance/concurrency problems on it own.
It doesn't seem hard until you've been there and given up.
I think the same is true for naming. If you told someone new at programming that naming is the most difficult part, they'd laugh at you and continue using quickly thought up, confusing names that cause them to introduce bugs because they misunderstand themselves.
Cache invalidation is a true challenge.
Naming things is a true challenge too. Same level of complexity (if not more) as cache invalidation since it deals with psychology of the user/programmer, patterns of thinking, etc.
Naming things is "hard", as names tend to stick forever. Later, names may miss the moving target of recent changes.
Off by 1 errors, refers to the list itself (joke). You either spend extra effort reducing their possibility upfront, or get dragged into hours/days trying to dechiper only to discover it was a off by 1 error. Programming needs to be exact, to be correct, and very few are consistently avoiding such subtle flaws in code logic.
When you have to explain the joke, it's not funny anymore! :D
Yes. It's a problem that repeats across the computing stack, can cause maddening edge-case errors, and doesn't (can't, in the general case) have a clear perfect solution.
It's literally that cache invalidation is hard. You can also think of "cache invalidation" as a substitute of concurrent programming: keeping multiple related threads of logic synchronised.
>Isn’t cache invalidation on a completely different level as naming things, both conceptually and in difficulty?
I'd say it's on a conceptually different level, but not less difficult, and because "naming things" is easy, it's more insidious.
From my point of view "naming things" is a substitute for architecting software instead of coding your way out of dead ends whilst inventing a lot of off the cuff names in the process. (of course, in the current climate, such ad-hoc solutions are now the standard, called "design patterns", and people find names that have "Factory" in them twice a normal thing.)
do you know a better name for "window manager"? i don't mean to hold that up as a paragon of great naming, just genuinely curious what you'd call it.
like, i'm no fan of AbstractFactories (or classes for that matter), but i never quite got this sentiment. to me, "manager" suggests that you have a bunch of resources that should be centrally managed (created/freed, whatever), and theres's something (perhaps an object) that handles that.
ofc it's really generic, and a more concrete name should be used if possible, but i wouldn't say it's meaningless
As to naming things, I seem to feel that good naming tends to go hand in hand with good abstractions, good model of the world; this is not as easy as "copying" relations from the real world to the computer (your stereotypical "cat is-a animal" which may result in surprising problems), but finding models and ideas that are at the same time simple & elastic & robust at representing some core essential concepts of the real world. Sorry I can't give specific examples, I feel those moments are often surprisingly vague and local. Also, I may just be overinterpreting this quote...
Cache invalidation has a risk of both false positives (something got evicted from the cache but shouldn't have) and false negatives (something should have been evicted but was not) and the effects of errors can be invisible, annoying, or disastrous, depending on the situation. Incorrect cache invalidation usually results from incorrect dependency management.
Naming is hard because names have a conflicting combination of requirements: names need to be short (they will be repeated often), expressive, accurate, unchanging, and easy to remember. It's often quite difficult to find a name for a concept that fits all those requirements. My company has spent years finding the right names for certain core concepts, but that is time well spent.
Also, I know that hex is cooler, but "0xF" is 33% longer than "15", is it really better? :) Of course in this kind of artistic/prosaic text it doesn't matter, express yourself and so on, but I find it really annoying in code.
Some people think that in C, the integer literal 0xff is more "byte-like" than 255, when they are really exactly the same (both have type 'int'). Pet peeve.
You are technically correct.
However the meaning of the number for purposes of bitwise operation or other relationships to binary can often be more _immediately_ obvious when using hex. Certain regularities that are present in base 2 are also present in base 16 since the base is itself a power of 2.
The simplest example is the one you gave 255 = 0xFF = 0b11111111 where the intent is very often a mask. However things get less immediately obvious with larger numbers 0xFFFFFFFF = 4294967295, so it's essentially about clarity, and even for the case of 255 which is obvious to most, it still solidifies the intended meaning.
Obviously in this article it's pure geekery and there is no objective defense, but i love it anyway :P
When I'm doing bitwise arithmetic, or poking hardware registers, I think in hex. 0xff/255 isn't a good example because that's easy offhand but a lot of other values take longer to "parse" in base 10. It depends on the context whether base 10 or 16 literals are easier to read and parse for humans.