March 3, 2020 ~ 7 min read

Accidental Frameworks

tap for dark mode

Originally published in 2013; updated for a 7-year follow-up (coming soon)

Whoops

I made a framework. Completely by accident. I set out with simplicity front and center, with KISS as the central star hanging low over the distant mountains. Surely I would never reach those mountains, I thought. Surely those craggy spires would never be my destination. I was a man of the lowlands, a dirt-on-my-hands kind of guy who'd never leave the aromatic fields of grass, or abandon the root elements of water, rock, soil, and tree. Well. The star was always right there, above the mountains. I should have known.

Not only had I managed to scale a mountain, but I'd made a place for myself there: a city, a beautiful though imperfect sprawl of streets, buildings, attractions, and services. I invited others to come on over for a visit, to taste of what was here, to explore the many wonderful places that...

What do you mean you need a map? It's quite simple really, you just take MessageType Lane to get to the Request Inn, and then...

No, no, it's really simple, I've just connected this to...

What? Look around! It's stone and earth and wood and...well, it's just the same raw materials you're used to, rearranged into convenient places to get things, and put things, and it all works together for the benefit of everyone who's here...

...whad'ya mean? There's plenty of room!

...it can accommodate that too!

...you don't know if you "trust" it? I built it myself, I...

...but...

My guests returned to the lowlands, offering me fistfuls of fresh grass and buckets of clean, simple water. I sank down glumly against the side of the JSON Exchange, embittered.

Abstraction

How did I get here? Well, that was easy: I took one step after another and arrived where I was. These were not large steps. I did not stride mightily. I pattered forward with all the naive innocence of a mouse. And yet. Here I was. A mouse on a mountain, mortified by the vista.

These tiny steps were small exercises in abstraction. I'd created components, helpers, and conventions by which to join and compose. As a programmer you do this (abstract) all the time. Doing it once does not a framework make. But how about twice? Three times?

If I'm counting, where along the number line does the bag of abstractions suddenly coalesce into a Frankenwork?

Remedies

Someone wisely interjects: start removing parts.

OK.

But I need this one here. And that one.

This one I can get rid of...oh no, I can't, I need that too.

You see, they're useful out by themselves like this because that lets you combine them into whatever you wish. I can't rightly predict how I'm gonna' want to use...

The wise one shakes their head: just use small, lightweight tools to do the jobs instead. There are libraries. Libraries: good. Frameworks: bad.

OK. I'd already done this and appropriated quite a bit. My city on the mountain was anchored on some of the best tools. But I begin searching the rolling hills again, sure of foot. I begin collecting and I don't stop. After a while I've got more small, light tools than all the parts, pieces and parcels contained in my framework. The tools aren't exactly right, but they're mostly right. I get to work connecting them all. Before I finish I realize I'm making a whole new city, twice as large.

Surely this can't be!

An old one, whom appears after the wise one steps to the side: take a tool and open it up.

Which one?

The old one: shrug.

Muttering, I make a random pick and twist off the lid.

The old one: what do you see?

Oh, that's curious. It looks like a miniature city is contained right inside here. It's kinda' neat. Look at all these wires. Wow. They must be pretty ambitious, whomever assembled this. It's complicated.

How did they...I'd need a schematic to...

The old one: What do you mean you need a schematic? It's quite simple really, you just take MessageType Lane to get to the Request Inn, and then...

Hey!

The old one: shrug.

I look back up the mountain at my city. I hold up the tool. I say to the old one: but surely they're not the same!

The old one, tired: yours is just missing a lid.

Sewing Up The Abstraction Tree

The reason my framework (it's just code! I whine uselessly) looks so impractical to my peers is that it exposes a canopy of features, functions, hooks, and conventions. It's an abstraction tree, with abstractions blossoming out of abstractions - a solidified collection of dependent roots, trunk, limbs, branches, and twigs. Out at the ends I imagine undulating leaves, coordinating as one in the breezes of shifting requirements, and I am pleased. My peers see something else - all the code, all the many pieces that make it up, all the unknown concepts and levels of indirection:

abstration tree

I'd made a fundamental mistake.

I'd forgot to cover it over, to apply a skin, to care about appearances. I'd not wanted to throw yet another layer on top of all the others. That would be bad, right? An unnecessary complication, yes? Wrong! I'd stopped one step too soon! (I imagined my significant other with no skin; a car with no body; a phone with no case.)

The last layer would be different than all the subsequent layers. Instead of branching out it would branch in. That is, it would close up the many ends of the tree. I would collapse the surface area to make the face of the framework, well, a face:

abstration tree

I should have started out with (something akin to) this layer. It should have been the first thing I wrote. Possibly I'd just needed to write a couple of failing test cases:


def test_ease_of_use_1():

    from accidental import just_code as apparent_framework
    apparent_framework.make_it_so('non-trivial task')

def test_ease_of_use_2():

    from accidental import just_code as apparent_framework
    from fundamental_constants import THAT_WAS_EASY
    assert apparent_framework.push('buttons') == THAT_WAS_EASY

Maybe I should have used these tests as my guiding light, rather than some vague notion of KISS? Maybe I should have focused on the actual words that would make up the actual sentences of user code, rather than on the building of some thing that works?

The Road Ahead


from hindsight import twenty_twenty as api
from accidental import just_code as apparent_framework

framework = api.patch(apparent_framework)

Bodies of code that let you see them in all their complex1 glory force you to use them in a complex manner, even if usage is straightforward in principal. Appearances trump principles because appearance is the top-level principle - the one that is firstly encountered and then most frequently re-encountered.

Without a friendly appearance, a familiar face in kind, irreparable damage may be done to the mental model that is your framework in the minds of potential users.

It may be too late for me. With an initial lack of skin I've pre-exposed the blood and bone.

-

I meander back down into the plain where the soil is dark and rich. I run my hands along the grasses and look up across the sky. I grab a shovel. The wise man watches and the old man sleeps.

  1. Eye of the beholder, etc.