48: One thing well
My little prototype of a information management tool is coming together. My apologies if that description means absolutely nothing to you, “a note-taking tool” wasn’t quite cutting it as a description for me.
Following my gut from last week, I threw out the web application I’d been building and instead made an EC REPL CLI (ha!).
Let’s break down those acronyms, eh?
First! EC = Entity-Component; the architecture of the application. Entities are
unique documents, and components are values that are associated with those
documents things like name
or content
.
This loose coupling let’s you easily add different properties and behavior
programmatically. For a simple example I could add a last-editted
component
that would be updated every time the content
is changed. Or, I could add a
newsletter
component, and every time it’s added to a document run a program to
publish it.
This is an implementation of what I mentioned two weeks ago, though I first got enamored with the architecture pattern around two years ago, while I was at the Recurse Center.
Now for the REPL part, something I first mentioned I was excited about implementing a whopping 27 weeks ago! A Read-Evalutate-Print-Loop is a way of interacting with a programming environment, where you execute code and view the results incrementally, as opposed to writing every instruction out and running it all at once.
You can have a REPL just for interacting with a programming language itself, but you can also load a repl with a specific set of functions, so it becomes an environment for making a particular set of programs. This is an absolutely fantastic way of rapidly prototyping an API for
Now for the last part, the CLI. REPL’s are great for humans, but what if I want to compose interactions with the program with other tools on my computer? For that I need a way to execute a given piece of code, and return out the result.
I can accomplish that with this little snippet:
// If input is provided, execute it and console log the result if(process.argv[2]){ console.log(await eval(` (async function main(){ return ${process.argv[2]} })() `)) } // Else start a repl for the user to interact with else { let context = repl.start().context let functions:Function[] = [updateOrCreate, findEntitiesWithComponent, getComponent, setComponent] functions.map(f=>context[f.name]=f) }
For example, here’s a tiny script to pop-up a menu of Document names, and then either edit or create the one I select:
note=$($HOME/dev/mud/mud "(await findEntitiesWithComponent('name')).map(component => component.name).join('\n')" | dmenu) [ "$note" != '' ] && $HOME/dev/mud/mud "await updateOrCreate('$note')"
This lets me play around in the REPL, and once I’ve figured out the code I want to take, integrate it into a larger script that interacts with other programs (like emacs, or a search tool!).
I could probably break that down further, and move logic out of javascript and into bash, but for now, it works great!
Evaluate-Print
I’m feeling pretty good about this core architecture (though I’ve definitely said that before!). There’s still one thing to implement, running code when components are updated, and one major open question, how to do complex queries on components, but everything is in place for basic usability.
I’m happiest about the fact that it focuses on doing just one thing, managing entities and components, and let’s everything else be handled by other programs.
I was averse to this path before because I’m excited by many different interaction possiblities. I want to be able to execute code while editing a document, and autocomplete links contextually. But, this architecture doesn’t mean I have to forgo those. In fact, by keeping the core API so simple it forces you to experiment outside of it, where it’s a lot easier to change and throw stuff away.
Importantly this feels like a foundation I can grow with.
Growth I think is the defining characteristic of my personal information management philosophy. I want to be able to constantly experiment and try out different ways of organizing and interacting with the things I create, without being impeded by my tools. The architecture of this tool directly reflects that, by allowing properties and behavior to emerge over time, and holding to an extremely simple data model.
Some newsletter updates
As we’re reaching the end of the year, I’m thinking about what I want to do with this lil newsletter. I’m going to take the next 4 weeks to do some reflection on what it’s been like writing this for a year, the ideas I’ve explored, and what interesting things I think I could do with it in the future. I’ll be taking January off most likely, and then kicking of a new “season” soon after that. It probably won’t have the same schedule or format, but I’m really excited to see what we can do!
It’s the home stretch! Thanks for coming along.