Introducing Pinafore for Mastodon

Today I’m happy to announce a project I’ve been quietly working on for some time: Pinafore. Pinafore is an alternative web client for Mastodon, which looks like this:

Screenshot of Pinafore home page

Here are some of its features:

  • Speed. Pinafore is built on Svelte, meaning it’s faster and lighter-weight[1] than most web apps.
  • Simplicity. Single-column layout, easy-to-read text, and large images.
  • Multi-account support. Log in to multiple instances and set a custom theme for each one.
  • Works offline. Recently-viewed timelines are fully browsable offline.
  • PWA. Pinafore is a Progressive Web App, so you can add it to your phone’s home screen and it will work like a native app.
  • Private. All communication is private between your browser and your instance. No ads or third-party trackers.

Pinafore is still beta quality, but I’m releasing it now to get early feedback. Of course it’s also open-source, so feel free to browse the source code.

In the rest of this post, I want to share a bit about the motivation behind Pinafore, as well as some technical details about how it works.

If you don’t care about technical details, you can skip to pinafore.social or read the user guide.

The need for speed

I love the Mastodon web app, and I’ve even contributed code to it. It’s a PWA, it’s responsive, and it works well across multiple devices. But eventually, I felt like I could make something interesting by rewriting the frontend from scratch. I had a few main goals.

First off, I wanted the UI to be fast even on low-end laptops or phones. For Pinafore, my litmus test was whether it could work well on a Nexus 5 (released in 2013).

Having set the bar that high, I made some hard choices to squeeze out better performance:

  • For the framework, I chose Sapper and Svelte because they offer state-of-the-art performance, essentially compiling to vanilla JavaScript.
  • To be resilient on slow connections, or Lie-Fi, or when offline altogether, Pinafore stores data locally in IndexedDB.
  • To use less memory, Pinafore keeps only a fraction of its UI state in memory (most is stored in IndexedDB), and it uses a fully virtual list to reduce the number of DOM nodes.

Other design decisions that impacted performance:

I also chose to only support modern browsers – the latest versions of Chrome, Edge, Firefox, and Safari. Because of this, Pinafore is able to directly ship modern JavaScript instead of using something like Babel to compile down to a more bloated ES5 format. It also loads a minimum of polyfills, and only for those browsers that need them.

Privacy is key

Thanks to the magic of CORS, Pinafore is an almost purely client-side web app[2]. When you use the Pinafore website, your browser communicates directly with your instance’s public API, just like a native app would. The only job of the pinafore.social server is to serve up HTML, CSS, and JavaScript.

This not only makes the implementation simpler: it also guarantees privacy. You don’t have to trust Pinafore to keep your data safe, because it never handles it in the first place! All user data is stored in your browser, and logging out of your instance simply deletes it.

And even if you don’t trust the Pinafore server, it’s an open-source project, so you can always run it locally. Like the Mastodon project itself, I gave it an AGPL license, so you can host it yourself as long as you make the modified source code available.

Q & A

What’s with the name?

Pinafore is named after my favorite Gilbert and Sullivan play. If you’re unfamiliar, this bit from The Simpsons is a great intro.

Does it work without JavaScript?

Pinafore’s landing page works without JavaScript for SEO reasons, but the app itself requires JavaScript. Although Server-Side Rendering (SSR) is possible, it would require storing user data on Pinafore’s servers, and so I chose to avoid it.

Why are you trying to compete with Mastodon?

Pinafore doesn’t compete with Mastodon; it complements it. Mastodon has a very open API, which is what allows for the flourishing of mobile apps, command-line tools, and even web clients like halcyon.social or Pinafore itself.

One of my goals with Pinafore is to take a bit of the pressure off the Mastodon project to try to be all things to all people. There are lots of demands on Mastodon to make small UI tweaks to suit various users’ preferences, which is a major source of contention, and also partly the motivation for forks like glitch-soc.

But ideally, the way a user engages with their Mastodon instance should be up to that user. As a user, if I want a different background color or for images to be rendered differently, then why should I wait for the Mastodon maintainers or my admin to make that change? I use whatever mobile app I like, so why should the web UI be any different?

As Eugen has said, the web UI is just one application out of many. And I don’t even intend for Pinafore to replace the web UI. There are various features in that UI that I have no plans to implement, such as administration tools, moderation tools, and complex multi-column scenarios. Plus, the web UI is the landing page for each instance, and an opportunity for those instances to be creative and express themselves.

Why didn’t you implement <x feature>?

As with any project, I prioritized some features at the expense of others. Some of these decisions were based on design goals, whereas others were just to get a working beta out the door. I have a list of goals and non-goals in the project README, as well as a roadmap for basic feature parity with the Mastodon web UI.

Why didn’t you use the ActivityPub client-to-server API?

ActivityPub defines both a server-to-server and a client-to-server API, but Mastodon only supports the former. Also, Mastodon’s client-to-server API is supported by other projects like Pleroma, so for now, it’s the most practical choice.

What’s your business model?

None. I wrote Pinafore for fun, out of love for the Mastodon project.

How can I chip in?

I’m a privileged white dude living in a developed country who works for a large tech company. I don’t need any donations. Please donate to Eugen instead so he can continue making Mastodon better!

Thanks!

If you’ve read this far, give Pinafore a try and tell me what you think.

Footnotes

1. Measuring the size of the JavaScript payload after gzip when loading the home feed on a desktop browser, I recorded 333KB for Pinafore, 1.01MB for mastodon.social, and 2.25MB for twitter.com.

2. For the purpose of readable URLs, some minor routing logic is done on the server-side. For instance, account IDs, status IDs, instance names, and hashtags may be sent to the server as part of the URL. But on modern browsers, this will only occur if you explicitly navigate to a page with that URL and the Service Worker hasn’t already been activated, or you hard-refresh. In the vast majority of cases, the Service Worker should handle these URLs, and thus even this light metadata is not sent to the server.

Smaller Lodash bundles with Webpack and Babel

One of the benefits of working with smart people is that you can learn a lot from them through osmosis. As luck would have it, a recent move placed my office next to John-David Dalton‘s, with the perk being that he occasionally wanders into my office to talk about cool stuff he’s working on, like Lodash and ES modules in Node.

Recently we chatted about Lodash and the various plugins for making its bundle size smaller, such as lodash-webpack-plugin and babel-plugin-lodash. I admitted that I had used both projects but only had a fuzzy notion of what they actually did, or why you’d want to use one or the other. Fortunately J.D. set me straight, and so I thought it’d be a good opportunity to take what I’ve learned and turn it into a short blog post.

TL;DR

Use the import times from 'lodash/times' format over import { times } from 'lodash' wherever possible. If you do, then you don’t need the babel-plugin-lodash. Update: or use lodash-es instead.

Be very careful when using lodash-webpack-plugin to check that you’re not omitting any features you actually need, or stuff can break in production.

Avoid Lodash chaining (e.g. _(array).map(...).filter(...).take(...)), since there’s currently no way to reduce its size.

babel-plugin-lodash

The first thing to understand about Lodash is that there are multiple ways you can use the same method, but some of them are more expensive than others:

import { times } from 'lodash'   // 68.81kB  :(
import times from 'lodash/times' //  2.08kB! :)

times(3, () => console.log('whee'))

You can see the difference using something like webpack-bundle-analyzer. Here’s the first version:

Screenshot of lodash.js taking up almost the entire bundle size

Using the import { times } from 'lodash' idiom, it turns out that lodash.js is so big that you can’t even see our tiny index.js! Lodash takes up a full parsed size of 68.81kB. (In the bundle analyzer, hover your mouse over the module to see the size.)

Now here’s the second version (using import times from 'lodash/times'):

Screenshot showing many smaller Lodash modules not taking up so much space

In the second screenshot, Lodash’s total size has shrunk down to 2.08kB. Now we can finally see our index.js!

However, some people prefer the second syntax to the first, especially since it can get more terse the more you import.

Consider:

import { map, filter, times, noop } from 'lodash'

compared to:

import map from 'lodash/map'
import filter from 'lodash/filter'
import times from 'lodash/times'
import noop from 'lodash/noop'

What the babel-plugin-lodash proposes is to automatically rewrite your Lodash imports to use the second pattern rather than the first. So it would rewrite

import { times } from 'lodash'

as

import times from 'lodash/times'

One takeway from this is that, if you’re already using the import times from 'lodash/times' idiom, then you don’t need babel-plugin-lodash.

Update: apparently if you use the lodash-es package, then you also don’t need the Babel plugin. It may also have better tree-shaking outputs in Webpack due to setting "sideEffects": false in package.json, which the main lodash package does not do.

lodash-webpack-plugin

What lodash-webpack-plugin does is a bit more complicated. Whereas babel-plugin-lodash focuses on the syntax in your own code, lodash-webpack-plugin changes how Lodash works under the hood to make it smaller.

The reason this cuts down your bundle size is that it turns out there are a lot of edge cases and niche functionality that Lodash provides, and if you’re not using those features, they just take up unnecessary space. There’s a full list in the README, but let’s walk through some examples.

