To me, minimalism in software development is not just a desirable design goal but a survival strategy. I’ve seen too many projects fail, many I’ve been involved in myself, due to an explosion of features and a complex technical foundation that stands on shaky ground but was just too tempting to start with.
After spending 10 years creating open-source editing solutions for scientific publishers, I set out to build a minimalist writing platform designed for knowledge exchange between individuals.
In this text, I’d like to reflect on the choices I’ve made in my design and implementation, facing the challenges of limited time, resources, and money.
In a perfect world, you could separate design and execution. But the reality is messy. I tried not to compromise on user needs but had to be very conscious about every design decision’s implication on the software architecture. Any complexity that it could cause would need to be anticipated. Usually, there are shortcuts, but it’s a highly creative act to spot them. In most teams, design decisions are made without too much technical consideration. I’m all in support of ensuring that technical concepts don’t ‘smell through’ into the user interface, but it’s not black and white. In the past, I’ve too often paid an expensive execution penalty for a perfectly valid design decision while not being aware of its technical consequences.
More than ever, it is tempting to go the quick and easy way. There are too many shiny things out there that promise you to build your product at the snap of a finger. There are frontend and backend frameworks of all kinds, APIs for almost every possible problem, and one of the most dangerous seductions: Object Relational Mappers.
Generally, nothing is wrong with using opinionated abstractions to build prototypes and test ideas. But if I’d do it, I’d plan to throw it all away once the MVP has proven to work and the general product design has been fleshed out.
Then I’d sit down to design the most minimal, least resource-consuming technical architecture to get the job done.
When you view a page on the platform, what happens behind the scene is a page requesting data from an API endpoint, usually a 5-liner function, that sends one query to a hand-crafted SQL-View, living in Postgres.
Why write plain SQL?
Because it is the best tool to access and manipulate data fast. I think it’s worth learning and mastering. In many cases (especially in early development phases) when I set up a caching layer to speed things up, what I should actually do is optimize that SQL query that is becoming slow. I’ve found that attacking the root of the issue becomes really rewarding in the long term, while covering up the problem, like with caching, will leave you with a lot of edge cases and possibly unpredictable behavior.
What’s important to me is that I build on top of reliable open-source technology that does not lock me in. The fewer software components I need to include the less fragile my system will become. My platform can run on any system that runs Node.js, Postgres, and an S3-compatible storage endpoint. The only exception is the image processing service I’m using. Here I’m relying on a proprietary API, but hope I can remove that dependency soon.
While I’m a big proponent of being close to the metal in code, the reality looks different to me when it comes to hosting infrastructure. I’m not a DevOps person, and neither running my own hardware nor managing Kubernetes myself would give me a good sleep. I’m very grateful that Zero-DevOps solutions exist. They enable me to run a venture like mine. What’s important though is that I really need to be conservative with my technology choices. A standard no-thrills Postgres instance without any special configuration will be easy to host on those platforms, which save me a lot of time and headaches.
Having a minimal tech stack also extremely lowers the maintenance costs. That’s important for me because I’ll likely do some intensive consultancy work while maintaining my writing service at the same time. The main reason why I dropped the optional paywall (you could put a price on individual articles), was that it would just cost me many hours every week to sort out invoices, do customer support, etc. For now, my time is better spent serving a more important need: My writers’ desire to express themselves.
I’m taking a minimalist approach to security as well:
“They can’t steal from me what I don’t have.”
For that reason, I’m essentially only storing things that will be visible on the website anyways. Direct messages between two users are realized via an email handshake. There is zero tracking in place, so I lose insights into my users’ behavior. What I win in return is not having to guard any of that sensible data. And possibly trust?
What a nice read Michael! Thanks for sharing. I’m honestly a little bit on the other side of the spectrum on this. I started to believe that if you really own the products and platforms you bring in your infrastructure, you should bring them in. If you are aknowledgeable enough to start a project on k8s, why not?
Didn’t want to include my current framework preferences in the piece itself, but for those who are interested: I'm currently using Next.js with a postgres connector (pg-promise). Most of my pages are really dumb with some very basic interactivity. When the state in DB has changed, I usually fetch the updated data as a whole and replace the entire page (or large portions of it). I prefer to optimize API endpoints and DB queries before considering switching to partial UI updates. I have one piece that is highly interactive though, which is the rich text editor component, used to compose documents, comments, and messages. I'm considering switching to Svelte at some point, as it is close to the metal and would fit for my dumb-pages as well as the interactive editor parts. I don't want to end up using two different frontend frameworks. Generally, I try to keep my codebase so small, I'd not be afraid of rewriting it completely within a couple of weeks. It's one of the biggest dangers on the…
Danke für einen weiteren Einblick, Michael! Mich hast du vom less-is-more-Prinzip bereits überzeugt. :) Bin schon gespannt auf deine nächsten Artikel!
On Ken, we're trying to figure out how the world works — through written conversations with depth and substance.