You’ve got a shiny new computer and want to avoid closed source browser components. Firefox is already open source, but everyone needs more than one browser. Chrome is the obvious choice, but is closed. Luckily its core, Chromium, is open. Unluckily, there’s no trusted source to grab it from. This month’s ship, Easychromium, solves this problem. Read on for lessons learned from a nitty and gritty Ship 2.
I’m shipping something new each month to learn and grow my capacity as a “full stack” tech person. So far I’ve broken down the capacities into promoting the product, messaging, attracting users/customers, etc. (marketing), designing the experience, finding product/market fit, and ensuring the value proposition gets delivered (product), and building the product (coding).
A couple caveats. Not every project touches each of these, as time goes on I may discover more essential business functions (payments processing!), and of course some lessons are only accessible as the scale of operations increases (e.g. HR). Nevertheless, I’m learning a lot and growing rapidly as I tackle each mini-project.
See Lessons from Ship 1, where I made a twitterbot, for more background (sidebar: turns out Twitter suspended my account…maybe for posting too much? Head’s up that 1 post every 2 minutes may be too many, despite the fact that I thought I read that as a guideline somewhere…).
Easychromium is a bash script that builds the latest stable release of Chromium from source.
The current options for installing Chromium on OSX involve installing a binary from
homebrew cask or from
freesmug (which I believe downloads from sourceforge).
Only one of these alternatives offers a checksum for the code, and even then it’s not signed. And one of them distributes via Sourceforge, recently criticized for putting adware into open source projects (though now under new management). I wanted a cleaner install path that could give users confidence in their browser, so I built a script.
As a bonus, Easychromium should be installable as a cron job to automatically update Chromium (it checks to see if Chromium is installed and if a newer version has been released).
Three Big Learnings
- The gap between functional and usable
- The ideal relationship between marketing, product, and engineering
- How and when to ask for help
1) Functionality vs. Usability
Usability is a very, very high bar. Everything must work and all the rough edges must be smoothed over. This is an exhausting thing to have to do after having to slog through the forest just to get the damn script to work in the first place.
For a product to truly be consumer-ready everything must be thought out. Using the product should be an absolutely frictionless, almost mindlessly easy experience. It should be as close to free utility in the economic sense as possible. More precisely, after purchasing the product, the marginal cost to derive utility from it should be zero.
An example: Automatic Updates
From a software engineering perspective there is a massive amount of work that has to happen under the hood to take care of this. For example, consider auto-updating. The whole point of having a browser built from source is to enjoy greater confidence in its security: you know (for some value of ‘know’) what you’re getting.
But if this browser is impossible to update, you’re not doing very well. Bugs and security vulnerabilities are fixed regularly, and you need access to those fixes. The problem is that recompiling from source takes hours, as many as 3-5 to overnight, depending on the end-user’s machine.
A couple of challenges here. First, the machine I’m developing on is not the machine everyone else will be using, so testing in general and judging the “pain” of the update process (e.g. time to complete) in particular is hard. Second, we want updates to be transparent and occur in the background, with essentially no user intervention until a little bubble pops saying “let’s restart Chromium.”
How do you implement that? To update from source you’ll need to pull new code, compile it, and then copy over the new application into the user’s
/Applications/ directory. Is now a good time to use the Internet connection? What if the user’s tethered on a mobile plan, on airport wi-fi, or not near the Internet. Can we support resume from partial downloads if the user has to shutdown in the middle?
Is now a good time to compile? Is the user plugged in or will I drain their laptop battery? Is it okay if their fans go super loud or are they trying to concentrate? Will it slow down their movie editing? What if compilation gets interrupted?
Is now a good time to replace their old Chromium.app with a new one? What if they’re currently using the browser? Should we save their old tabs? Should we interrupt their browsing or ask them for a good time? What should that dialog look like?
User experience guides development
We can clearly see that product must drive these decisions. The general frame is: how do we deliver value to the user with zero (or minimal) marginal cost? This means minimizing the amount of user interaction, especially true for a non-user-facing service like updating the browser (as opposed to a mobile app where the opposite goal: driving engagement, might occur*). With that frame in place we can understand the technical decisions to make, which have to do with:
- Resource Discovery – do we have Internet? Is it wi-fi or data? Do we have power? Do we have system resources like CPU/RAM available?
- Scheduling – when should the auto-update run? Should downloading and compiling be separate tasks? How do we keep track of what tasks have run and which haven’t? Can we set the process priority low to avoid stealing resources from user-facing applications?
- Intermediate States – how do we keep track of intermediate states of completion? Are all tasks resumable from mid-points? What if the laptop loses power or Internet unexpectedly, how do we exit gracefully? Is it cheaper to just start from scratch in some instances, which ones?
No easy answers, but scope is key
These questions don’t have easy answers, but for a consumer-ready product that needs to be usable they are 100% necessary. While spiritually my aim in these projects is to ship something, it’s not feasible to churn out one functional and fully usable product a month in my spare time. The key lesson learned here is: for solo practitioners, tightly scoping product, marketing, and engineering in conjunction from the beginning is key for delivering to market. This is especially true as our resources are limited, since we’re often working another job while trying to pull off a product launch. I’m excited to see how a year of shipping projects makes me ready to deliver a true product experience afterwards.
2) The relationship between marketing, product, and engineering
Reflecting on this project, it helps to start with the “why?” Why did I do it? I built Easychromium to solve a specific problem I had: wanting to build Chromium from source so I could have a trusted open source browser. This is a very common approach for hackers and techies to take, but does it make good product?
We could go ahead and address the usability questions we proposed above, make auto-updating buttery smooth, and end up with a pretty usable product. But would anybody want it?
Well, we could try placing some ads, or posting it on Facebook, or emailing various open source dev lists about it (or trying to get it placed on Glenn Greenwald’s privacytools.io), but what’s the right way to frame it? Have we built something whose message users will want?
Seen this way we can reorder the path to producing a killer product.
We should start with Marketing, to consider what message users will be receptive to. Implicitly, this has us already thinking about the value proposition from the perspective of the user. This lets us know why users want.
Then we can think about a product that fulfills that need. We can consider how to craft an experience that is usable, simple, and whose marginal cost to derive utility post-purchase drops to zero. This lets us know what users want.
Finally, we can figure out how to build, deliver, and maintain that experience. This lets us know how to fulfill the users’ wants. And of course, in reality, each of these is actually a hypothesis. We think users want product x because of reason y, which we can build with method z. With this framework in place, we can now test and iterate.
3) How to ask for help, effectively
Let’s talk about that last hypothesis, the engineering one. How do we know method z will work? There’s a ton of technical tradeoffs to consider, chief among them the amount of technical debt the team is taking on. But talking about technical debt and tradeoffs assumes we have competing system designs to evaluate. How do we come up with a system design in the first place?
When designing Easychromium I did what most people do when starting out and googled. I found a series of webpages from the Chromium team with documentation, almost entirely targeted towards developers hacking on the project, not end-consumers trying to build the project. Coupled with an outdated blog post, this led me to a build process that produced the latest bleeding-edge build, was a Debug build, and as a result was unstable (not ready for production).
What’s worse, my workflow was following an obsolete model. Since I thought I had to manually tweak a .gclient file (a file holding configuration settings for the Google tool gclient, which handles syncing the source code), my entire build ended up irrecoverable (starting with “Managed Mode: True” makes it very hard to migrate to “Managed Mode: False,” which is necessary for properly fetching Chromium source for a stable build).
Instead I needed a different process that would compile the latest stable build, produce a Release version, and thus give me something usable for end-users. To get to the correct workflow took a month of hacking around, building prototypes, sending them over the list, and having folks go “Oh, that’s what you’re trying to do? Why not try x?”
While I was asking for help, I wasn’t doing it in the most efficient way possible.
The smart way to ask for help
The trick requires understanding that the engineering hypothesis is a hypothesis just like any other. To test it we ship an MVP (minimum viable product) and see what the feedback is like. The breakthrough here is that we don’t actually need to build anything to ship our MVP. Our MVP is just words: it’s a plan.
Had I opened my engagement with the Chromium-dev list by saying “Hey, I’d like to create a bash script for users to fetch the source code, check dependencies, and build the latest stable Mac release on an OS X machine. Here’s how I’m thinking of doing that <snip>. Is this the smartest way to go about it?” I might have saved myself a lot of headaches.
Asking for help in open source communities
Easychromium is my first significant engagement with an active open source community, and I learned three important things about how to send emails that will get answered with the help you need.
The key things to remember are:
- people have differing levels of knowledge
- documentation is generally targeted towards whatever the project considers to be a contributor (so if your use-case falls outside that, know you’ll need extra help)
- people come and go as they are available.
Keeping these in mind,
- Ask for the best approach first before writing any code.
- Write a separate email for each problem you encounter – CC any people from a previous thread who were helping you. New emails start at the top of the list. Old ones will never get read.
- Always include background info on your project’s motivation and goals with each email you send. Even if you’re trying to figure out some specific implementation question, someone will come along and say “oh why don’t you just do it this other much simpler way.” Since little is written down, the knowledge you want is mainly in the heads of the individual contributors. Craft your emails as opportunities for people to share this knowledge, no matter what you’re asking about.
I’m glad I did this project. Easychromium was a very “backend”-y type project to code up, and also involved learning a lot about how large open source projects are organized (the difference between debug and release builds, component builds and the speedup on linking, trunks vs. branches and what “tree closure” means, sheriffs and their role in continuous builds, etc.). In addition I learned a ton about bash, which I’ll expand on in my technical lessons learned post.
Plus I’ve got a good addition to my heuristic for selecting future Ship projects to work on: in addition to technically interesting hacks, I can select projects that introduce me to a business function (e.g. payments processing) that I haven’t yet touched.
Beyond upgrading my technical chops, Easychromium gave me an opportunity to reflect more deeply about the relationship between Marketing, Product, and Engineering, and gather my thoughts a bit on what my first full product launch will entail. Learning just how big the gap is between functional and usable is a lesson that really takes fire with experience. No matter how much anyone tells you that successfully launching a product is a hard thing to do, we’re programmed to ignore these kinds of warnings. It’s the entrepreneur gene. But fully appreciating the challenges ahead can only be helpful in surmounting them, and I’m grateful for the lessons learned.
*Sidebar: allow me to introduce a hypothesis, I’ll call it “the product/provider hypothesis.” The value proposition of the product to the consumer should align with the value proposition of its consumption to the provider. In other words, if we want to drive engagement on our mobile app because it makes us money (say with ads or in-app sales) when users spend lots of time in there, then spending lots of time in there should constitute the value proposition to the user. The value proposition and the mode or style of consumption must be identical. Tax accounting software for small businesses? We don’t want users spending a bunch of time in there, make it painless. Candy Crush? A little pain is good…
**Diagram built with draw.io, which is really easy to use!