27: Cut one feature down, another rises in it's place
This week I finished implementing the append-only-log architecture I laid out two weeks ago. That turnaround isn’t bad, especially considering I only work on Fancynote on the weekends, but I’d hoped to be done last week. As you may have read, that didn’t pan out, due to struggles with API’s, my own and the browser’s.
The latter was nothing diving into MDN couldn’t fix, but figuring out how to design my own interfaces took some more thinking.
I decided I could cheat a little with my “only weekends” rule. Just taking notes about API design isn’t the same as programming right? Any time I’d start to think about fancynote through out the week I’d try to write something down, coherent or not.
Views and Reactive Queries
I had one particular problem I was noodling about. How can I write Views, such that they enable reactive queries.
Views are programs that take in the event log and expose different ways to query it. Today I wrote a view for getting the current state of a note and one for getting all the links and backlinks for a note.
Reactive queries are queries to a view that will automatically get updated when
their result changes. So for example if I edit Note A
to remove a link to
Note B
and somewhere else I have a query for the pages that link back to Note
B
that query should automatically update to no longer include Note A
.
Honestly, I’m getting ahead of myself a little as this isn’t super important at this stage of Fancynote. Reactive queries really become essential when I actually get into building the interface. It’s important the interface updates quickly and with as little work done as possible.
Basically the trick here is you have to keep track of what data a query accesses, and what data an update changes. Because we’re building this on top of a basic Key-Value store (where you put in a key and get out a value!), this isn’t too hard!
- Each view has access to a unique data store with a set and get function
- When you query a view instead of immediately getting an answer you pass a function that will be called with the result.
- When the query runs it can read data with “get” and it tracks the keys that are accessed and saves them along with the callback.
- When a view processes a new event it updates data with “set”, and keeps track of which keys are changed.
- We goes through all queries and if they accessed changed keys, run them again!
This is a really nice example of how the event log + views architecture makes some things simpler. If I wanted to have a single “notes database” and a single function to query everything, it becomes much harder to track changes and keys accessed in an intuitive way. Separating things out into views let’s them be purpose built!
Aside: Is this situated software?
Speaking of purpose built things, I’ve been thinking about fancynote a little in the context of situated software
One of my favorite newsletter writers Hillel Wayne this week embarked on his own note-taking tool journey, building a little tool called Mindnet.
Mindnet is a kind of situated software. It is designed for my idiosyncrasies. It has exactly what I need and nothing else. A happy consequence is that it’s also fast, as computers are supposed to be.
Hillel Wayne , Situated Software
Situated software is an idea proposed by Clay Shirky, describing software made for a specific set of people, as opposed to the generic “user” that looms over traditional software development.
Situated software can be quicker to make and better because it’s made for exactly the needs of a real group of people.
I’m definitely making Fancynote note for me (and I’m a real person!), but it doesn’t quite feel like the archetype of situated software.
For one, I keep embarking on these abstraction expeditions to try out different architectures and features. The append-only log is one example, reactive queries are another. These certainly aren’t necessary for the simplest possible program that meets my needs.
To be fair, I’m not even sure what my needs are here. In fact, I’m pretty sure I don’t want to be sure! Fancynote is a tool to for thought and I don’t want my thoughts to be encoding a single system upfront. I want the tool to be situated in my specific contexts yes, but I also recognize that the context must change, and the tool needs to be able to change with it. Maybe fancynote is a tool for writing software? I’m not sure, but it’s something I’m thinking about!
Ultimately though, try as I might to justify why I’m building fancynote a certain way, there’s one main reason. It’s interesting and I enjoy it! Writing software can be about more than just meeting needs. It’s a way of exploring ideas, learning, having fun. I hope I convey some of that to you through this newsletter!
How did all the pre-work play out?
Thinking about the problem throughout the week let me spend time on it without any pressure to figure things out, or write some code.
My experience here runs seems counter to a blog post I recently read from Daniel Gross:
The longer you think about a task without doing it, the less novel it becomes to do. Writing things in your to-do list and coming back to them later helps you focus, but it comes at the cost: you’ve now converted an interesting idea into work. Since you’ve thought about it a little bit, it’s less interesting to work on.
Daniel Gross, Improvising for Productivity
Interestingly, I’m pretty sure I agree with Daneil here! Spontaneous Improvisational work is definitely the kind of stuff I find most satisfying.
I think I may have bamboozled myself. I set out to plan out how to implement the event-log + views API, but instead thought about an adjacent problem, the reactive views! This actually made the context for solving the intial problem richer and more engaging, instead of taking away from it and turning it into work.
I don’t know if I can systematize this, but it seems like an interesting thing to think about with my own workflow!
Next week, I’ve gotta work on getting reactive queries working, and making the first steps towards the UI. I also want to figure out how to get better types for my views, and properly handle the “lifecycle” of views (catching them up to current data, etc).
I’ll tell you about it next week!