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.
If you manage data for others it's extremely difficult to secure.
Efforts to secure it add to your costs.
malice
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
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
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
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
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.
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.
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.
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
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.
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.
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!
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.
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.
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.
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.
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.
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.
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.
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.)