Using computers more freely and safely

Transcript for this video (18 minutes). Click on images for full-size versions.

2 kids at a computer How can we use computers more freely and safely?
the punchline
Prefer software:
  • with thousands rather than millions of users
  • that seldom requires updates
  • that spawns lots of forks
  • that is easy to modify
  • that you can modify
These are my suggestions.
  • Prefer software with thousands rather than millions of users,
  • that doesn't change often,
  • that seems to get forked a lot,
  • that can be modified without specialized tools, and, ideally
  • that you can make small changes to. Yourself. In a single afternoon.
You don't have to do all this. Their benefits are additive, but acting on even one of these suggestions is better than nothing. The suggestions are arranged roughly in order of increasing effort and skill required. Trying to follow one suggestion will pave the way for the others, should you choose later to continue down this path. Software without constant updates is easier for forks to keep up with. Forks are signs of easily-modified software, and testimonials from nearby programmers can be promising signs that, hey, maybe making a change yourself won't be very hard.

The most important step is the first one. Humanity didn't get good at building houses by building the same house a million times. We built lots of different houses and learned from each other's failures. Gravitating away from monopolies is a way everyone can help improve software, regardless of our abilities or needs.

outline
  • Problems
  • Suggestions ↔ Examples
That's the whole argument in a nutshell. In the rest of this talk I want to show how to apply these principles in small ways in your day-to-day decision-making, making the world a little better in the process. I'll show this by drawing on my own journey over the past year for examples. I'll first back up to some problems I was responding to at the start, then show how I responded fairly directly to these problems and ended up with the above suggestions.
expensive
So, problems. The first problem is: software is expensive. We like to think the incremental cost of software is 0. You build it once, lots of people use it. The additional cost for any new user is negligible. This is just not borne out by multiple decades of experience. Apps and services require constant maintenance. And they grow complex over time, so their costs grow over time.
untrustworthy
Also, software today is just not very trustworthy.
incompetence
some data on data breaches
Data breaches impact millions of people every year.

If you manage data for others it's extremely difficult to secure. Efforts to secure it add to your costs.

malice
headline: how popular apps can read your phone's clipboard without permission
Beyond incompetence, services engage in rampant misbehavior. This is a headline from a couple of years ago. Just about every single major phone app was snooping on your clipboard. And this was going on for years before these researchers noticed.

Since they noticed, Apple plugged this loophole. But what else are apps up to, and what current misbehavior will we find out about this year or the next?

slow
headline: the website obesity crisis by Maciej Cegłowski
Ok, so software providers fail to keep us secure and also do shady stuff. What do we get for this? Are they at least effective at providing the service they advertise? Here is a talk about how inefficient just about every single mainstream website is. Our computers pay a tax on every page we read.
slow
screenshot: computer latency by Dan Luu
But maybe that's just websites that have to go out over the internet. What about native apps? Here is a study showing that a computer from 2015 is 2-5 times slower than an Apple 2e from 1986 just at reading a keystroke and displaying it on screen.
all is not well with computers
  • they grow increasingly complex and expensive
  • they grow untrustworthy as they grow complex
  • they slow down as they grow complex
These are the fairly fundamental problems I see. They're not new or insightful, lots of people have said all this. What do we do about it?
depend less on software
My first resolution is just to bring less software into my life. It is still early days, we don't really understand computers yet. It's important to be clear-eyed about the risks they bring with them, and to think about computers primarily as a liability rather than an asset.
depend on services with dozens of users
Situated Software by Clay Shirky
But, unfortunately, I came to this realization too late. Computers have already eaten the world. Today I need to use computers to conduct commerce, interact with my government, and to talk to my family and friends. What to do about this?

One coping mechanism is an idea from almost 20 years ago called situated software. This is software with a few users who know each other and share a social context or situation. The idea is analogous to local government: services with few stakeholders are often better able to meet the needs of their stakeholders, particularly when everyone knows everyone and there's a certain level of social accountability.

This isn't always possible. Sometimes we have to use software with millions of users. But I think it helps to rely on small-scale tools as much as possible, and to question tools for large crowds of people at every opportunity.

depend on the right tools
Dependency by Randall Munroe
The idea of situated software has been seeing a renaissance recently, and there is growing awareness of the value it brings. However, I think we don't yet appreciate the implications of this idea at all levels of activity around computers.

As a programmer, I've tried multiple times in the past decade to create services just for myself and a few friends. Each of them has fallen away after a year or two. And a big reason for that was the burden of keeping up with updates for all the tools they depend on.

It took me a while to realize the underlying issue: I was using tools that themselves are catering to non-situated software. They assume that it's worth someone's time to keep up with updates every month or two. But situated software doesn't have those kinds of surpluses. It requires programs to just work once built, with little maintenance.

screenshot: lua.org Last year I switched to something new. This is the Lua programming language. It's implemented in just 12k LoC, it's extremely easy to build from source and it's quite fast. It's not as popular as Javascript or Python. As a result, it doesn't tend to get used in products of conquest that try to be all things to all people.
screenshot: lua.org versions page Another thing I love about it: there's a widespread culture of using old versions. Lua is often embedded in games. Games are a hits-driven business like movies. Hits are short-lived. As a result, it's less common for released games to receive updates. Old games running old versions of Lua are common.

