morning
morning all, happy friday! My new Clojure proverb is "avoid excessive indirection". The second chapter of Edvard Tufte's Envisioning Information captures this beautifully, titled "Micro/Macro". But now I cannot find my copy of the book 😢 … To me, "avoid excessive indirection" nails why Ring is good — it gives full access to the information model of HTTP, without introducing unnecessary layers that imposes arbitrary limitations.
I subscribe to this proverb too. Indirection breaks code analysis, both of the static variety and the one in your head. It is also usually a sign of an over-engineered design, though that it IMO secondary to the indirection itself. Obviously, you can't always avoid it.
Indirection breaks code analysisI label "too much function calling" as excessive indirection too. You're maybe thinking more in terms of interfaces / multimethods / type classes?
Not really. I am thinking about code in general. Often frameworks (of any kind, really) will introduce indirection through e.g. dependency injection.
"too much function calling" AKA "syvende far i huset-kode" 😄
e.g. I use Pedestal for all of my web projects, but just adding that single layer of indirection makes tracking errors much more bothersome. The stack traces are enormous, bigger and messier than the usual Clojure ones. And that's just one level of indirection. When you add multiple, that's where things start get confusing. Function composition is fine by me, but I think some people definitely overdo it. To me that's more of an architecture/design skill issue.
Every layer of indirection needs a good reason and purpose. Sometimes indirection is necessary, but often it is not. The data oriented approach of Clojure makes at least some indirection unnecessary compared to OO languages.
E.g. multimethods and protocols, as tools for indirection, are available and can be put to good use for example, when your problem needs polymorphism. But using them without need leads to accidental complexity. It boils down to the difference between necessary vs. excessive.
Took me quite some time to learn that there is no good use for multimethods in application code. Very expensive indirection, and there are practically no benefits over a case when you control all the code.
I've come to believe the same; I value direct find-references and goto-definition so much I'd prefer dispatch via a case / cond or a hash-map of Clojure vars. Hash map of Clojure vars is likely slower than protocol dispatch, but that's been a non-issue for me this far. For libraries that need to perform well, I see the need.
Yes, libraries and applications are very different contexts for these trade-offs
case/cond are closed to extension and can lead to the expression problem where as multimethods and protocols are open. It may not make a difference, when you control all the code. But if not, it makes a huge difference.
exactly. In my application, i control the code. In libraries, I do not!
I've also had some annoying experiences in repl-driven development with the statefulness of multimethods. conds/cases/map literals reload easily.
Related tangent:
When I interviewed for Pitch some years back, I was told that they aimed for "greppable code". This notion has come up again and again when I've had to dig through code bases where too many things that could have been easily findable literals were dynamically cobbled together at runtime. Being able to "Go to definition" is great, and being able to simply grep (or otherwise text-search, like via the Github search interface) a code base is also great. And that's even if you do have access to and normally use IDEs, a REPL, static analysis or similar tools. Text search is usually built into whatever you read text with, so there's (potentially) no git clone, no setting up a project, no configuration needed, no spawning new stateful processes and connecting to them (except under the covers, of course 😄 ).
Maybe it seems caveman-like, but skimming code via Github navigation and search usually gets the job done for me when trying to figure out what's behind the interfaces of other teams in my org.
Too much indirection (or maybe, too ad hoc, disorganised indirection) also works against the "comprehending-code-by-skimming-it-as-raw-text-only-armed-with-a-text-searching-tool" approach.
Good morning
Morning
Morning and TGIF!!! The weekend is almost here!
good morning