Aug 12 2024
There’s an old saying:
There are only two hard things in Computer Science: cache invalidation and naming things.
― Phil Karlton
I also appreciate the joke version that adds “and off by one errors.”
Lately, I’ve been thinking about this saying, combined with another old joke:
“The patient says, “Doctor, it hurts when I do this.” The doctor says, “Then don’t do that!”
― Henny Youngman
Specifically, if naming things is so hard… why do we insist on doing it all the time?
Now, I am not actually claiming we should stop giving things names. But I have had at least two situations recently where I previously found names to be kinda critical, and then I changed to systems which didn’t use names, and I think it improved the situation.
One of the most famous examples of not giving something a name, lambdas/closures, took some time to catch on. But many folks already recognize that naming every single function isn’t always neccesary. I wonder if there are more circumstances where I’ve been naming things where I didn’t actually have to.
Anyway, here’s my two recent examples:
Nameless Branches
I haven’t written much about it on my blog yet, but I’m fully converted away from git to jj. I’ll say more about this in the future, but one major difference between the two is that jj has anonymous branches. If, like me, you are a huge fan of git, this sounds like a contradiction. After all, the whole thing about branches are that they’re a name for some point in the DAG. How do you have a nameless name?
Here’s some output from jj log
:
Here’s some sample output from jj log:
$ jj log --limit 5
@ pzoqtwuv steve@steveklabnik.com 2024-03-01 15:06:59.000 -06:00 9353442b
│ added some cool new feature
│ ◉ xrslwzvq steve@steveklabnik.com 2024-02-29 23:06:23.000 -06:00 a70d464c
├─╯ create hello and goodbye functions
│ ◉ yykpmnuq steve@steveklabnik.com 2024-02-29 23:03:22.000 -06:00 210283e8
├─╯ add better documentation
◉ ootnlvpt steve@steveklabnik.com 2024-02-28 23:26:44.000 -06:00 b5db7940
│ only print hello world
◉ nmptruqn steve@steveklabnik.com 2024-02-28 23:09:11.000 -06:00 90a2e97f
│ refactor printing
Here, we are working on change pzoqtwuv
. (@
means the working copy.) There
are colors in the real CLI to make the differences more obvious, and to show you
unique prefixes, so for example, you probably only need p
or pz
instead of
pzoqtwuv
to uniquely identify the change. I’ll use the full IDs since there’s
no syntax highlighting here.
We have two anonymous branches here. They have the change IDs of xrslwzvq
and
yykpmnuq
. The log output shows the summary line of their messages, so we can
see “create hello and goodbye functions” on one branch, and “add better
documentation” on the other.
You don’t need an additional branch name: the change ID is already there. If you
want to add even more better documentation, jj new yykpmnuq
(or again, likely
jj new yy
in practice) and you’re off to the races. (jj new makes a new change
off of the parent you specify.)
(And if you’re in a larger repo with more outstanding branches, you can ask jj log
to show specific subsets of commits. It has a powerful DSL that lets you do
so. For example, say you only want to see your commits, jj log -r 'mine()'
can
do that for you.)
That’s all there is to it. We already have the commit messages and IDs, giving an additional identifier doesn’t help that much. In practice, I haven’t missed named branches at all. And in fact, I kind of really appreciate not bothering to come up with a name, and then eventually remembering to delete that name once the PR lands, stuff like that. Life is easier.
Utility CSS
Another technology I have learned recently is tailwind. But Tailwind is just one way of doing a technique that has a few names, I’m going to go with “utility CSS”. The idea is in opposition to “semantic CSS.” To crib an example from a blog post by the author of Tailwind (which does a better job of thoroughly explaining why doing utility CSS is a good thing, you should go read it), semantic CSS is when you do this:
<style>
.greeting {
text-align: center;
}
</style>
<p class="greeting">Hello there!</p>
Whereas, with Tailwind, you end up instead having something like this:
<p class="text-center">Hello there!</p>
We don’t have a new semantic name greeting
, but instead describe what
we want to be done to our element via a utility class.
So the thing is, as a previous semantic CSS enjoyer, this feels like using inline styling. But there’s a few significant differences. The first one is, you’re not writing plain CSS, you are re-using building blocks that are defined for you. The abstraction is in building those utility classes. This means you’re not writing new CSS when you need to add functionality, which to me is a great sign that the abstraction is working.
It’s also that there is some sleight of hand going on here, as we do, on another level. An objection that gets raised to doing things this way is “what happens when you need to update a bunch of similar styles?” And the answer for that is components. That is, it’s not so much that utility CSS says that semantic names are bad, it’s that semantic names at the tag level are the wrong level of abstraction to use names. To sort of mix metaphors, consider the lambda/closure example. Here’s a random function in Rust:
fn calculate(list: &[i32]) -> i32 {
list.into_iter()
.filter(|i| **i % 2 == 0)
.sum()
}
The **
is unfortunate, but this function takes a list of numbers, selects for
the even ones, and then sums them. Here, we have a closure, the argument to
filter
, but it’s inside a named function, calculate
. This is what using
Tailwind feels like to me, we use names for higher level concepts (components),
and then keep things semantically anonymous for some of the tasks inside of them
(markup).
Heck, even the most pro-semantic-styles folks don’t advocate that you must give every single element a class. Everyone recognizes the value of anonymous things sometimes, it’s just a matter of what level of abstraction deserves to get named.