I use version 5.1 which came out in 2006.

screenshot: love2d.org This is the LÖVE game engine. It's based on Lua, it's easy to build, it changes infrequently, and it's surprisingly versatile while providing a tiny set of APIs.

LÖVE allows me to send a zip file with inspectable source code to my friends. All they need to run it is a single, reputable 5MB binary.

alternatives
Now, you don't have to use Lua and LÖVE. I have friends who use Python or Rails or Javascript and are able to manage the overheads of upgrading. They do so by being extremely selective about what libraries they depend on. This can work, but I think it's not ideal. These languages foster a culture of depending on lots of libraries, and those libraries put out frequent updates. If you use these languages, you have to spend some energy espousing your values to collaborators and users, so they are parsimonious with libraries and depend on the right libraries. It requires constant discipline. With Lua and LÖVE the community shares these values and this discipline.
forks/examples
a map of my forks
What can I do with this platform? A language that doesn't try to be all things to all people and tends to leave copies of itself embedded in older games is fertile soil for forking. Every new game is an opportunity to rethink old ideas, to shed some complexity. This culture has had an effect on me even though I don't build games. I build little apps for my own life, and when I need something new, some of the time I now copy an existing program and permit the two copies to diverge.

This picture shows a family tree of sorts for the apps I built over the past year. I organized the tree roughly by complexity from left to right. And the lines trace heredity from top to bottom. Look for this image over the rest of the talk as I focus on individual apps to illustrate values I care about and concerns I can jettison entirely.

screenshot: editing a file with a drawing using lines.love lines.love on the map of forks The app that started it all was a plain-text editor that lets me draw little line drawings in the middle of text. I find it very useful. Definitely talk to me if it or any of my other programs sounds interesting. I want to support anyone interested in using it or hacking on it.

When I show it to other programmers, often the first question I get is about what the file format for drawings is, and how to get other editors to support that file format. But does it make sense to so privilege interoperability? You have a tool to draw pictures as you write. There are situations where it can be useful, even if nobody else can read it. Trying to stay close to other people and tools makes things more complex and less supple. A tiny, open-source tool that is easy to run and works with a simple file format allows me (and you) to focus on the writing experience without precluding others from taking on additional concerns.

values
  • no requirements

This is an example of keeping requirements negotiable. We programmers have a tendency to start with a germ of a neat idea and, in a microsecond, often so fast we're not even conscious of the transition, pile on a bunch of requirements to it, just because other things like it satisfy those requirements.

values
  • no requirements
  • wabi-sabi
Requirements often stem from unconscious acculturation, so it's worth coming up with strategies to question assumptions. One hack I've found useful is to stop trying to seem “professional”.

I remember when I started out programming, I wanted my programs to look “professional,” like the programs other “real” programmers made. This desire is the devil. It's taken me 20 years as a professional programmer to realize what matters is what it does, for your specific situation. In practice, seeming professional is often a way to end up with a pile of stuff you don't need. All it does is slow you down.

values
  • no requirements
  • wabi-sabi
  • no compatibility
One particularly egregious requirement we unthinkingly take on is backwards compatibility. Backwards compatibility is of huge strategic importance if you're Intel and trying to sell a lot of chips. But it's also easy to end up depending on a million lines of code just to avoid writing a thousand.

Deciding when and how an organization should break compatibility is a thorny problem. But fortunately we're not concerned with organizations here. When we're just individuals creating for other individuals, asking each other to make small changes just isn't that big a deal.

broadsheet.love on the map of forks Here's another of my forks. This one's not an editor, just a viewer. Its only reason for existence is to use all available width to display text in a readable way. That's it. It's a very simple thing to build, just 100 lines once you have an editor, and yet it's something I've never seen other programs do. I'm sick of overly wide lines of text and oceans of wasted whitespace. Now I can have dense but readable text on screen.
values
  • no requirements
  • wabi-sabi
  • no compatibility
  • avoid disagreements by forking
We programmers have long had an ideal of building programs that do one thing and do it well. But we have a really hard time keeping such programs from accreting features and complexity over time. I think one essential requirement for programs that do a single thing well is to not tie yourself too tightly with what other people want. It's easy for two people to want slightly different things, and a program that tries to cover both is no longer doing one thing. Rinse and repeat, and you end up with programs with hundreds of commandline flags or preferences. Or worse, someone deciding for everyone, whose preferred settings should get taken out. Just say no. Build simple things, and if others want to do something slightly different, well we already have a solution: fork!
lines.love on the map of forks Here's how I draw pictures in my text editor. One thing to notice is that there are no menus, dialogs or conventional UI elements. I've been trying to mimic the feel of paper and pen. I want to be able to draw at a moment's notice, but I don't want any reminders that I could draw. I don't want any widgets constantly on screen just for the moment when I might start drawing.
values
  • no requirements
  • wabi-sabi
  • no compatibility
  • avoid disagreements by forking
  • limit features per fork