Iteratee shorthands

What in the heck is an “iteratee shorthand”? Well, let’s say you want to map() an Array of Objects like so:

import map from 'lodash/map'
map([{id: 'foo'}, {id: 'bar'}], obj => obj.id) // ['foo', 'bar']

In this case, Lodash allows you to use a shorthand:

import map from 'lodash/map'
map([{id: 'foo'}, {id: 'bar'}], 'id') // ['foo', 'bar']

This shorthand syntax is nice to save a few characters, but unfortunately it requires Lodash to use more code under the hood. So lodash-webpack-plugin can just remove this functionality.

For example, let’s say I use the full arrow function instead of the shorthand. Without lodash-webpack-plugin, we get:

Screenshot showing multiple lodash modules under .map

In this case, Lodash takes up 18.59kB total.

Now let’s add lodash-webpack-plugin:

Screenshot of lodash with a very small map.js dependency

And now Lodash is down to 117 bytes! That’s quite the savings.

Collection methods

Another example is “collection methods” for Objects. This means being able to use standard Array methods like forEach() and map() on an Object, in which case Lodash gives you a callback with both the key and the value:

import forEach from 'lodash/forEach'

forEach({foo: 'bar', baz: 'quux'}, (value, key) => {
  console.log(key, value)
  // prints 'foo bar' then 'baz quux'
})

This is handy, but once again it has a cost. Let’s say we’re only using forEach for Arrays:

import forEach from 'lodash/forEach'

forEach(['foo', 'bar'], obj => {
  console.log(obj) // prints 'foo' then 'bar
})

In this case, Lodash will take up a total of 5.06kB:

Screenshot showing Lodash forEach() taking up quite a few modules

Whereas once we add in lodash-webpack-plugin, Lodash trims down to a svelte 108 bytes:

Screenshot showing a very small Lodash forEach.js module

Chaining

Another common Lodash feature is chaining, which exposes functionality like this:

import _ from 'lodash'
const array = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
console.log(_(array)
  .map(i => parseInt(i, 10))
  .filter(i => i % 2 === 1)
  .take(5)
  .value()
) // prints '[ 1, 3, 5, 7, 9 ]'

Unfortunately there is currently no good way to reduce the size required for chaining. So you’re better off importing the Lodash functions individually:

import map from 'lodash/map'
import filter from 'lodash/filter'
import take from 'lodash/take'
const array = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']

console.log(
  take(
    filter(
      map(array, i => parseInt(i, 10)),
    i => i % 2 === 1),
  5)
) // prints '[ 1, 3, 5, 7, 9 ]'

Using the lodash-webpack-plugin with the chaining option enabled, the first example takes up the full 68.81kB:

Screenshot showing large lodash.js dependency

This makes sense, since we’re still importing all of Lodash for the chaining to work.

Whereas the second example with chaining disabled gives us only 590 bytes:

Screenshot showing a handful of small Lodash modules

The second piece of code is a bit harder to read than the first, but it’s certainly a big savings in file size! Luckily J.D. tells me there may be some work in progress on a plugin that could rewrite the second syntax to look more like the first (similar to babel-plugin-lodash).

Edit: it was brought to my attention in the comments that this functionality should be coming soon to babel-plugin-lodash!

Gotchas

Saving bundle size is great, but lodash-webpack-plugin comes with some caveats. By default, all of these features – shorthands for the iteratee shorthands, collections for the Object collection methods, and others – are disabled by default. Furthermore, they may break or even silently fail if you try to use them when they’re disabled.

This means that if you only use lodash-webpack-plugin in production, you may be in for a rude surprise when you test something in development mode and then find it’s broken in production. In my previous examples, if you use the iteratee shorthand:

map([{id: 'foo'}, {id: 'bar'}], 'id') // ['foo', 'bar']

And if you don’t enable shorthands in lodash-webpack-plugin, then this will actually throw a runtime error:

map.js:16 Uncaught TypeError: iteratee is not a function

In the case of the Object collection methods, it’s more insidious. If you use:

forEach({foo: 'bar', baz: 'quux'}, (value, key) => {
  console.log(key, value)
})

And if you don’t enable collections in lodash-webpack-plugin, then the forEach() method will silently fail. This can lead to some very hard-to-uncover bugs!

Conclusion

The babel-plugin-lodash and lodash-webpack-plugin packages are great. They’re an easy way to reduce your bundle size by a significant amount and with minimal effort.

The lodash-webpack-plugin is particularly useful, since it actually changes how Lodash operates under the hood and can remove functionality that almost nobody uses. Support for edge cases like sparse arrays (guards) and typed arrays (exotics) is unlikely to be something you’ll need.

While the lodash-webpack-plugin is extremely useful, though, it also has some footguns. If you’re only enabling it for production builds, you may be surprised when something works in development but then fails in production. It might also be hard to add to a large existing project, since you’ll have to meticulously audit all your uses of Lodash.

So be sure to carefully read the documentation before installing the lodash-webpack-plugin. And if you’re not sure if you need a certain feature, then you may be better off enabling that feature (or disabling the plugin entirely) and just take the ~20kB hit.

Note: if you’d like to experiment with this yourself, I put these examples into a small GitHub repo. If you uncomment various bits of code in src/index.js, and enable or disable the Babel and Webpack plugins in .babelrc and webpack.config.js, then you can play around with these examples yourself.

Decentralized identity and decentralized social networks

I’d like to tell you a story about Bob. Bob is a fairly ordinary, upstanding citizen. Bob also has a lot of hobbies.

Bob is a good father, so one of his hobbies is to coach his son’s little-league team. Bob is careful to enforce a certain set of rules during the games and at the after-game pizza parties. If one of the kids uses a curse word or bullies another kid, Bob is expected to intervene and apply the appropriate discipline.

Bob is also a Christian. When he’s in church on Sundays, there’s another set of rules, both implicit and explicit, that Bob is expected to abide by. For instance, it’s okay for Bob to confide in other churchgoers about his momentary lapses of faith, or about his struggles to understand certain Bible passages. But if Bob started quoting Richard Dawkins or loudly preaching atheism, he’d probably create a very awkward scene, and may even get kicked out of church.

Bob also happens to be a vegetarian, and he attends a monthly vegetarian meetup. Within this group, there’s an entirely different set of rules and norms at play. Bob is careful not to talk too much about his favorite recipes involving cheese, eggs, or honey, because he knows that there’s a sizable minority of vegans in the group who may be offended. It would also be completely unacceptable to talk about a juicy steak dinner, even though this topic of conversation may be perfectly acceptable within the church or the little-league team.

Bob also has a set of old college buddies that he occasionally meets up with at the local bar. Here, once again, an entirely different set of norms apply. Raunchy jokes and curse words are not only allowed – they’re encouraged. Open debate about religion is tolerated. Bob may even be able to let his vegetarian guard down and talk about a delicious steak dinner he ate in a moment of weakness.

One Bob out of many

Bob intuitively understands these different norms and contexts, and he effortlessly glides from one to the other. It’s as if there’s a switch in his brain that activates as soon as he walks through the church doors or into the bar.

Furthermore, nobody accuses Bob of being dishonest or duplicitous for acting this way. In fact, everything described above is such a fundamental, everyday part of the human experience that it’s downright boring.

Now Bob goes online. Suddenly, every social network is telling him that he should have exactly one identity, speak in one voice, and abide by one set of rules. Mark Zuckerberg says, “Having two identities for yourself is an example of a lack of integrity.” OKCupid says, “We want you […] to go by who you are, and not be hidden beneath another layer of mystique.” Eric Schmidt says, “If you have something that you don’t want anyone to know, maybe you shouldn’t be doing it in the first place.”

Bob is apparently expected to use his real name, and use one account, and present a single public face for every possible context and social situation.

Intuitively, Bob knows this is bullshit. We all know it’s bullshit. But in the online world, we’ve just learned to put up with it.

Identity on social networks

Now let’s step away from Bob for a moment and talk about how the rest of us deal with this problem.

One of the common coping mechanisms is to fracture ourselves into different silos. We use Slack to talk to our coworkers, Discord to chat with our gamer buddies, LinkedIn for professional talk, Twitter for talking about the news, Facebook for talking with our family, and so on. Folks who follow this strategy may use a completely different voice in each platform and may not even reveal their real names.

With decentralized social networks, though, the situation gets more interesting. On platforms like Mastodon, Pleroma, GNU Social, postActiv, and others, you sign up for a particular “instance” representing a self-contained community. This community may have its own rules, its own culture, and even its own emojis and theme color.

However, each instance isn’t walled off from the outside world. Instead, it has tendrils that can reach into any other community it may be connected to. It’s less like the isolated silos of Facebook, Twitter, and Slack, and more like a cluster of small towns with some well-traveled roads between them.

