By now, y’all should know about the Alternate Hard and Soft Layers pattern. It’s the idea of designing a system with some rules carved in granite (like Emacs’ C primitives) and some loosy-goosy (like Emacs’ Lisp extensions).
“In a cloud, bones of steel” as Charles Reznikoff put it. But what supercharges this design pattern for hackers is if you don’t make the boundaries between the layers too strict, if you provide ways to fall back through the patterns.
This “make the abstractions intentionally leaky” is a design decision that everytime I implement it, I get rewarded many times over (like how call-tables gives you easy, convenient access to the underlying hash-tables; I wasn’t sure if I was ever gonna use that but I’ve ended up using that again and again in many unforseen ways), and each time I forget to do it, I end up with a library that’s languishing from disuse and “What was I thinking?” and I don’t even use it myself.
It’s also why Markdown is so great. I was coming from Textile, which has all kinds of specific syntax to do specific things. Nice. I started out with Wikisyntax and was running up against the limitations of it, and Textile felt like a powerful injection of “wow, they managed to make room for all these things!”
p>{font-size:0.8em}. This is an example from the documentation for Textile markup language.
And then I saw Markdown. Fall through to HTML at any time. What a hecking Gordian knot. Make common things easy but keep unusual things possible.
And then as I’ve been working on this li’l site for years, I’ve been adding layers and above and below (pre-processing steps and post-processing steps), always keeping this “permeability” in mind. If I wanna bang out a quick li’l post using the normal defaults, I can. If I want to make anything a little different, weird, more special, I can. The other day I was writing a post that had super messy syntax under the hood; I have a way to make quick asides but here I needed a long aside with multiple nested paragraphs, blockquotes, links, something my normal aside system can’t handle. Escape hatches to the rescue; I just wrote that particular section in normal HTML. Easy peasy.
Like all patterns, this pattern isn’t always appropriate.
“Complex” is Latin for braided together, entwined.
Those who make super strict boundaries between the layers hope that will make each layer simple and portable. Scumm and Z-machine are two classic success stories from the world of game dev where they kept the abstractions tight and unleaky, and were rewarded with very portable games that are still installable and playable today.
But that requires you to know ahead of time exactly what primitives you’ll need and not need. One approach that might work here is to make the leaks traceable. You provide escape hatches so you can leak through the abstractions whenever you want to, but you put in some way to search for them. Then, once your app is settling, you can refactor all the “leaks” into proper calls to new API methods that you add to the layer below (recur this process when the leaks are from a layer more than one step below).
Or you just accept that the app is never gonna be ported, that it’s gonna stay as a big ball of mud, but thanks to the loosy-goosy layer boundaries it’s easy to quickly and flexibly add whatever feature you want.
Obviously you don’t want to do this for user input. HTML with JS is not appropriate for user input for example, since they can XSS you. (Why the world then has decided that HTML with JS is appropriate input for users and their browsers, from servers, is beyond me… but that’s a topic for another day.) So then you don’t want to allow formats that allow fallback HTML/JS either. Markdown, as in real markdown with JS and HTML attributes and stuff, is not a great format for a world-writable wiki, for example. Obviously a markdown-inspired format, like using ATX headers or Gemtext, is fine.