💾 Archived View for idiomdrottning.org › inliniac captured on 2024-05-12 at 15:56:11. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
I tend to love inlining and extracting. Whenever something is only used once, I wanna inline. When two things look the same (especially if they’re long), I wanna extract.
(let ((zebra (striped horse (donkey tail)))) (foo (bar baz quux) zebra (bar baz quux)))
I would wanna turn into:
(let ((bbq (bar baz quux))) (foo bbq (striped horse (donkey tail)) bbq))
Sometimes when I am collaborating with people on code, they want me to turn some of those striped horses into zebras, i.e. introduce some new semantic units for clarity and explicitness, and turn some of those repeated bbqs into bar baz quuz if the newly extracted semantic unit is overly abstract and indirect.
And that’s fine, it’s not like I don’t ever wanna compromise. I already have plenty of code in my preferred Idiomdrottning style, and I don’t see it as a huge loss of face to change some bindings around for my friend’s sake. I also sometimes for my own clarity’s sake do introduce some zebras (in the sense of strictly unnecessary semantic units), although I prefer to place them as defines, as their own functions, rather than as a let binding.
In other words, my style preference here isn’t an absolute.
Let’s get an obvious caveat out of the way. Yes, this style means that as the program evolves, I need to be willing to extract what I had previously inlined (if I need to use it elsewhere) or inline what I’ve previously extracted (if I end up only using it once). I always have the “inline”/“extract” perspective on.
That becomes especially necessary when you consider the following: We have a machine that can make popcorn and one for coffee. We see that some of the functions are similiar so we extract them to be the same function. If we later need up having to make the same change to both machines, we’re gonna be really happy that we extracted the part. We kept our code DRY and clean. However, if we end up having to make completely different changes one or both of the machines, we might need to start by inlining. If we always have “inline”/“extract” mindset on, we can spot those situations right away and deal with them. If we don’t, we are gonna suffer. It’s gonna be pretty rough trying to figure out how to add salt to your popcorn and not your coffee.
However, I want to explain a little bit where I’m coming from with this, what’s my motivation and what benefits I’ve found with my style.
This defers making choices about what abstractions to use. The program, as it evolves, creates those for us, just by us extracting what’s used twice or more, or inlining what’s only used once. Please don’t underestimate how awesome this is. It tends to create abstraction levels that are just right, just perfect. Not right away, but, as the program is being worked on and refactored and cared for in this way.
Instead of us trying to abstract a domain’s logic into code, this method just does that for us automatically. That is a wonder that never ceases to amaze me. Don’t worry about those extra bbqs. They tend to end up either sorting themselves out again, or, end up being exactly what the doctor ordered to make sense of the code. (Be careful when coming up with good names for them. As a personal practice, I always call them weird zorky names like “frobnicate” as a placeholder, some thing I know that I’ll replace. If they had been called SyncManagerHandler, that name might’ve stuck. Instead, I want a naming pass after I see what the function does.)
And then you can introduce your extra zebras to the extent that that helps clarity and matches domain expectations.