Some folks look at Mastodon as a mere replacement for Twitter. Maybe for them it’s Twitter for lefties, or Twitter for anime artists, or Twitter for a nationalist agenda. It’s really none of these things, though, and I think importantly it has the potential to address one of the biggest problems with online identity: context collapse.

Context collapse

“Context collapse” was first coined by danah boyd, and a good description of it can be found in a blog post by Michael Wesch.

The basic idea is this: when human beings converse in person, we use a wide variety of unwritten rules to govern the acceptable boundaries of the conversation. We pick up on subtle nonverbal cues such as someone’s posture, their hand gestures, and their degree of eye contact to choose the right “register” for the conversation. We might even switch between different dialects of the same language, depending on who we’re talking to (linguists call this “code-switching”).

All of this happens automatically and intuitively, and it’s a valuable tool for avoiding ambiguities and misunderstandings. There are entire subfields of linguistics that study how humans communicate this way, such as pragmatics and sociolinguistics.

Online, we have none of this context. Staring into the webcam or into the textbox on a social media site, we are simultaneously addressing everyone and no one, for now and for all time. Factor in character limits, upload limits, and just the limits of human attention, and this is a ripe environment for misunderstandings. Sarcasm, facetiousness, irony, playful ribbing between friends – all of it can be lost on your audience if they don’t have the proper context to guide them.

Here are some of the symptoms of context collapse that you may have experienced:

  • jokes are misunderstood and taken at face value
  • in-jokes between friends are perceived as harassment by outsiders
  • you accidentally offend someone when no offense was intended
  • something you say is taken out of context and used for dogpiling
  • you feel like you have to censor yourself online
  • you agonize over every character and punctuation mark to avoid misinterpretation

All of these situations can be frustrating or even harmful to your mental health. Consider Justine Sacco’s poorly-received joke that cost her her job and brought her a lot of mental anguish.

Fracturing ourselves into siloed social networks, in its own ham-handed way, offers a solution to this problem. Instead of just hoping that our readers will pick up on the context, we rely on the context granted by the social network itself. Discord is for gamers, LinkedIn is for professionals, Slack is for coworkers, etc.

But on decentralized social networks, we may have a more elegant solution to this problem, and one that doesn’t require locking up our identities into various proprietary silos.

Solving context collapse on decentralized social media

The notion that you should use a single identity online is, I believe, a holdover from the centralized social media sites. Their goal is to get you to reveal as much information about yourself as possible (to sell it to advertisers), so of course they would discourage you from having multiple accounts or from concealing your real name. But that doesn’t mean decentralized social networks need to be the same.

Instead of treating your identity “on Mastodon” or “on the fediverse” as a single entity, what if you had multiple identities on multiple instances, and you treated them as distinct? What might that look like?

I figured this out myself over the past year or so, as I largely split my online identity on Mastodon into two accounts: @nolan@mastodon.social and @nolan@toot.cafe.

The tone of the two accounts is completely different. @nolan@mastodon.social makes silly jokes and mostly writes in all lowercase. @nolan@toot.cafe talks about software, programming, and his day job, and tends to use proper punctuation. (It’s more like the voice of this blog.)

The reason for this split is partly historical. @nolan@mastodon.social tends to speak only in jokes because it was my first Mastodon account, and when I signed up I didn’t reveal my full name or tie it back to my real-world identity. Instead, I just tried to have fun, making as many silly jokes as I could and seeing what landed and what didn’t. I’d say I did fairly well, since at one point I had the most-favorited Mastodon post of all time and got quoted twice in this article on Mastodon.

Screenshot of Mastodon post saying "mom: hey son I joined this new Mastodon thing me: oh shit mom, I coulda helped you find a server, which one did you choose? mom: well I liked the privacy policy on satanic.bikerladi.es but then communist.blaze.party had the shortest ping latency so"

When I set up my own instance, though, things started to get complicated. Now I had an admin account, @nolan@toot.cafe, and I needed to talk about serious admin stuff: when was the server going down for maintenance, what was our privacy policy, what was our moderation policy, etc. So for that account, I switched to my professional voice so that folks could understand that I wasn’t joking or being sarcastic.

But I still had @nolan@mastodon.social for the silly stuff. And the more I used it, the more I found that I liked the split. People who followed me on @nolan@mastodon.social didn’t necessarily care about Mastodon admin topics (memory usage, systemd, Ruby, etc.) – maybe they only followed me for the fun stuff. Likewise, people who followed me on @nolan@toot.cafe maybe just wanted to keep up-to-date on Mastodon admin and development (especially as I started contributing to the Mastodon codebase itself), and didn’t care for the jokes.

Keeping my identities separate thus served a few purposes:

  • I could have fun with people who didn’t know or care about tech topics (e.g. my wife, who loves my jokes but finds tech boring).
  • Nobody had to wonder when I was being sarcastic and when I was being serious.
  • People who followed me for tech stuff didn’t have to put up with my jokes if they didn’t like my sense of humor.
  • People who liked both my jokes and my tech talk could still follow me on both accounts.

This process wasn’t without its hurdles, though. At one point I was using fairly similar avatars for each account:

Screenshot of two Mastodon avatars, one with a subtle coffee icon and one without

My original Mastodon account avatars. Could you tell the difference between the two?

Eventually, though, I got tired of people not picking up on the sarcasm in my joke account. So I switched to an avatar that could only be interpreted as something silly:

Picture of a Mastodon avatar that looks like Ogmo from the Jumper game but handrawn, a silly face with bug eyes

My new, unambiguously “zany” Mastodon avatar.

Taking this avatar seriously would be like arguing with the “We Rate Dogs” account on Twitter. The new avatar makes the intent of the account much clearer.

Am I being duplicitous? No, I link between the two accounts on my profile pages, so everyone can figure out that both accounts are me.

Is it hard to juggle two different accounts? No, I use separate browser tabs, and since toot.cafe has its own theme color, it’s easy for me to remember which site I’m on.

Screenshot of Mastodon toot saying "tfw I have to switch from my joke account to my serious account to boost a toot, to make it clear I am not boosting ironically"

Is it hard for others to know which Nolan to talk to? Well, sort of. When my wife wants to post something like “@nolan said to me today…” she tends to use my @nolan@mastodon.social account because she has more fun interacting with that account than with my serious one. But other than that, I haven’t really run into any problems with this system.

Previously, I was also running a French-language account at @nolan@mastodon.xyz, but I found this a bit hard to manage. I didn’t have a network of French-speaking friends I was regularly talking to, and most of the francophones on Mastodon can speak English anyway. Also, managing three social media accounts was just a bit too much of a time investment for me.

Instance policies and identity

Right now I have a simple two-account system, and my choice of instance for each account is fairly arbitrary. (Although toot.cafe is somewhat tech- and programming-themed, so talking about computery stuff there feels very natural.) However, you could imagine tailoring an account to its home instance, based on the instance’s theme or moderation policies.

Going back to the Bob example, let’s imagine that Bob sets up four instances:

  1. An instance for his son’s little-league team, which is closed off from most of the fediverse via whitelisting and has very strict moderation policies to ensure it stays kid-friendly. All of the parents have moderator accounts.
  2. An instance for his church group. The moderation policies reflect Christian values, and although you can talk openly about your faith, it’s advised to use Content Warnings for controversial topics.
  3. An instance for his vegetarian meetup. You’re encouraged to take pictures of your food, but pictures of meat dishes are strictly off-limits. Vegetarian (non-vegan) food photos are okay, but should be hidden behind a “sensitive” tag.
  4. A free-for-all instance for his drinking buddies. Anything goes, say whatever racy or off-color joke pops into your head, but be aware of the consequences – such as the fact that other instances might not want to federate with you. You might also want to use a pseudonym here instead of your real name.

Bob could create a separate account on all four instances, and he might speak in a very different voice on each of them. If he’s an admin or a moderator, he may even enforce very different policies, and he might choose different instances to block or silence. In fact, one of his instances may even block the other! Via whitelisting, the kid-friendly one certainly blocks the drinking-buddies instance.

Bob’s not doing anything wrong here. He’s not a hypocrite. He’s not being deceitful. He’s just taking exactly the same logic that we use in the real world, and applying it to the online world.

Conclusion

It’s unreasonable to expect people to speak in the same voice in every social setting offline, so it’s equally unreasonable to ask them to do it online.

In the world of centralized social networks, users have responded to “real name policies” and “please use one account” by fracturing themselves into different proprietary silos. On decentralized social networks, we can continue fracturing ourselves based on instances, but these disparate identities are allowed to comingle a bit, thanks to the magic of federation.

I don’t expect everyone to use the same techniques I use, such as having a joke account and a serious account. For some people, that’s just too much of an investment in social media, and it’s too hard to juggle more than one account. But I think it’s a partial solution to the problem of context collapse, and although it’s a bit of extra effort, it can pay dividends in the form of fewer misunderstandings, fewer ambiguities, and less confusion for your readers.

2017 book review

This is a first, but I decided to jot down some thoughts on a few of the books I read this year. Enjoy!

Quick links:

Nonfiction

