Reverse Engineering LIGHT: a learning pattern

Jelly Donut
3 min readApr 1, 2021

There’s quite a bit of literature on the practice of reverse engineering programming languages or bits of software in order to better understand them, hack them, or squash their bugs. Chances are if you’re a self-taught developer or had an otherwise unorthodox introduction to programming (like me), you don’t know binary or Programming Language Theory and you don’t care to learn, so the thought of reconstructing JavaScript from its foundations sounds ludicrous. For those of us who aren’t closeted computer science or linguistics nuts, reverse engineering a language seems like it might be time-consuming, painful, impractical…and altogether a distraction from the hustle for that first React/Typescript job.

But what if we can steal the basic thrust of reverse engineering and revise it for our very practical purposes, in particular for learning and internalizing new frameworks and libraries?

I propose that we can devise a friendlier reverse engineering process to balance out rote ingestion of documentation and make us wiser, more nimble wielders of the seemingly magical methods that come with Vue, React, Angular, Express, D3, Mocha, etc. (I list only JavaScript tools because that’s my jam, but the process I describe could be applied in other languages).

To the left, I’ve summarized this Reverse Engineering LIGHT pattern as it could apply to learning new libraries and frameworks.

Long story short, the idea is to translate the built-in methods of a framework into bare vanilla JS, even if only in your imagination.

Whereas traditional reverse engineering might emphasize an accurate reconstruction of what’s going on under the surface of a language or software, we’re not so much in the business of figuring out e.g. what developers at Facebook actually did when they built React (though if you’re curious, you can scour the implementation).

Instead, we’re interested in a sort-of make-believe analysis, a hypothetical vanilla articulation of our tools that will help us abstract away from the plug-and-play context in which we usually apply them.

You may be thinking, “I already do this. This is how I always deal with a new tool.”

If that’s the case, well done! You probably learn new libraries and frameworks more deeply than the rest of us, but I urge you to introspect, just in case. I think many of us are used to the abstraction step involved in what I’m describing. We’re used to explaining and re-explaining a method to ourselves, devising metaphors for a framework’s architecture, recognizing parallels between methods in one library’s API and those in another…

But often we chew on the whole tool at once (rather than taking the time to examine pieces of its functionality one by one) AND we’re very quick to start coding, copying and pasting syntax, building up muscle memory, mad-libbing our way through the work of those who came before.

This mimicry is important, but on its own, it can lead to brittle learning, familiarity without understanding, and fluency with only one or two (perhaps arbitrarily selected) design patterns.

I’m suggesting one extra cognitive maneuver to help us deepen our learning before we get stuck with a pattern, a little exercise to enrich the abstraction. By first analyzing functionality into vanilla logic, and only then investigating how that logic fits into the big picture, we’re less likely to miss an important piece of the puzzle, and we’re more likely to be resourceful when making decisions about our code in unfamiliar contexts.

A couple of tips before you try it

start simple and iterate

Begin by pseudocoding for the most basic use case of a method and only then worry about edge cases or fancy interactions with other methods

failure should teach you something

If you can’t even begin to translate some feature into vanilla code, that should reveal to you (a) something in the library or framework you could stand to brush up on and/or (b) what makes the library or framework special (no truly useful tool should be easily replicated)

And now a challenge:

To start off, try analyzing the logic of useState() — a React Hook — into vanilla JS. The actual implementation of this method is only 9 lines long, but of course, it calls on the useReducer() Hook, which is a bit gnarlier. Comment your solutions…and then challenge yourself to something harder.

Jelly Donut posts are written by Kelly Dinneen. Find her on GitHub or LinkedIn.

--

--

Jelly Donut

Specializing in questions about JavaScript and its appendages