October 30th, 2020

If I had to summarize what I do day-to-day, I'd say I build websites. Leaving aside the actual nuances of what that work requires, I suspect most people would hear that and form a similar mental picture: some text, some images and maybe some dynamic elements that pop up or move around all inside a browser window.

Though that seems simple enough, what I've had trouble articulating lately is regardless of what that website looks like on your screen, how those elements you see on screen were pulled together is anything but simple. Communicating about my work, is perhaps the most important part of my job and I worry about my team's standing when I can't articulate that effort clearly.

So, better to write out my thoughts now, in the hopes they'll crystallize into something I can speak to later.

You'll have to bear with me, the industry hasn't fully settled here, so while my thinking is in flux, I've decided to illustrate this new wild web world using the concept of "computation". You don't need a fancy degree to follow along, simply think of computation as an analogue for "where the work happens."

(Nb: I will be leaving aside the endless possibilities of frameworks, programming languages, server stacks, virtual environments, containerization, etc. Trying to understand how HTML, CSS and Javascript come together to form the page you're currently browsing is a marvel of technology, too much for the scope of a single article.)

Server-side Computation (on Arrival)

Most websites up to this point, have relied on a single server (i.e., "someone else's computer", not yours) doing all of the computation to pull a web page together. It receives the request, pulls data from a database, injects that into a template, and displays that on your screen. If the user logs in, that interaction is handled by the same server that displays the webpage; different functionality all computed on the same server. Complicated, sure, but not impenetrable to most people. You might come across this referred to as an "integrated" or "monolithic" approach.

Client-side Computation (on Arrival)

These days, data is increasingly being kept in different places, be it a third party service, or different part of a database cluster, or some other strange arrangement. How then does that data end up on a web page? Most of the computation is still handled by the server (i.e., the place where your web page lives) but your visitor's browser can go ahead and fetch additional data when they arrive via a Javascript request.

See what happened there? Where previously you needed a powerful server to do all the heavy lifting, now you've split the computation among the server, the visitor's computer and browser (also referred to as a "Client"), and a third party server. The split of the computation depends on the architecture of the web page, many rely heavily on the server for computation because it is likely the most powerful, but some developers opt to minimize server work and put more computation onto the Client. (The downside to the latter is there are no guarantees that a visitor's browser is capable of enough computation to deliver a good experience: think older phones, lower tier models, or spotty connections.)

Computation Before Arrival

I did mention there was another way to split that computational whole: you could fetch all of the data (the server templates and third party data) before a visitor even reaches your site. Now, a tiny amount of compute is done at our third party's server, then almost all of the compute happens on a developer's machine or a "build server". All of the work that would have been done by the original server and the browser, is squeezed together before the visitor arrives at your site.

Why? Well, this way we save requests going out across the network to fetch new data and we save the Client from having to do much work. The pay off for doing all the compute ahead of time is speed. Simply put, you can't trust everyone to have a fast network, a fast browser and certainly not both together all of the time. The page works exactly like one I would have put together 15 years ago by hand: static and beautiful HTML, CSS and Javascript. You may come across this growing movement as the "JAMStack".

Drawbacks? Well, remember that example about a user logging in from before? Pretty hard to do when you don't have any access to a database to look up whether a user exists or that their password matches. Remember this page is already built, it has no ability to include logic or dynamic functions on its own. The limitations of putting all of the computation before the user visits in this second example versus computation happening before-and-during a user's visit is pretty stark: a static web page cannot have dynamic functions on its own, at least not without some clever hacks.

I'll warn you now, this is where things start to get mind-bending.

Computation at the Edge (Between Arrivals?)

Companies like AWS, Netlify and Cloudflare, on the forefront of this movement to split up computation have worked very hard to build massive distribution networks. In essence, scores of simple but oh-so-fast servers all over the planet. These servers aren't as complicated as the server setup to host your WordPress site, they really only do HTML and client-side assets, including Javascript. But, these servers live in every major city center across the world, so they're physically closer to your visitors and the economies of scale wielded by these larger companies mean that these machines are way more powerful and way better networked than anything you could achieve yourself.

So you serve a website that takes all of the computation and handles it at build time, well before your visitors can even see the site, and then spreads these pages far and wide across the distribution network. Dynamic functionality can be added on using javascript in the visitors browser, like before... though that brings back the original problem we meant to solve: slow networks and slow browsers. Uh-oh.[^initial]

[^initial]: Statically built web pages do make the first load of these pages quicker and ensure there's something for Google's search indexing algorithm to crawl over, so it's not as if there are zero benefits. If you have read to the end or are a close reader and have figured out my final conceit, do know that staging dynamic vs. static build processes as a binary was intentional for dramatic effect.

The geniuses behind these distribution networks thought of something very clever since they had all of this server power "lying around": what if they allowed developers to write simple and restricted functions (mostly in javascript, but just about any language will fly these days) that can be run not when the user lands on the page, but just as they signal where they mean to go? Now a person clicks on a link and before they finish the journey to the next page, computation can occur.

via GIPHY

Let me make a bad visual/pop-cultural analogy to help illustrate: remember the infamous scene from the Matrix, where the camera "slows" down to show Neo dodging bullets? When a gun is fired, the bullet travels so fast it's intuitive to assume that it effectively hits its target instantaneously. What the slow motion reveals in the file is that there is plenty of time and space between to do work between the firing of a (cgi!) gun and it reaching its target... if you're as fast as Neo. Think of these edge servers as just that: more powerful and faster than you could conceive, enough to squeeze in an opportunity to perform a bit of computation immediately after your visitor has made their request and before that web page has returned. They're so fast they can add information, fetch data, spit out templates and so on to any page in single-digit-milliseconds!

If you're clever and have a specific use case dreamed up, you can have a reasonably durable website, that's wicked fast, has little to no operations cost (e.g., no load balancers, database caching, etc.) and should theoretically scale in a fashion that doesn't leave your IT team in cold sweats. I've seen examples of edge functions grab the visitor's rough location and use it to serve a statically built web page with localized to that language instead of the default. This is one example, imagine authorizing users and serving different content, splitting visitors for A/B testing, or something I have yet to imagine.

You Were Right, Building Websites Did Get Complicated

To recap, we have server-side computation on arrival, computation in the client (read: browser), computation ahead of time in the form of static sites pulling data from various APIs then building the page and now computation at the "edge".

A Skeptic wouldn't be far off asking how many types of websites or apps can have their computation broken up into chunks like this? Shouldn't the developer community stick to what's worked for 20 years? And honestly, the answer to both remains to be seen. Content-only websites and landing pages are a perfect fit, or an eCommerce site where content is mostly static and payment processing is handled by a third party, say Stripe, is another good use case. However, an app that processes large swaths of real-time data? No chance and anything between those use cases would be tough to provide a definitive answer.

Now try explaining to a non-developer that where my straw-man skeptic falls apart is the assumption that you would only choose one of these pathways, rather than choosing some/all of them depending upon the need.

Luckily for us, the user/client never really needs to know what it took to get their site or app to their screen. However, communicating about our work is a developer problem. Communicating how a site was constructed, what those advantages are (or what disadvantages these choices minimize) and how that provides value to the client or customer is incredibly important to successful work. Being a successful developer is hard enough writing code that meets standards, budget and time allotments, let alone when you have trouble enough speaking about what it is that your team delivered in the first place.

August 23rd, 2020

If you're anything like me, you're going to mess things up. Not all the time, of course. But it's inevitable, we can't be perfect. (I'd contend that being perfect isn't a worthy goal, but that's a topic for another day.)

When you find yourself taking a loss, what do you do? How do you make the most of the discomfort? I have a rough plan for dealing with failure and coming out the other side a little wiser and hopefully, a little better for next time.


First, remember failure is a diagnostic state, or an opportunity to look around and take stock. Chances are your actions were largely correct, but you missed some key detail. Take the time to figure out what it was: an unclear goal, a lack of resources, or poor timing. The clearer you are about what didn't meet your expectations the better. It is easier to plan your journey if you know exactly where you are now and where you are headed next.

Second, honesty is your friend, even brutally so. If you didn't put in your best effort, or give your project the attention it needed, then say so, especially if you didn't want to face the fact. This point links very closely with the first, but the key here is that honesty should not involve any judgement to color the fact. Not achieving your goal on your first (or hundredth) run through does not mean that you're a loser or you deserve this result. That my friend is too too far. Park your judgments, and forgive yourself a little. All learning is difficult, otherwise you'd know everything already.

You might feel low at this point, remember why you started. Was it to stretch yourself? To hit a new project milestone? To earn more this next quarter? Or build the esteem of those you care for? Those motivations and positive emotions are still there, so ignore everything else and focus on whatever it takes to get you to the finish.

The time is finally here, you've been following the shape of the valley, had a hard look around at what happened, reached the nadir when you reflected honestly about where you are and what you need, now you're ready to rise: it's time to follow through. A new iteration on your last plan, one that's more clear about what's needed and where your headed rises from the ashes. Because, what point is there dealing with the uncertainty, discomfort and brutal honesty if you're not going to put together a new plan and execute? You are almost there, hold steadfast.

Building something, learning a new craft and any other form of self extension is going to be messy at times. Remember that you are tough and you are capable. Ride the valley and follow through as many times as it takes. Your victory is only a few miss-steps away.

Share your methods for resilience.

July 14th, 2020

It’s been a strange week: turbulent, disruptive and exciting all mixed into one. (Honestly, the best word to characterize this week would be whiplash.) To meet the challenge, I have had to get something out of the way first. I needed to square away who I am as a professional.

My personal self image has been reasonably consistent, but I have never managed to nail down a narrative to explain myself in my career; perhaps, it’s because I have jumped between continents, then between fields (and back... and back again), all factors which obfuscate my sense of professional self. Not being certain about who I am, has made it difficult to adapt. Imagine the difficulty in planning a journey, when you’re not sure where you’re starting from...

For whatever reason, the challenge of this week have given me the clearest glimpse of what I want to be in some time. So, I‘m taking this as an opportunity to work hard and nail that identity down. Introspection can be scary stuff--you are likely going to face some uncomfortable truths before you get through the process--yet making the leap has clarified what was uncomfortably fuzzy about my direction.

(Drum roll please...)

In short: I am/will be known as a person who strives to, “Raise the floor.”

It’s a phrase I heard often in the inner-city school I taught at in London, England. The idea is pretty simple: the community around the school was vibrant and beautiful, they wanted nothing more than for their children to experience success, but those wishes were wrapped in reality: most experienced poverty, transiency and other significant challenges that got in the way of any meaningful success in school and out.

As an educator serving this community, my duty was to raise the floor of attainment and success for all. (I simultaneously was tasked to push the attainment “ceiling” for that same group, for those wondering.) That meant digging deep, working with my entire team, parents, community partners and the students themselves, to push (uncomfortably at times) to change their pessimistic mindset, one that shied away from difficulty because success wasn’t part of their lived-experience, and into a hunger for the next opportunity to realize success. Everyone had to lift themselves up. If the goal was to have each student reach for bigger risks on more difficult problems, they couldn’t be worried about how far they might fall. My job was to provide the supports to get that momentum going and the skills and habits necessary to sustain their momentum independently.

In the last couple of years, the world twisted a bit beneath my feet, so I no longer find myself in the classroom. What then does “raising the floor” mean for a team leader and developer? I am fully committed to raising expectations and to refine and improve the quality on work that everyone else has already moved on from. That might be through attention to the product itself, refactoring, realigning, etc., or engaging with the culture that empowers those decisions to build a better product. I will push the bounds on what the team considers “shippable” in the time budget we have, always striving for more accessible, performant, collaborative and ultimately better products.

When I join a project, I’m at peace with the fact that I do not shine brightest when working on the “latest and greatest.” I am not motivated by prestige, money or even building things that are unique. No, I get up in the morning looking towards a chance to lean-in to hard problems. Typically those problems are cultural, or people-based, and not sitting inside my text editor (Neovim in case you care 😘). Tackling those problems bring me the greatest contentment, because the first step to creating great work is fostering an environment where the team is empowered to reach after greatness and not worried about the potential fall.


I’ve met countless other styles of people in my professional career, but never anyone with the same priorities and values as me. Perhaps, that is why I haven’t been confident in coming to this conclusion earlier, or maybe there is some kernel of wisdom that I hadn’t realized until recently. Whatever the reason, I’m ready to face what the world has in store for me: ready to adapt or hold steadfast, starting from my current understanding of who I am.

Are you on a similar journey? Tell me about where you landed, about who you are or who you‘re becoming.

Start the conversation.

July 3rd, 2020

All great things have to start somewhere. Well I should clarify: all things, good, bad and mediocre, have to start somewhere. So why not here? Why not now?

No project, whether it’s a novel, a portrait, or an application, ever greets the world fully formed. Every book started with its first draft, every portrait its first brush strokes and believe me, every piece of code has been refactored (or ought to have been if quality was a core company value) before it landed behind the comfort of your screen. Don’t fret about your masterwork before it’s even seen the light; you’re not waiting until it’s perfect, instead you are killing your momentum and reducing the likelihood that your passion will ever make it public.

If you tag in or around business and technology circles, you may have heard about releasing an MVP (minimum viable product), or about “shipping early and often.” It may even be advice you agree with, sending a project out with the minimum level of functionality to test for market fit, and improve iteratively over time. Missing from those discussions is, perhaps, the real reason you and I refrain from shipping: it’s painful.

  • It’s painful to miss the mark.

  • It’s painful to receive feedback.

  • It’s painful hurts to attach your name to work that you’re not satisfied with.

If you see yourself in those words, I am right there with you; I’d bet most of the world is or has felt those exact same feelings. There’s a beauty in shared experience, but more so in the realisation that every success you see around you started in the same place, with those same worries.

So take the leap. Build something nearly invisible into something mighty. Just remember, it all happens one step at a time.

To quote a tongue-in-cheek phrase from Merlin Mann:

“Sometimes, taking the first step is the first step.”