Nothing Is True and Everything Is Possible: The Surreal Heart of the New Russia by Peter Pomerantsev (2014)

One of my favorite books I read this year. Surprising, funny, and engaging in a way that few nonfiction books ever are.

Pomerantsev’s view of modern Russia is of a cynical society, where little matters except celebrity, riches, and maybe catching something juicy on reality TV. The prevailing mood seems to be: democracy is a joke, nothing any leader says is to be believed, but who cares as long as we’re being entertained?

My favorite quote from the book is this one:

“The new Kremlin won’t make the same mistake the old Soviet Union did: it will never let TV become dull. The task is to synthesize Soviet control with Western entertainment.”

The Retreat of Western Liberalism by Edward Luce (2017)

If you felt blindsided by the political upheavals of 2016, this book may be the sober and unflinching “explainer” to make sense of the whole mess. It’s so good that I may even need to re-read it.

My main takeaway is that recent populist anger at “globalist” policies (neoliberalism, neoconservatism, etc.) can be largely traced back to the “elephant chart”. The chart basically shows how the working class of the developed world hasn’t seen a wage increase in several decades, whereas everybody else is doing pretty well in comparison. Once you understand the elephant chart, everything else kind of flows from that.

My second main takeaway is that American pre-eminence in geopolitics is not something we should take for granted, and that maybe the US should find a way to slide gracefully into a more modest role on the world stage. The question is whether we can manage to keep faith with liberal democracy in the process, or if instead 2016 is just the harbinger of worse things to come, like 1932 before it.

The Attention Merchants by Tim Wu (2016)

A masterful book that ties our current media landscape into a history of advertising, as far back as posters in 19th-century Paris and snake-oil ads in early 20th-century America. After reading this and The Master Switch by the same author, it’s hard to look at the tech industry the same way again. Unfortunately, the conclusions from both are supremely pessimistic.

#Republic by Cass Sunstein (2017)

2017 was a year with a lot of pontificating about what’s wrong with the tech industry. (I indulged in a bit myself.) But this is the rare book that actually backs up its criticisms with some hard evidence and scientific data. The results aren’t always encouraging, but they’re often surprising. (For instance, artificial upvotes in a Reddit-like social media site do impact outcomes, but artificial downvotes don’t.)

Sunstein also approaches the problem as a policy advocate. Many of his arguments boil down to the idea that, even if social media is giving us what we want as consumers, maybe it’s not giving us what we want as citizens.

We used to have shared public spaces, where one was free to protest or hand out flyers in support of a cause. Now we have Facebook pages and Google search results, which don’t have any of the same guarantees. We also used to have a shared national media, i.e. three TV channels that everyone in the country tuned in to. Now every individual crafts their own media.

What does it mean for American democracy when our new media landscape is both balkanized and privatized? It’s an interesting question, and Sunstein does a thorough job of exploring it.

Black Ops Advertising by Mara Einstein (2016)

A pretty terrifying look at how advertising actually works in the age of social media. Once you read this book, you might never look the same way again at an artfully-placed bottle of Mountain Dew in some Instagram celebrity’s “candid” photos.

One thing this book impressed upon me is that the line between “content” and “advertising” has become so blurred that it’s almost impossible to tell the difference anymore. Tim Wu describes it well:

“Jimmy Fallon’s opening monologue began hilariously enough, when abruptly he pivoted to a series of inexplicably weak jokes centered on a forthcoming football game. It slowly dawned on me that I was watching a commercial for NBC’s ‘Sunday Night Football,’ albeit one baked right into the opening monologue and delivered by Fallon himself.”

This is one of the reasons I’ve become hesitant to talk about Microsoft-related stuff on social media (even Minecraft! a game I genuinely enjoy), because I’m worried it’ll come across as mere schilling for the company’s products. Then again, are any of us immune to our own biases?

Islamic Exceptionalism by Shadi Hamid (2016)

A great, thought-provoking book about the Arab Spring and the role of Islamism in world politics. It makes the case that Islam is unique among religions in that its adherents tend to seek political systems that intertwine with their religious lives, and that maybe that’s something the West just needs to learn to accept.

This book may need to be re-evaluated given the decline of IS in 2017 and rising secularism in the Islamic world, but it’s an interesting read to help understand modern Islamist movements.

Radical Technologies by Adam Greenfield (2017)

A fascinating, if somewhat dry and academic read. My favorite part is the first chapter describing the strange impact the smartphone has had on the daily hum of the modern city. The first paragraph is gripping:

“The smartphone is the signature artifact of our age. Less than a decade old, this protean object has become the universal, all-but-indispensable mediator of everyday life. Very few manufactured objects have ever been as ubiquitous as these glowing slabs of polycarbonate.”

The rest doesn’t disappoint either. And incidentally, I learned a lot about how the blockchain and smart contracts (are supposed to) work.

The Great Crash, 1929 by John Kenneth Galbraith (1955)

Although Galbraith doesn’t use the phrase “animal spirits” once in the nearly 200-page book, this is clearly what the book is about. A pretty interesting look at how speculative bubbles can warp society as well as the market.

One takeaway for our modern age: you can probably find some parallels in the way housewives of the 1920’s might have taken a sudden interest in Wright Aero or in Steel, and the way non-techies of today are suddenly becoming interested in cryptocurrencies:

“To the typical female plunger the association of Steel was not with a corporation, and certainly not with mines, ships, railroads, blast furnaces, and open hearths. Rather it was with symbols on a tape and lines on a chart and a price that went up. She spoke of Steel with the familiarity of an old friend, when in fact she knew nothing of it whatever.”

Dream Hoarders by Richard V. Reeves (2017)

After reading this book, you might stop saying, “We are the 99%!” and start saying, “Oh crap, I am the 20%…”

It turns out that some of the most insidious forms of inequality (leading to a crisis of liberal democracy as described by Luce above) can be traced back to the gap between the so-called “upper middle class” and everybody else. It’s also not lost on the author that most of his readership probably counts themselves in that lucky 20%.

This is also a good segue into the next book:

Bobos in Paradise by David Brooks (2001)

The first time I heard the word “bobo” was when one of my French relatives was trying to explain who all those preppy-looking kids were hanging out on the lawn at Montmartre in Paris. I asked what “bobo” meant in English (I thought it was a French word), and the best translation we could come up with was “yuppie.” As Brooks explains, though, “yuppie” is really only half the story.

I found a lot to identify with and laugh at in this book, most probably because I am firmly in the “bobo” camp myself: a bourgeois by birthright, but a bohemian by disposition. We bobos may have achieved success in our chosen industries, but we find talking about money too distasteful, too gauche, and so we instead try to exude granola hippie values like you might find in the local REI store, on sale for $199.

The bobos are a ruling class that finds a way to combine Reaganite yuppiedom with 60’s hedonism, and in the process we’ve got none of the noblesse oblige that the previous ruling class, with their Elks and Rotary Clubs, ever had. Lord knows what we’re going to do with the world we inherit.

So You’ve Been Publicly Shamed by Jon Ronson (2016)

A book about tech that somehow doesn’t set out to be a book about tech. A pretty fascinating look into the history of public shaming, from the colonial era to the social media era.

A scary takeaway from this book is to realize how effective public shaming is as a punishment, and how cavalier we are nowadays to employ it merely as a remedy for boredom on Twitter. Some choice quotes:

“The people who mattered were the people on Twitter. On Twitter we make our own decisions about who deserves obliteration. We form our own consensus, and we aren’t being influenced by the criminal justice system or the media. This makes us formidable.”

“‘I’d never had the opportunity to be the object of hate before. The hard part isn’t the hate. It’s the object.'”

“On social media we’d had the chance to do everything better, but instead of curiosity we were constantly lurching toward cold, hard judgment.”

I read this book well after my own breakup with Twitter, but a lot of what I wrote in those three blog posts is echoed in this book. It’s a sobering read, and it’s made me a lot more ambivalent about all the high drama and escalations that seem to be an ongoing part of the social media experience.

Weapons of Math Destruction by Cathy O’Neil (2016)

I got my master’s degree in Computational Linguistics, and I worked for a time on building machine learning models (what we called “feature engineering”). Everything described in this book about how machine learning can effectively become a reflection of society’s preexisting biases rings absolutely true to me.

A lot of laypeople seem to have this hardened faith that computers are smarter than they are, and if the computer says something is true, well then it must be true. Unfortunately the reality of most machine learning is that it’s like a calculator: garbage in, garbage out. Sometimes you can build interesting systems by feeding it enough garbage that it starts to find signals in the noise, but even those signals can be a form of garbage if they just reinforce a society’s existing prejudices.

This book is a bit dry and overly long, but the sections on the criminal justice system, and how the “AI” used there to predict recidivism rates has just created an unaccountable feedback loop, are absolutely worth reading.

Fiction

The Amazing Adventures of Kavalier & Clay By Michael Chabon (2000)

What a great book. It has some of the most inventive language you’ll ever read, and the characters are so vivid that you’ll almost miss them after you turn the last page.

