When we brainstorm Workbench features, I have a mantra: don’t promise the impossible.

Last month we designed our date and time system. My mantra came up again and again. A lot of APIs promise the impossible.

TL;DR when you’re programming with dates and times, store data in two formats:

  • “Timestamp” or “Instant”: a moment on Earth. Almost everyone should use UTC (Coordinated Universal Time) — not in a timezone.
  • “Date” or “Calendar date”: a wishy-washy concept. We read dates in news articles and publish dates in annual reports. …

Python, C++, Ruby and Java all use exceptions. To them, “exception” means, “nifty piece of syntax kinda like goto.” Language specifications and communities haven’t defined “exception” in a way humans can understand.

It’s the only incomprehensible term out there. Anybody who’s programmed for five hours can explain “if” to a human. Same goes for “else”, “while” and “for”. Deeper concepts like “function” and “class” can be clarified, too. Humans can even grasp flawed terms — like, “int” meaning “32-bit signed integer” and not “integer”.

But “exception” is completely incomprehensible. Ask ten beginners and ten experts to define “exception” to a…

Errors are the universal language of programming. Make them count.

A well-designed error helps fix bugs

The other day, I saw this server error in my inbox:

Traceback (most recent call last):
File "/usr/local/lib/python3.8/asyncio/events.py", line 81, in _run
self._context.run(self._callback, *self._args)
File "/usr/local/lib/python3.8/site-packages/aiormq/base.py", line 115, in <lambda>
future.add_done_callback(lambda x: x.exception())
asyncio.exceptions.CancelledError

… and the service stalled. I had to restart it manually. There was no error message at all.

This is unacceptable.

I wrote a new library, carehare, to replace aiormq. Then I saw this new error:

Error during render of workflow [REDACTED]
Traceback (most recent call last):
...
carehare._exceptions.ConnectionClosedByServer: …

This is the third and final post in a series. In Chapter 1, we sandboxed using subprocesses. In Chapter 2, we leveraged Linux’s clone() system call to create subprocesses quickly.

Workbench’s Renderer process runs one Step process after another. We sandbox each (untrusted) Step by running it as a non-root user, to deny it access to Renderer’s wealth of passwords and users data.

Most of the time, this will protect our users’ data. But not always.

Every so often, someone finds a Linux-kernel “privilege escalation” bug. …

This post, second in a series, offers a Python solution to a Python problem. The broad principles should apply to any single-threaded language on Linux.

In Chapter 1, we began sandboxing. Workbench’s “Renderer” runs a series of Pandas-powered “Steps”. We give each Step a new process, so Steps can’t control Renderer or other Steps.

Workbench Steps’ environment — Python, Pandas, Numpy, Pyarrow — takes 1–2 seconds to start. But Renderer needs to launch several Steps per second, per CPU. We must optimize.

It costs 1–2 seconds between when Renderer calls subprocess.Popen() and when Step sandboxes itself. Importing Pandas, Numpy and Pyarrow takes too long.

We can’t “recycle” Step processes after they run a Step’s untrusted code. A “bad” Step could, say, rewrite…

Workbench lets users drag and drop “Steps” to create programs we call “Workflows.” It’s like a user-friendly Jupyter.

When a user submits a Step, our “Renderer” program executes all the Steps in the Workflow. Most steps are pre-built; but users may code their own using Python and Pandas.

The dilemma: how do we safely run untrusted code in our Renderer?

Our Renderer accesses our database and file store to do its job. And it runs Steps … but Steps must never gain that power.

Other web services run users’ code — such as Travis, Jupyter and Heroku. They allocate a…

When we describe code, we tend to use confusing words. Re-think your language with this simple guide.

These quick tips apply to README files, code comments, API documentation, reports, research papers, websites, elevator pitches and water-cooler conversations.

“Automatically” means “without human control.” Who is responsible for what the code does, then? Clarify and nix “automatic.” Instead of “the program places an order automatically,” say: “this function places an order via the FooBar API.”

“Manually” means “using hands.” Whose hands? Clarify and nix “manually.” Instead of a code comment like, “this will require manually sorting the list,” say: “the end user…

The first — and hopefully last — experience your user has with your news story is on social networks. I’ll describe a neat trick for sharing a single web page on social networks in several ways or at several times.

Primer: the share card

Virtually all news sites get one thing right: they create a “share card” per story. A share card has an image, a headline and a description. Here’s an example on Twitter:

Social networks display share cards by fetching the web page and rendering its HTML <meta> tags. Each web page has one share card.

What if I want to share my page in several ways?

Sometimes, it’s hard to settle…

Grunt, Gulp, Browserify, Webpack — they all make the same rookie mistake.

The task is “minifying”: transforming many small-but-verbose JavaScript files (coders maintain these) and into a few large-but-terse JavaScript files that do the same thing (browsers download these).

All the JavaScript bundlers I’ve seen do it wrong. Here’s what they do:

  1. Read the many small files
  2. Lump them into a few big files
  3. Minify the big files

There are two problems. First, the minify step gets slower and slower when you add more code. Second, the minify results can’t be cached.

Adding Code Compounds Minify Wait Times

Here’s how a minifier works:

  1. It parses a…

Everybody’s doing it wrong. Use this file format.

Ever hear of a “static website?” They’re the Next Big Thing in website hosting — and a return to yesteryear. Unlike today’s normal hosting companies, static-site hosting companies don’t run any of your code. Economies of scale make your website crazy-fast and crazy-cheap.

Static websites can‘t write to a database on the server. No sign-in forms; no online shopping; no photo upload. With a bit of creative programming, a static site can handle just about anything else.

GitHub Pages, Jekyll, Middleman and Roots all generate static websites. …

Adam Hooper

Journalist, ex software engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store