Now, I likely don't know what I'm doing. I've only been drawing pixels for a year now, I'm not a UX designer. But I notice that menus grow over time, and the trend doesn't often come with great UX.

Our conventional UI idioms were created in the context of organizations. Menus and toolbars are at least partly scalable ways to pack lots of features in, to be all things to all people. Situated software doesn't need menus and toolbars.

meme: setup my dev environment Let's set aside app features and look at how we might make changes to these apps. It's distressingly common to need complicated tools to modify an app. We'd like to avoid requiring any such setup.
driver.love on the map of forks To modify any of my LÖVE apps you need just a second LÖVE app. Run the same 5MB LÖVE binary, just on a different 5k lines of Lua, mostly the same as my editor, just tweaked in a few ways, and now you can make changes to any of my apps as they run, without having to restart them.

Teaching a new LÖVE app to listen for commands from the editor takes 250 LoC.

values
  • no requirements
  • wabi-sabi
  • no compatibility
  • avoid disagreements by forking
  • limit features per fork
  • reward curiosity
It's not enough that the sources are available. “Open” is a spectrum, and most open software today is too hard to build, so we leave the build process to a priest class, and the priests accumulate power over time. What if there was zero accidental complexity to modifying a app, and all you had to focus on was understanding how it worked?
values
  • no requirements
  • wabi-sabi
  • no compatibility
  • avoid disagreements by forking
  • limit features per fork
  • reward curiosity
  • just small apps (for now)
My editing environment doesn't have find-and-replace yet. I haven't felt much need for it, which is surprising because I used to use it all the time. I recently realized why: small programs just tend to need less bulk replacement.

There are many features like this that my environment lacks at the moment. Some of them I'll get to, some I may never add.

There will absolutely be programs that are difficult to create this way, but that's ok.

luaML.love on the map of forks I've surprised myself a couple of times when a seemingly complex program turns out to have a simple core. This is a simple DOM model I wrote in 50 lines of code. It doesn't support 99.9% of CSS. It's just a simple way to specify grid layouts. Throw in an infinite 2D surface with support for panning and zooming, and it requires 350 LoC.
driver.love on the map of forks Once I built it, it was easy to include in my editing app. Here you can see my programming environment with the ability to view multiple definitions at once. This is something I've wanted for a long time, to view not just arbitrary files but arbitrary definitions side by side.
driver.love on the map of forks When I first started working on this environment I had a hazy desire for multiple views. However, I found myself gravitating towards a style where I positioned definitions once and never moved them thereafter. It was valuable to give all the code for my apps a place, so I always have a sense of space when I make changes to it. The computer contains my memory palace.
I'm a little surprised at this point, by how far I've been able to take what I initially considered just a coping strategy. My initial plan had been to create clones of apps for myself and take out lots of features. It felt like eating my vegetables. I didn't expect to find myself wondering what a web browser for memory palaces might look like. Small apps leave more headroom for design exploration. What new types of experience might you create if you undertook such a journey? Focus on keeping software easy to try out, easy to modify and easy to share.
avoid crowds
Prefer software:
  • with thousands rather than millions of users
  • that seldom requires updates
  • that spawns lots of forks
  • that is easy to modify
  • that you can modify
https://git.sr.ht/~akkartik/driver.love
The final message I want to leave you with is: avoid crowds. We can each have huge quantities of freedom inside our own devices on this crowded planet. Our freedoms only run into frictions when we leave our devices. The less often we need to do that, the happier we'll be. It doesn't solve everything, but it helps. A lot.

There isn't a whole lot of software out there that follows these principles. I expect I have a lot more to learn on this journey. If you're interested in joining me, I'd love to help ease your way along however you need. My freewheeling apps are freely available and designed for the long term, and I'm always looking for ways to make them useful to others.

Resources

Mirrors for the video: PeerTube, YouTube

Moar demo: Hands-on with Freewheeling Apps (mirror, mirror)

Links to all the apps/forks I showed above. Click on any node in this image to see its repo and Readme. (Unfortunately HTML doesn't support resizing such an image.)

clickable map of my forks draw line drawings, edit text experimental support for drawing polygons just text, no line drawings text viewer, no editing text editor with hyperlinks to switch files fork for supporting CJK languages (nothing much yet) draw line drawings, edit text, make hyperlinks to switch files helper tool for pensieve.love helper tool for techmeet.love my note-taking application; unclear how well it works for others experimental fork of pensieve.love for a small group of people experimental fork for mobile devices with touchscreens scratchpad app; write and draw, export html, clear and repeat template repo for creating live-editable freewheeling apps that can communicate with driver.love toy interpreter for the Brainfuck programming language multi-column reader for text files experimental flashcard app for drilling kids on spelling experimental markup language and 'browser' graph drawing tool visualize a Mastodon thread tree editing environment for freewheeling apps (image map generated using image-map.net)


2023-05-22