I loved the portrait of Josef Kavalier as a man who practically invents the “comic-book superhero beats up on Nazis” trope, and yet with every comic he writes, it only underscores his own impotence to save his family from German-occupied Czechoslovakia.

At times, it’s also a hilarious book. The scene where Josef and Sammy spitball a half-dozen superhero ideas had me roaring with laughter:

Sammy shook his head. “Ice,” He said. “I don’t see a lot of stories in ice.”
“He turns into electricity?” Joe tried. “He turns into acid?”
“He turns into gravy. He turns into an enormous hat. Look, stop. Stop. Just stop.”

Ham on Rye by Charles Bukowski (1982)

Possibly the best book I’ve ever read about toxic masculinity. Growing up in poverty during the Great Depression, being abused by his alcoholic father, feeling like he constantly has to pick fights with the biggest guy in the room to look tough… although I can’t identify with all the details, I strongly identify with the constant feelings of inadequacy associated with being a hormone-addled teenage boy.

Bukowski also seems to remember childhood in a way that few writers can, with all its confusion and logical leaps and dreamlike muddiness. A great book, and certainly the best in the Henry Chinaski trilogy.

Post Office by Charles Bukowski (1971)

The worst book in the Henry Chinaski trilogy. Henry gets a job at the post office, drinks a lot, sexually abuses a woman, drinks some more, is terrible at his job, and keeps drinking. Skip this one.

Women by Charles Bukowski (1978)

Charles Bukowski explains that, if you’re a famous writer, you can abuse, insult, and take advantage of women and get away with it. And all the while, you can believe yourself to be a misunderstood Casanova whose revolving harem of lovers just can’t heal the deep wounds in his deep poet’s soul. If I had read this book as a 17 year-old during my Jack Kerouac phase, it would have ruined me.

Ask the Dust by John Fante (1939)

A strange, haunting book. Fante, like Bukowski, is able to tap into the confusion of youth, telling a story about a guy who can think tender thoughts about the woman he loves, but in person can only manage to be coarse and callous to her. This book is about a love triangle where you half-believe all three participants actively despise each other, and that somehow that’s what drives the whole crazy thing forward. But it all rings true because human courtship is so inherently messed up.

The only part that didn’t ring true to me was the description of marijuana use, which reads as fairly antiquated given our modern understanding of the drug. In one scene, the protagonist buys a fridge full of food, and his poor lover is unable to eat any because she’s sick from smoking too much pot. (Fante, did you ever know any potheads?) The fact that the woman loses her mind because of marijuana (“reefer madness!”), and that this is a crucial plot point, is the only blemish that mars an otherwise excellent book.

Transmetropolitan by Warren Ellis and Darick Robertson (1997-2002)

This is a weird series of graphic novels. It imagines a future that’s not so much dystopian or utopian as just… what-the-fuck-topian. People modifying their DNA to look like aliens, religious zealots being reborn as sex-crazed clouds of gas, laboratories growing human flesh so that it can be sold for food… It’s as if they took all the griminess of 1970’s New York (ala Taxi Driver), added some Blade Runner sci-fi, and then dialed it up to 11.

The main message I got from this book is that one of the most unsettling aspects of the future might be its downright progressivism. It’s easy to look at the arc of history as bending toward justice, with a steady progression in the twentieth century toward greater freedoms and greater tolerance for a widening circle of people and behaviors. In short, social conservatives have been on the losing side of history for most of the past hundred years. But this book takes that idea to the extreme, to a future where absolutely nothing feels off-limits, and in the process it probes at some fundamental human concepts of the taboo, the sacred, the inhuman, and the profane. It’s disturbing in the same way that Mary Shelley’s Frankenstein was probably disturbing to 19th-century readers.

Another weird aspect of these books is how violent they are. Much of this violence also feels gratuitous and completely unnecessary, serving to punctuate conversations in the same way that Calvin and Hobbes’ sleigh rides punctuated theirs. (I.e., the drawings have nothing to do with the text, but it gives you something interesting to look at.)

Overall it’s an interesting read, although I wouldn’t recommend it to the queasy or faint-of-heart. It also lost my interest about halfway through, when it became less of a sci-fi cabinet of curiosities and more straightforward action thriller.

Snow Crash by Neal Stephenson (1992)

This is one of those books that’s supposedly “required reading” for nerds, along with The Lord of the Rings and Neuromancer, so I decided I should get around to reading it this year.

I found it pretty riveting for the first few chapters – lots of whiz-bang action and weirdness and excitement – but it sort of lost me about halfway through when the plot got too convoluted for me to follow. (Incidentally I felt the same way about Neuromancer.) Still, it’s interesting to understand where the concept of an online “avatar” came from, as well as lots of the ideas for things like MMORPGs, MUDs, and Second Life.

If nothing else, I can now use the phrase “That sounds like Snow Crash” to capture a certain feeling about virtual reality, and also to buy me some cred in nerd circles.

Living with an open-source phone

A few months ago, I decided to make a radical change to my smartphone lifestyle. I wanted a phone that would limit the amount of personal data I was broadcasting to third parties – namely Apple or Google – and decided to run a more-or-less vanilla version of Android, without any Google Play Services (i.e. no Google Maps, GMail, Google Play, or Google Search apps).

I’ve been living with this setup for a few months, and to my surprise, it’s really not that bad. It doesn’t feel like a return to the Stone Age, nor does it feel like I’ve sacrificed all the niceties of a smartphone to the point where I’m carrying around a glorified flip phone.

However, it’s a bit non-obvious how to get all of this stuff to work, and especially how to get by with a Android phone that doesn’t have the Google Play Store. So in this post, I’d like to talk a bit about my smartphone setup, in the hope that it might help someone who’s looking to make a similar switch.

Choosing an Android ROM

There are various flavors of Android out there: you can choose LineageOS (the spiritual successor to CyanogenMod), Paranoid Android, CopperheadOS, or you can even just build AOSP (the Android Open Source Project) from source.

After fumbling around with building AOSP from source (which was much more difficult than I thought – lots of requirements for the build environment, CPU horsepower, and storage), I also tried LineageOS and CopperheadOS, and eventually settled on LineageOS.

Why LineageOS? Well, mostly because it was easy, it offered fast security updates, and I like the minimalist interface and built-in apps. LineageOS was also familiar to me, as I had previously used Cyanogen for many years. (I forgot how much I enjoyed the small creature comforts, such as long-pressing the volume up/down keys to skip tracks!)

Screenshot of default homescreen on LineageOS

Default homescreen on LineageOS

I also needed a recovery image in order to install the ROM, and it seems that TWRP has become the de-facto standard these days, replacing the venerated ClockworkMod.

As it turns out, none of these options will result in a 100% open-source phone, as you’ll still be running the vendor binaries for your particular phone. But this is about as close as you can get to a smartphone that runs only free/libre open-source software.

Choosing a phone and installing a ROM

This isn’t going to be a guide to unlocking or rooting your Android phone. The process is different for every phone, and it would take too long to describe all the various steps. Suffice it so say that it’s still a painful process, and your choice of phone can either make it easier or harder.

I’ve been rooting, unlocking, and tinkering with Android phones for a long time, since the days of the HTC Dream and HTC Magic around 2009/2010. Since then, I’ve worked as an Android and mobile web developer, and I’ve become very comfortable with tools like the Android SDK, adb, fastboot, and Android Studio. And yet, to this day I still find installing custom ROMs to be a frustrating and time-consuming experience. I wish it were easier for casual folks to do this stuff.

The Nexus line of phones (now Pixel) have always been the easiest to customize, and for many years I stuck with the tried-and-true Nexus 5, which is still a surprisingly capable phone despite having been released in 2013. (I swear it ran faster than my 5X, which also kicked the bucket after only a year or two of use.) However, my aging Nexus 5 just couldn’t cut the mustard anymore due to hardware issues (the USB port was too loose; it had become tricky to charge it), and so I decided to buy a new phone instead.

I settled on the Samsung Galaxy S5, mostly because I could get it for cheap (<$200 on Amazon) and with full support for my carrier (T-Mobile). In retrospect, choosing a non-Nexus device made my life a lot harder, and after several hours of research on unlocking Samsung phones (including building Heimdall from source on a Windows machine, because the prebuilt binaries were out of date but the software was too old to build on a Mac), I finally had my LineageOS phone up and running.

The second thing you'll want to do is ensure that your device is encrypted, which you can enable in the security settings. Unfortunately this ended up making my phone unable to start the OS, but after booting into recovery and doing a factory reset, I had both encryption and the OS up and running just fine.

Screenshot of my LineageOS home screen

My LineageOS home screen

Getting apps

Without the Google Play Store, you'll have to use F-Droid, which has the added benefit of only hosting free and open-source apps. In fact, a couple of my own apps were previously on there (Catlog and KeepScore), and as far as I can tell, they were built directly from source. (I’m not sure why they were removed; possibly because I stopped maintaining them.)

To get F-Droid, you just download it directly from f-droid.org. You'll also have to allow installation from "unknown sources" in the security settings.

For the odd app that isn't available on F-Droid, you can also use the Yalp Store, which can either use your Google account or an ephemeral account to download apps from the Play Store. It’s not clear to me whether or not this violates the Google Play Terms of Service, though, so proceed with caution.

Messaging

I use Signal as my default SMS app and for most messaging with family and friends. Unfortunately it isn't available on F-Droid, but you can download it directly from the Signal website, or use the Yalp Store technique above.

Update: if you’re wondering how to verify the SHA256 fingerprint of the APK downloaded from the Signal website, here’s an example.

Like most Android apps, Signal normally uses Firebase Cloud Messaging (FCM, formerly GCM) to send push notifications. If you don't have Google Play Services installed, Signal will offer to switch to a less battery-efficient background polling mechanism.

I've used this mechanism for months and only had occasional problems where a large backlog of old messages was suddenly delivered all at once. It also hasn't had a visible impact on battery life. (I usually end the day with half a charge left; the GS5 has a great battery!)

Web browser

For a web browser, I mainly use Firefox via the FFUpdater tool, which is clunky but gets the job done. I’ve set DuckDuckGo as my default search engine, and I have uBlock Origin installed as an add-on, which undoubtedly makes my browsing faster and easier on the battery.

Occasionally though, I do find sites that don’t run so will with mobile Firefox, and for that I use Auto Updater for Chromium, which automatically installs Chromium and updates it. This is a bit nicer than FFUpdater because it does its work silently in the background, rather than requiring you to manually check for updates.

The built-in browser doesn’t support “Add to Homescreen,” so I find it fairly useless.

Maps

I use OsmAnd~, which is nice because it allows you to download maps in advance for offline use. Unfortunately it’s still nowhere near as feature-complete as Google Maps, so if you’re looking for something to help you navigate your car, you may be out of luck. (Update: actually, OsmAnd~ supports turn-by-turn navigation.)

I also frequently use maps.google.com in Firefox, which works surprisingly well. Besides some minor performance issues, it’s fairly indistinguishable from the native app for basic directions, bus timetables, and store lookups.

Screenshot of Google Maps running in Firefox

Google Maps running in Firefox

Living in Seattle, one of my favorite apps is also OneBusAway, which provides up-to-date arrival times for Seattle buses. Unfortunately this app requires Google Play Services in order to work, so I’ve had to do without.

Weather

Speaking of Seattle, it’s also important for me to know how much it’s going to rain in a given day. (Spoiler alert: a lot.)

This happens to be one of those things about LineageOS that’s a bit non-intuitive. To get weather to work, you have to go to the “extras” page and download a weather provider. (In my case, I’m using OpenWeatherMap.)

Unfortunately, though, even after installing the weather provider, I couldn’t get the built-in “cLock” widget to show the weather. (It keeps saying “network geolocation is disabled,” even though it’s not.) So I ended up installing Forecast widgets, which gets its data from the National Weather Service rather than the built-in weather provider.

Maybe this is just some bug with my installation or with the hardware itself, but in any case I’m satisfied with this workaround. The Forecast widget looks and works fine.

Screenshot of weather and time widget on my homescreen

Weather and time widget on my homescreen

Keyboard

The only non-standard features I really want from a keyboard are 1) emoji support, and 2) swipe input.

Unfortunately I couldn’t find any open-source keyboard that can do both of these things, and the AOSP keyboard doesn’t seem to support either. The closest I found was AnySoftKeyboard, which at least has an emoji screen. It doesn’t allow you to search for emoji, though, which is a bit frustrating.

Screenshot of sending an emoji via AnySoftKeyboard and Signal

Sending an emoji via AnySoftKeyboard and Signal

Overall, the keyboard experience has been my least favorite part of the LineageOS experience. I didn’t realize how much I had become accustomed to swipe input until I had to revert back to tapping, which feels to me like hunt-and-peck. Input is extremely laborious and slow, although on the plus side I’m spending less time texting, so maybe that’s a good thing.

Update: actually, AnySoftKeyboard does support searching emoji! You just need to type : and then the search term.

Music and podcasting

I’m a fairly old-school music consumer. I prefer to listen to albums from start to finish, and I never really got into services like Pandora or Spotify. Instead, I buy my MP3s from Amazon (old habit, my entire library is there) and then sync them from my desktop computer to my phone using adb-sync.

For browsing and listening to my music library, I’ve found Vanilla Music to be fantastic. It has a cover art downloader, the interface is minimal and clean, and it can play an album from start to finish, which is all I really ask.

Screenshot of Vanilla Music with some of my albums

Vanilla Music with some of my albums

Oh, and of course Vanilla Music sets the cover art on the lock screen. It’s the little things that count.

I’m also something of a podcast addict, so I use AntennaPod to download and listen to podcasts. I’ve tried several podcast apps on F-Droid, and I found this one to be the easiest and most reliable overall. I particularly like that it allows me to search on iTunes, since some podcasts can be hard to find elsewhere.

Social media

I stopped using Twitter, but if you absolutely must, their mobile website is not bad in either Firefox or Chromium. I’m told Facebook’s mobile website is also pretty functional.

I spend most of my social media time these days on Mastodon, and as it turns out the mobile websites work perfectly fine in both Firefox and Chrome, so you can just pin it to your homescreen. There’s also Tusky if you prefer the native app experience.

Ridesharing

I don’t use Uber, but Lyft has a mobile webapp that works just as well as their native app. So when I need a ride, I just open ride.lyft.com in Firefox. It’s a PWA, and as far as I can tell it works just as well as the native Android app.

Somewhat bafflingly, though, if you go to lyft.com directly, the site may try to route you to their driver portal or to the app store instead.

Screenshot of Lyft's website offering "Lyft in Firefox,"

Lyft’s website may offer “Lyft in Firefox,” which is the PWA

In case you get confused, you may need to look for the “Lyft in Firefox” link. To me, this seems like a bizarre way of saying “Lyft for the web,” but you do you, Lyft.

Email, calendar, and contacts

I switched to FastMail recently for my primary email account, and I’ve been really happy with the service. It’s fast, it’s simple, and it has a clear business model where I pay them 5 bucks a month and they host my email. Simple.

To get my email on my phone, I use K-9 Mail, as I’ve found it a bit more reliable and feature-rich than the built-in Email app. If you prefer a simpler interface, though, the built-in app works fine too.

FastMail also supports calendar and contact sync, and this is where it gets a bit trickier. If you’ve ever connected an email client to your email server by manually typing the IMAP and SMTP settings (which, incidentally, you’ll have to do for K-9 email), then it’ll feel pretty familiar. FastMail supports CalDav and CardDav, and so to hook these up to my phone I used DavDroid.

Honestly this was probably the most tedious process of setting up my LineageOS phone. It involved creating app passwords for each client (I use separate passwords for email, calendar, and contacts, in the interests of security), and manually typing in the server names and ports for the various FastMail endpoints. This was a long and error-prone process, but in the end I do have full email, calendar, and contact sync, so I can’t complain.

Passwords and two-factor auth

For nearly a decade I’ve stored my passwords using the Joel Spolsky method, which is to use PasswordGorilla on desktop and PasswdSafe on Android. I like this method because it’s simple, it works cross-platform, and I maintain control of the password file.

For two-factor authentication (other than basic SMS), there’s FreeOTP, which essentially takes the place of Google Authenticator.

The web works for everyone

One of my main reasons for switching to a non-Google Android phone was to see how capable the web is as an application delivery system. And aside from the native apps listed above and some minor utilities (e.g. a barcode scanner and a notes widget), I do pretty much everything in a web browser.

Media sources like Hacker News, Ars Technica, and others don’t need an app – you can just pin a website to your home screen. (Although for Hacker News, I use the excellent hn.premii.com.) The main exception for me is NewsBlur, which I access via the open-source client app.

For videos, both YouTube and Vimeo also work great as mobile webapps. In Firefox, they can run both in fullscreen mode and in the background.

For file sync, I use Dropbox’s mobile webapp for quick file downloads from my Dropbox account and Firefox Send for sending more ephemeral files. I need a better solution to backing up photos, though; for now I’m just using adb-sync to sync to my Dropbox folder on the desktop.

I also do work at Microsoft, and although I have a personal policy of not syncing my work email to my phone, I can make a temporary exception by loading outlook.office.com in Firefox, which works surprisingly well. For those odd moments when I need to send an email or check the location of a meeting, it gets the job done.

As a guitarist, I also needed a way to tune my guitar, and sadly the excellent g-strings is both paid and closed source, so it was a no-go. So I use Paul Lewis’ guitar tuning webapp instead, which is a good substitute.

Screenshot of guitar-tuner.appspot.com

Me singing a bit off-key into a guitar tuner

Turns out the web of 2017 is capable of quite a bit, from hailing a taxi to tuning your guitar!

Conclusion

I hope I’ve demonstrated in this blog post that it’s not only possible to use an open-source phone without any of the pervasive tracking, spyware, or bloatware that we’ve come to expect from most smartphones, but it’s actually quite viable and even enjoyable.

When I booted up my Galaxy S5 for the first time, I was immediately greeted with a barrage of ads for Samsung and T-Mobile services and upsells, all in the 5 minutes it took to turn on USB debugging so I could install custom software and mercifully silence all of the nagware. My clean and stripped-down LineageOS setup is about as far from that horrendous out-of-the-box experience as you can get.

Note though, that this is the setup that works for me, and your mileage may vary depending on how much you rely on various software and services. If you use GMail and GDocs, you may be better off just using a Google-flavored Android phone. And if you’re bought into the iTunes and iCloud ecosystem, it may be more trouble than it’s worth to switch from an iPhone.

Also, despite my attempts to de-mystify some of the less obvious parts of this setup, I’m in no way claiming that any of this is accessible to the non-geek, non-hacker crowd. The mere process of installing LineageOS is so far beyond the capabilities of the average non-techie that it actually fills me with a kind of despair.

This is probably a subject for an entire post, but I’m becoming concerned that my friends and I in the open-source, pro-privacy hacker scene are building a two-tiered world, where the tech elite can successfully install and configure software that maintains their security and privacy, whereas the average person is stuck either paying a premium for a privacy-respecting but closed-source iPhone, or paying a reasonable price for an Android phone where their security and privacy are far from assured.

That said, maybe if more of us inhabit this (admittedly neophyte-unfriendly) world, then maybe we can work to make it more accessible to those of us who don’t know how to use a command line and have no patience to type out IMAP server URLs into their smartphone. Let’s hope so.

Why I’m deleting my Twitter account

When I first got on the Internet back in the 90’s, it felt like a cool underground rock concert. Later on, it seemed like a vast public library, maybe with a nice skate park nearby. Today it feels more like a shopping mall. The transition happened so gradually that I barely noticed it.

Hanging out with your friends at the mall can be fun. But it can also be tiring. You’re constantly surrounded by ads, cheery salespeople are trying to get you to buy stuff, and whatever you eat in the food court is probably not great for your health.

For the past few years, I’ve subsisted on a media diet that mostly came from Twitter, consisting of “snackable” news articles with catchy headlines, shareable content with wide appeal (baby koala cuddles baby cat, how cute!), and righteous outrage at whatever horrible political thing was happening that day.

Twitter was often the first thing I looked at when I picked up my phone in the morning, and the last thing I browsed late into the night, endlessly flicking my thumb over the feed in the hope that something good would pop up. The light of the smartphone was often the only thing illuminating my bedroom before I finally turned in (always much too late).

All of this content – cat pictures, articles, memes, political hysteria – came streaming into my eyeballs in a rapid and seemingly random order, forcing my brain to make sense of the noise, to find patterns in the data. It’s addictive.

But the passivity of it, and the endless searching for something good to watch, meant that for me Twitter had essentially become television. Browsing Twitter was no more edifying than flipping through channels. At the end of a long, multi-hour session of Twitter-surfing, I could barely recall a single thing I had read.

Social media as public performance

Twitter is unlike television in a few crucial aspects, though. First off, the content is algorithmically selected, so whatever I’m seeing is whatever Twitter has determined to be most likely to keep my eyes on the screen. It’s less like I’m surfing through channels and more like the TV is automatically flipping from channel to channel, reading my eye movement and facial expressions to decide what to show next.

Second, Twitter has become an inescapable part of my professional life. My eight thousand-odd Twitter followers are a badge of honor, the social proof that I am an important person in my field and worthy of admiration and attention. It also serves as a measure of my noteworthiness in comparison to others. If someone has more followers than me, then they’re clearly more important than I am, and if they have less, well then maybe they’re an up-and-comer, but they’re certainly not there yet.

(This last statement may sound crass. But any avid Twitter user who hasn’t sized someone up by their follower count is either lying to themselves, or is somehow immune to the deep social instincts that mark us as primates.)

For the kinds of professionals who go to conferences, give public talks, and write blog posts, Twitter serves as a sort of “Who’s Who,” except that everyone is ranked by a single number that gives you a broad notion of their influence and prominence.

I’m sure many of my friends from the conference and meetup scene will look at my announcement of deleting my Twitter account as a kind of career suicide. Clearly Nolan’s lost his mind. He’ll never get invited to a conference again, or at the very least he won’t be given top billing. (Conference websites usually list their speakers in descending order of Twitter followers. How else can you tell if a speaker is worth listening to, if you don’t know their follower count?)

Much of that is probably true. I used to get a lot of conference invites via Twitter DMs, and those definitely won’t be rolling in anymore. Also, anyone who wants to judge my influence by a single number is going to have a hard time: they’ll have to piece it together from blog posts and search results instead. Furthermore, my actual influence will be substantially reduced, as most of the hits to my blog currently come from Twitter.

Why I’m done with Twitter

Thing is, I just don’t care anymore. I’ve spent years pouring my intellectual and emotional labor into Twitter, and for countless reasons ranging from harassment to Nazis to user-hostile UI, platform, and algorithm choices, they’ve demonstrated that they don’t deserve it. I don’t want to add value to their platform anymore.

To me, the fact that Twitter is so deeply embedded into so many people’s professional lives is less a reason to resign myself to keep using it, and more a reason to question and resist its dominance. No single company should have the power to make or break someone’s career.

Twitter has turned a wide variety of public and quasi-public figures – from Taylor Swift to a dude who speaks at tech conferences – into brand ambassadors for Twitter, and that ought to worry us. Despite what it claims, Twitter is not a neutral platform. It’s an advertising company with a very specific set of values, which it expresses both in how it optimizes for its core constituents (advertisers) and how it implements its moderation policies (poorly).

Well, it may indeed be a bad career move for Taylor Swift to abandon her Twitter account, but for a (very) minor public figure like myself, it’s a small sacrifice to make to knock Twitter down a peg. My career will survive, and my mental health can only improve by spending less time flicking a smartphone screen into the late hours of the night.

That’s why I’m deleting my account rather than just signing out. I want my old tweets to disappear from threaded conversations, from embeds in blog posts – anything that’s served from twitter.com. I want to punch a hole in Twitter’s edifice, even if it’s a small one.

I’ve backed up my tweets so that anyone who wants to see them still can. I’m also still fairly active on Mastodon, and as always, folks can follow me via my blog’s RSS feed or contact me via email.

This isn’t me saying goodbye to the Internet – this is me saying goodbye to the shopping mall. But you can still find me at the rock concert, in the public library, and in the park.

What is Mastodon and why is it better than Twitter

Mastodon is a Twitter alternative that recently released version 2.0 and has been steadily growing over the past year. It’s also a project that I’ve been dedicating an inordinate amount of my time to since last April – helping write the software, running my own instance, and also just hanging out. So I’d like to write a bit about why I think it’s a more humane and ethical social media platform than Twitter.

Much of the discussion around Mastodon centers on the fact that the flagship instance explicitly bans Nazis. This is true, and it remains a great selling point for Mastodon, but it also kind of misses the point. Mastodon isn’t a single website run by a single company with a single moderation policy. It’s a piece of open-source software that anybody can use, which in practice means it’s a network of independent websites that can run things however they like.

There is no company behind Mastodon. There’s no “Mastodon, Inc.” Mastodon doesn’t have a CEO. The code is largely written by a 24-year old German dude who lives off Patreon donations, even though he’s a very talented web developer and could probably make a lot more money if he joined the industry. He works on Mastodon because it’s his passion.

What this means is that if someone wanted to take Mastodon’s code and build a competing service, they could do so trivially in a matter of minutes. And they do. The original instance, mastodon.social, isn’t the only server – in fact, it’s not even the biggest one anymore. There are over a thousand active instances, and it’s become easy enough that Masto.host can even create one at the click of a button.

In practice, though, these Mastodon instances don’t compete with each other so much as they form a giant constellation of interconnected communities. Users from any server can read, follow, and reply to users on another server, assuming neither of the two servers is blocking the other.

The closest analogy is email: if you use Gmail, you can still communicate with someone who uses Outlook.com and vice-versa, because they both rely on the same underlying system (email). Through its own underlying systems, Mastodon (as well as compatible software like Friendica, GNU Social, and postActiv) forms a network of independent sites referred to as the “fediverse,” or federation of servers.

Why this is better than Twitter

The problem with Twitter is that its incentives are completely misaligned with those of its users. Twitter makes its money from advertising, which means that its goal is to keep your eyes glued to the screen for as long as possible, and to convince you to interact with ads. Its goal is not to keep you safe from harassment, or to ban dangerous extremists, or to ensure your psychological well-being. Its goal is to make advertisers money by selling them an engaged audience.

This is why Twitter will never #BanTrump, even though many have called for it after he began threatening North Korea on the platform. From Twitter’s perspective, Donald Trump increases engagement. Donald Trump gets eyeballs. If Donald Trump started a nuclear war on Twitter then hey, all the better, because Twitter would get a massive boost in traffic, at least right up until the point the bombs started raining down. Twitter even uses Trump in some of its advertising, which gives you an idea of how they feel about him.

Mastodon, by contrast, isn’t run on advertising. Well, instances could add advertising if they wanted to, but I’m not aware of any that do. Most of them, including the flagship, are run on donations from their users. Others get a bit more creative: cybre.space, for instance, allows free signups for one hour each day, but if you donate you can get an instant invite. capitalism.party is an interesting experiment where every signup costs $5. social.coop is run as a co-op. The possibilities are endless, since the underlying code is open-source.

What these instances all have in common is that they’re not driven by the insatiable appetite of marketers for clicks and engagement – instead, their goal is to make as warm and hospitable a place for their users as possible. The incentives of the people who run the platform are aligned with the incentives of the users.

Ultimately, this is why Mastodon instances can implement the kinds of moderation policies that their users clamor for (including banning Nazis). Most instances only have a few dozen to a few thousand active users, and they’re often organized based on shared interests, languages, or nationalities. This means that each instance tends to be small enough and like-minded enough that they can have fairly nitpicky moderation policies (or policies that adapt to local laws and customs), and it’s not too overwhelming for a small group of sympathetic and highly-motivated admins to handle.

Privacy and respect for the user

There are a lot of other benefits to Mastodon’s lack of an advertising model. For one, as a Mastodon user you’re not subjecting yourself to the adware, spyware, and bloatware that we’ve come to expect from much of the modern web. To see what I mean, here’s a screenshot of my instance, toot.cafe, compared to Twitter.com.

creenshots of Twitter vs Mastodon, showing Twitter loading 3.48MB of JS vs 990.84KB on toot.cafe

Besides the refreshing lack of advertising on the Mastodon site (and toot.cafe’s charming purple theme), you might observe that Mastodon is loading less than a meg of JavaScript, whereas Twitter loads a generous 3.5MB. A lot of that extra heft is probably just standard web bloat, but if you have an ad blocker or tracker blocker installed, then you can see another dimension to the story.

Screenshot of Ghostery showing 4 trackers blocked on Twitter.com vs 0 for toot.cafe

According to Ghostery, Twitter.com is loading 4 separate trackers, including Google Analytics, TellApart, Twitter Analytics, and Twitter Syndication. (Those last 3 are all owned by Twitter, so who knows why they need 3 separate trackers for each.) Whereas on the Mastodon site, Ghostery found 0 total trackers.

Screenshot of uBlock origin showing 14 requests blocked for Twitter vs 0 for toot.cafe

Looking at uBlock Origin, we can see it needed to block 14 requests on Twitter.com, or 9% of the total. On the Mastodon site, though, uBlock didn’t need to block anything.

Beyond the lack of ads and trackers, though, these privacy benefits accrue to the data you share with the website itself. On Twitter, you’re handing over your tweets, browsing habits, and photo metadata to a large VC-funded company that makes no bones in its privacy policy about all the various ways it feels entitled to use and sell that data. The terms of service also make it clear that once you post something, Twitter can do whatever it wants with it.

Screenshot of https://twitter.com/en/tos#usContent starting from "By submitting, posting or displaying Content..."

A snippet of Twitter’s terms of service.

Now compare this to Mastodon. On Mastodon, image metadata is stripped by default, links show up as (wait for it) actual links instead of tracking redirects, and some instances even go so far as to specify in their terms of service that you’re not relinquishing any copyright over your content and your data will never be sold.

Screenshot of mastodon.art's guidelines, saying "All content is ⓒ each artist & cannot be distributed or used without prior permission by the respective Mastodon.ART artist."

A snippet of mastodon.art‘s terms of service.

It’s such a far cry from the way we’re used to being treated by online services, with their massive legalese-laden EULAs stripping us of the right to do anything beyond gripe at the rough way we’re being manhandled, that using Mastodon can almost feel like browsing a web from a parallel universe.

So Mastodon is a paradise, right?

I’m not going to pretend that Mastodon is devoid of moderation problems. Yes, the flagship instance bans Nazis and other malcontents, as do most of the other large instances (including my own). There are plenty of instances with their own policies, though, and there’s nothing in the software to prevent them from doing so. So if you want to use an instance that harbors Nazis, or even just libertarians or free-speech advocates, then you can certainly find them.

As you can imagine, though, a right-wing instance that brags about its tolerance toward fascists is not likely to get along with a left-wing instance that bills itself as “anticapitalist”. Thus you will find lots of instances that block each other, creating a situation where you might discover vastly different content and vastly different people depending on which instance you sign up with.

This goes beyond straightforward disagreements between the political left and right. Every so often in the Mastodon community, a serious conflict will arise between instances. Often it starts because two users on two different instances got into a fight with each other, the admins got involved, and they disagreed on how to resolve the dispute. Sometimes it’s the admins themselves who started the fight. Either way, the admins end up criticizing or disavowing each other, the public timeline gets filled with debates on who’s right or wrong, and ultimately one group of instances may decide to block or silence another group. We call this “the discourse.”

“The discourse” tends to flare up every month or so, and when it does there’s usually a lot of moaning about how much drama there is on the fediverse. This lasts for a day or two and then things go back to normal, albeit with a slightly more bifurcated community than we started with.

Discourse and disintegration

I don’t enjoy “the discourse,” and I tend to agree with folks who argue that it could be alleviated if Mastodon had better tools for resolving inter-admin conflicts. I don’t think this problem can ever be completely eliminated, though. Human beings are just naturally inclined to seek the company of those they agree with and shun those they disagree with. This has the unfortunate effect of creating filter bubbles, but it turns out human beings also have a boundless appetite for filter bubbles, as evidenced by the churches, clubs, meetups, and political parties where we seek those who are similar to us and give a cold shoulder to outsiders.

I don’t believe it’s Mastodon’s job to correct the problems caused by the right to free association. But Mastodon could improve the process of communities splitting into smaller, more harmonious networks of people with shared values and mutual tolerance for one another.

Furthermore, a lot of these disputes boil down to a difference of opinion over what constitutes harassment, abuse, hate speech, etc. So in a way, “the discourse” can be seen as a testament to the seriousness with which these subjects are treated on Mastodon. Instance admins care so much about the well-being of their users and protecting them from disturbing content, that they routinely argue and even block each other over the best way to implement it.

Now compare that situation to Twitter. On Twitter, there’s one moderation policy, and if you don’t like it: tough. Whereas on Mastodon, if you don’t like your instance’s policy, you can always switch to another one. (And there’s work in progress to make that migration easier.)

Conclusion

Mastodon is not perfect. The software is still rough in some places, the underlying protocols (OStatus and ActivityPub) are still getting hammered out at the W3C, and the community devolves into tiresome bickering more often than I’d like.

But I still have more faith in Mastodon than I do in Twitter, whose user growth has flatlined and whose profits are nonexistent, and thus will have to resort to increasingly desperate measures to satisfy its investors, who are still waiting for a sweet return on investment for all those eyeballs they bought. I expect this will mean more promoted tweets, more ways to promote tweets, and ultimately less value for Twitter’s users, as they become increasingly drowned in a sea of brand accounts trying to sell them a hamburger, fake news trying to swing an election, and bots trying to do who knows what. Meanwhile the harassment problem will never be Twitter’s main priority, despite what their CEO says, because as long as controversy and conflict are good for grabbing eyeballs, they’re good for Twitter’s bottom line.

The main reason I’m hopeful about Mastodon is that it’s an opportunity to learn from Twitter’s mistakes and to experiment with fresh ideas for improving social media. For instance, how about disabling public follower counts, since they can make us feel like we’re living in a Black Mirror episode where everyone’s self-worth is determined by a single number? (In fact witches.town already does this; every user’s number is a cheeky 666.) Or how about removing the “quote-repost” feature, since we saw the nasty dog-piling it enabled on Twitter? Or how about adding features that encourage users to log off every once in a while, so that social media doesn’t turn into an addictive slot machine?

All of these things are possible in Mastodon, because the code is open-source and the servers belong to the users. We can even tinker with these ideas at the instance level, to test how something pans out at the small scale before bringing it to a wider audience. Instead of Twitter’s one-size-fits-all approach, we can tailor social media to fit the needs of every community, with local admins who are motivated to help because they’re moderating a small group of like-minded people rather than 300 million of them.

Mastodon can feel like a return to another time, when the web was small and it felt possible to actually have an impact on the websites we use every day. But it’s also a glimpse into the post-Twitter future that we need, if we want to have control over our data, our minds, and our public discourse.

Interested in Mastodon? Check out joinMastodon.org or instances.social for help finding an instance to join. If you’re not sure, I’d recommend toot.cafe (my own), cybre.space (cyberpunk themed), mastodon.art (for artists), awoo.space (focus on safety), or for general interests: mastodon.social, icosahedron.website, or octodon.social.