Sep 03, 2023

Looking back on a decade in software engineering

I can’t say for sure whether it was late 2012 or early 2013 but around that time I probably wrote my first, very scrappy, lines of code. Back then it didn’t dawn on me that I was about to embark on a career path that would open up so many experiences down the road, I just wanted to build some extensions to a popular Java-based video game (ten points if you can guess it) I routinely played with my friends at the time.

Ever since, I’ve been working on projects, building products, working for startups, building my own, and collecting a huge catalog of experience along the way. 2023 is about ten years since I started programming, and I wanted to look back on what I spent my time working on in the past decade to see what influenced my mental models up to this point. This also shows that whatever happens from now on is not an overnight success but ten years of hard work and late hours leading up to that overnight success.

I apologize in advance for the poor choice of project names. Naming, as you know, is the hardest part of software engineering (on the same complexity level as caching, maybe harder).

It’s easy to retroactively come to conclusions about my knowledge or mental models at any point in time, and the fact that I worked on most projects over multiple months, often overlapping multiple projects adds more complexity to understanding the chain of events, so please view the list as a very rough outline rather than ground truth.

Early days

Unfortunately, I wasn’t aware of versioning and source control in my first years of building software, so most records are either archived on some old hard drive or lost to time. Because of this, I can only try to recall what I did from 2012 to 2015, the year I started using GitHub more frequently. As I wrote above, my first projects were all about extending Minecraft with plugins for all sorts of fun little extras. I probably tried to put together a few badly designed websites as well, but I mostly used pre-built templates that I adjusted. Still very much a script kiddie, but everyone has to start somewhere.

I mostly learned by building small projects, and trying to rebuild other tools I was using or infrastructure I wanted to understand better. For better or for worse, you can almost always trace my early projects back to some trend that was going on at the time.

Around 2015, I figured I wanted to build some mobile applications. Because of my previous Java experience, I decided to build apps for the Android ecosystem. With some luck, you may be able to find some old app builds (.apk files) floating around the ether uploaded by a third party, but I kindly ask you to spare your time and eyesight and not dig deeper.

For some apps, I had to build some sort of backend, which was when I first made contact with PHP. Times were different back then, the LAMP stack was all the rage, and deploying a web app meant uploading files through FTP. It was like the Wild West out there.

PHP was my entry into web development and I quickly learned what SQL injections were and why we need prepared statements. When I first got to know my good friend Tim in the summer of 2016, he was building a series rating website (presumably using C#/ASP.NET), and I was inspired to build my first bigger project.

upstream (June 2016) ⭐️

Tech stack: PHP, MySQL, Node.js, Socket.io, jQuery

Concepts: Web applications, frontend/backend split

The original idea for upstream was a collaborative music player based on YouTube, similar to plug.dj. While the first version was more of a demo to see if I could properly embed and control YouTube videos, in later iterations, I added some basic streaming back-end where users could vote for the next track and sync playback using Socket.io running on Node.js.


In addition to creating some super basic websites, I also played around with frameworks like Electron and Cordova to bring those apps back to the desktop to avoid learning proper frameworks and languages for native application development, which I would later pick up.

Moving into web development

From my first bigger web applications in 2016, I kept diving into JavaScript, Node.js, and web service architecture. I started using TypeScript in late 2016, and I gradually phased out usage of JavaScript (or even worse, CoffeeScript).

serve (May 2017)

Tech stack: Node.js, JavaScript, Docker

Concepts: Static file serving, dynamic extensions, containers

To host my portfolio, I started using a simple static site middleware in Express.js but gradually added more features, which became my first naive webserver implementation. I had to update it lots of times to support basic features like compression and content-length/range support.

Interestingly, I added an extension system that would allow to write JavaScript-based route handling for adding APIs and other functionality right into the webserver. This might have been based on my previous exposure to the configuration format of nginx.

Of course, I made all possible mistakes like opening up the webserver to path traversal attacks (who knew that exposing the entire file system would be a bad idea, right?), which helped me learn in the end.

After traversing the commit logs, I found one of the earliest usages of Docker in May 2017. It doesn’t look like I fully used it back then, but I had definitely made contact with the idea at that point.

github-deploy (June 2017)

Tech stack: Node.js

Concepts: Webhooks, HMACs

To avoid uploading new versions via FTP, I started trying out different ways to get my code to run on the final VM instance. With github-deploy, I attempted to download, untar, and run the codebase from GitHub when I received a push event webhook from GitHub. This was the first idea to have fresh code running on the deployment machine, and definitely not the last. To integrate GitHub webhooks, I had to understand the concept of HMACs for message integrity and authentication.


From the first projects onward, I wanted to build more applications around the web. In the summer of 2017, I landed my first internship position at a digital agency in Frankfurt. My first tasks weren’t strictly on web development, though.

Moistermeister (July 2017)

Tech stack: Arduino, JavaScript

Concepts: APIs, microcontrollers

We had lots of plants in the office and the team just received their first shipment of ESP8266 boards, low-cost microcontrollers with WiFi connectivity. I used a humidity sensor to track the moisture levels in the soil and hosted a small dashboard page through the microcontroller that would periodically fetch the latest readings and plot them in a chart.

Project Work for BMW (July 2017) ⭐️

Tech stack: React, MQTT, mosquitto, Rails, capistrano

Concepts: Single-page application (SPA), PubSub

While I’m probably not allowed to share the details, we worked on a client-rendered React application (SPA) for BMW at the time. All updates were announced through PubSub (MQTT) and then pulled over the air because we needed a low-overhead transport mechanism in the deployment area. This was the first proper React project I worked on, and I had to pick up some other tools in the team’s stack such as Rails with rake tasks and Rubygems and capistrano for some deployment flow.


After interning in the summer, I was hooked on React and JavaScript, and I kept building more projects with Node.js and React, departing from the LAMP stack (one of the best decisions I made and a big step in becoming a better developer, for sure).

nexus (July 2017)

Tech stack: Node.js, JavaScript

Concepts: Task workers, HMACs

I can’t remember the context around this project but it was probably connected to me running a couple of low-cost VMs in the cloud and wanting to abstract away the busy work of running scripts or deployments via SSH. For this, I built nexus, a distributed task worker system where nodes could periodically ping a central instance for new tasks and report status updates. When working on github-deploy previously, I saw how other platforms like GitHub handled integrity checks using HMACs so I added those for the communication between node and core instances.

Records show that I knew about Docker at that time, but this was probably my first and most simplistic attempt to re-create something like Kubernetes.


In between bigger projects, I usually worked on small PoCs and experiments like building my own webserver hosting my portfolio (and JavaScript extensions for hosting the portfolio API) or JSON database in Node.js, trying out Next.js for the first time, and so on. Sometimes, I repurposed old projects like upstream with a newer tech stack like adding TypeScript to the mix.

I first started hosting my workloads on simple DigitalOcean droplets using script runners like forever to keep processes running in the background, and using HAProxy and later nginx for reverse proxying incoming requests to the respective webserver or backend.

Node.js best practices (Winter 2017)

Repository: Node.js best practices

To add some context, I believe that around 2015-2018, the hype around Node.js peaked, leading to the high adoption we’re used to nowadays. When I was learning the basics of Node.js, I looked up lots of blog posts and resources in the ecosystem and found the Node.js best practices project. Back then, most popular frameworks had these community-built collections of knowledge and best practices, and I knew I wanted to help out and make this the best available resource for new people getting into Node.js. This was mostly editing existing content around code quality (using async/await over raw Promises, error handling, graceful exits, using loggers, etc.).

meridian (Spring 2018)

Tech stack: Node.js, TypeScript, React, Next.js, GraphQL, express, JWTs, MongoDB

Concepts: .env files, NoSQL databases, WebSockets

After continuing to learn through the fall of 2017, in early 2018 I had to hand in a project using databases in my high school computer science class. After spending lots of time working with MySQL, something happened and I tried out MongoDB.

I chose to re-create the nexus project using TypeScript and a MongoDB as a persistent data store. I also swapped the HTTP-based node-core communication flow for WebSockets and added real-time status updates for dashboard users.

Between nexus and meridian, code quality improved vastly. I wrote more comments, and documented functions that were more descriptive already thanks to TypeScript, and the project was more structured as well. I also added more layers of abstraction using interfaces, extension mechanisms through plugins, and extensibility using environment variables and files.

The frontend was built using React with Next.js, TypeScript, and a customized version of Bootstrap for SASS-based styling.

In a subsequent iteration, I gradually replaced the RESTful API with GraphQL after landing my job at GraphCMS. From the commit logs, this wasn’t an all-at-once move but took place over several weeks.

So this was my second attempt at rebuilding Kubernetes. I still didn’t use Docker for this project.

RecipeDB (June 2018)

Tech stack: Node.js, Docker, TypeScript, TypeORM, JWTs, InfluxDB

Concepts: Time-series metrics, service quotas

A couple of friends were working on a CS project for creating and storing recipes, and I offered to help with the backend. I simply used all the tools and knowledge I had gathered up to that point and built a RESTful Node.js application backed by MySQL and InfluxDB for metrics, containerized with Docker, and deployed using docker-compose.

Joining Hygraph

After completing the internship, I knew that I wanted to stay in tech and become a better engineer. I kept looking for jobs and in May 2018, I sent a mail to Michael from Hygraph (known as GraphCMS back then) and got an answer offering an interview a couple of days later. In June 2018, I joined the small Hygraph team of 5 people as a frontend developer while finishing high school.

Working on the frontend (June 2018) ⭐️

Tech stack: React, Emotion/styled components, GraphQL, TypeScript

Concepts: higher-order components, form rendering/validation

I started working on the frontend and submitting small improvements here and there, soaking up all the knowledge from working together with Jonas and Daniel in the office. I learned about GraphQL and features like fragments and schema stitching, as well as how production React applications were usually built. We were heavy on providing a good editing experience, so form states, validation, and error handling were important to get right.

Understanding the backend (Winter 2018) ⭐️

Tech stack: GraphQL, Apollo Server, Prisma (v1), Google Cloud, Kubernetes, Docker, PostgreSQL, CircleCI

Concepts: Schema stitching, event streams, orchestration

While building frontend features, I inevitably got to work with the backend as well, understanding our legacy architecture (which was already the second infrastructure iteration) based on Prisma for managing schema migrations on managed PostgreSQL databases. The infrastructure was already showing growing pains, and I got to help with some mitigations like improved caching which briefly helped.

To recreate environments, we used a simple change event stream approach, which allowed us to record and replay all changes to a project to end up with the same final state. A big downside back then was that the larger event streams grew, the longer it took to replay an environment.

The deployment was managed using managed Kubernetes in Google Cloud, and we used Google Cloud PubSub for service-to-service communication. Through Kubernetes I learned about distributed tracing with Jaeger, traffic routing with Istio, and other K8s ecosystem components.

trident-configure (December 2018)

Tech stack: Docker, PostgreSQL, Kubernetes

Concepts: event stream, schema stitching

What started as a visual Kubernetes configuration interface became a platform for sharing cloud configurations. While the final product never saw the light of day, I used lots of my learnings from Hygraph like adding integration tests, using GraphQL APIs connected to PostgreSQL, schema stitching to combine multiple services, an event stream for persisting changes and potentially allowing to recreate databases, and more.

Starting to blog

Rebuilding the portfolio (December 2018) ⭐️

Tech stack: Gatsby, TypeScript, GraphQL

Around the end of 2018, I already felt like I had learned so much in a short time frame that I needed to write things down. I rebuilt my portfolio using Gatsby (because they were based on GraphQL) and started writing regular posts.

I used remark to process Markdown and have kept a similar flow ever since.


With the new portfolio in place, sharing knowledge and tracking projects was easier than ever.

compose-deploy (February 2019)

Tech stack: Node.js, TypeScript, Docker, SSH

Concepts: Copying compose file for deployment

Moving on from manually pulling changes on the remote after building and pushing the image, I worked on compose-deploy, a simple CLI tool to build and push all docker compose images, copy the compose file to the remote host using SFTP, and restart the services using the new file. This made deployments a lot easier but occasionally ran into problems like orphaned containers.


After I graduated high school in May 2019, I decided to join Hygraph full-time, transitioning primarily to backend work. At first, this meant servicing the existing infrastructure and adding safeguards to keep the lights on but we increasingly ran into issues and decided to rebuild the Hygraph infrastructure from the ground up starting in Summer 2019.

Hygraph infrastructure rewrite (Fall 2019) ⭐️

Tech stack: Go, PostgreSQL, GraphQL, AWS SQS, AWS RDS, AWS ECS, Pulumi, GitHub Actions

Concepts: ASTs, complex SQL queries, infrastructure-as-code

While I can’t expose our secret formula, we made some pretty major infrastructure changes, including switching away from Prisma for GraphQL/database schema migrations to hosting and migrating our own databases internally and switching away from managed Kubernetes on Google Cloud to AWS ECS on AWS Fargate. We also switched our content serving layer from Node.js to Go. All I can say about the internals is that we used very complex and advanced PostgreSQL features for the heavy lifting and worked a lot on the AST level of GraphQL, which was extremely interesting for me to learn since I didn’t have a formal CS background.

Dividing the rewrite work between Jonas, Daniel, and myself, I chose to build the complete mutation layer, with every content modification flowing through my code (again, for better or for worse). I also helped with the management component and schema migrations, as well as versioning, webhooks, scheduled publishing, sortable relations, polymorphic relations, RichText, and other parts.

Throughout the whole journey of trying to keep the legacy system running, we learned a lot about the importance of service quotas and setting limits, informed by benchmarks and stress tests. We always had a hard time when customers would go crazy and build huge content schemas or send millions of requests in a short time frame, so we added service quotas and rate limits right into the new architecture.

We thought about the best way to deploy the new system early on, as we knew we’d have to spin up multiple regions and dedicated customer deployments, so reproducibility was very important. While we previously configured Google Cloud manually, we decided to adopt Pulumi as our infrastructure-as-code foundation to model our infrastructure on (we chose Pulumi over Terraform because we knew how to write Go and nobody understood HCL, a good choice).

Distributed GraphQL edge cache (October 2019) ⭐️

Tech stack: Cloudflare Workers, GraphQL

Concepts: Edge computing, ASTs

While we were working hard on the new infrastructure, we had to service the increasingly unstable legacy infrastructure, which took a lot of time while degraded performance frustrated our customers. We fixed some memory leaks in the previous API gateway but quickly realized that we’d have to buy some time until we could confidently launch the new infrastructure into production the following Spring.

Together with Markus, a true hacker we’d gotten to help us out on infrastructure topics, we built a new caching layer at the edge powered by Cloudflare Workers, decreasing access times to cached content down to tens of milliseconds. This was the first time we were building a multi-layered caching architecture and while the original components are no longer in place, the knowledge has lived on and strongly influenced subsequent architecture decisions.

helferlein (December 2019)

Tech stack: Go, Git

Concepts: CI/CD

In another iteration of my personal deployment flow, I created helferlein, a small CLI tool that could be deployed to a server and continuously pull new changes, running commands to restart services when changes were found.

Working on bigger projects

When the pandemic hit in 2020, Hygraph went remote, I started studying in the fall of 2020, and I built a couple of projects myself at first.

Pulse (Spring 2020)

Tech stack: AWS Lambda, AWS SES, GraphQL, PostgreSQL, Go, TypeScript, React, Apollo, xstate

Concepts: OAuth applications, CI/CD flows

From building multiple iterations of the unit and integration testing harness at Hygraph, I remember the pain of monitoring test runs before we switched to GitHub Actions for everything. With Pulse, I wanted to perform and monitor test runs.

Tuple (Winter 2020)

Tech stack: SwiftUI, Node.js, TypeScript, GraphQL

Concepts: iOS native mobile application development, declarative UI rendering

Like every software engineer, I had my short social network phase and tried to build an app to plan and join spontaneous events around university life. I used this as an excuse to teach myself SwiftUI and understand the Apple developer ecosystem, getting some valuable insights into other thought patterns on how to develop applications and developer tools.

Stapel (Winter 2020)

Tech stack: SwiftUI

Concepts: stack navigation with SwiftUI

For building a proper mobile application, I had to add stack-based navigation functionality to tuple and extracted this into a public library. This was an interesting exploration into the depths of SwiftUI state management and declarative rendering.

Working on bigger projects with Tim

While I kept building features and onboarding new engineers at Hygraph, I knew I wanted to build something together with Tim for a long time, and when he came around with an idea for a music-based social networking app, I jumped in.

sonata (Spring 2021) ⭐️

Tech stack: Node.js, TypeScript, GraphQL, AWS, Pulumi, Docker, Angular, NewRelic, Mixpanel, GitHub Actions

Concepts: OAuth applications, batch loading and caching, data normalization, matching and ranking algorithms, cron jobs

Tim and I had a blast building sonata, we moved the fastest we could and built new features every week underpinned by a robust architecture pulling in data from Spotify and Apple Music.

Our largest challenge was matching users based on their music preferences. For this, we normalized scores of their mutual favorite artists and genres and created match pairs based on distance. The intuition was that people listening to more mutual artists more frequently would be a better match. Combining multiple data sources (artists, genres) was important in case users weren’t particularly aligned. Next, we had to work around large joins by filtering down based on properties like country, connection status, and preferences as fast as possible.

We also had to make sure we could serve external data quickly and wouldn’t exceed rate limits so we added a batching and caching layer to deduplicate multiple data requests into fewer batch requests and cache responses at the same time.

cuteforms (Summer 2021) ⭐️

Tech stack: Docker, Pulumi, Node.js, TypeScript, Angular, GitHub Actions

Concepts: workflows, Single Sign-On (SSO)

Tim worked on a relatively simple headless form submission backend for some sites and applications he was building and I offered to turn his side project into a collaboration. We quickly added production features like service quotas, rate limits, Single Sign-On, and submission workflows for sending mail notifications for new submissions, among others. We also added RBAC, integrations to enable API access, audit logs, event processing, and mail templating functionality.

bricks (Summer 2021) ⭐️

Tech stack: TypeScript, Node.js, GraphQL, NewRelic, Dataloader, JWTs

Concepts: building blocks

Combining our previous work on sonata and cuteforms, we bundled up and reused functionality for building applications (data fetching, external notifications, worker patterns, event processing, service quotas, notifications) as well as B2B-specifics (SAML/SSO, SCIM, audit logs, RBAC, integrations) into a single library, bricks.

We split bricks into core and b2b modules, offering production-readiness basics for any application and B2B-specifics for cuteforms and other products, reducing the time to start working on and launching production-ready apps from weeks to hours.

WebSocketDebug (June 2021)

Tech stack: SwiftUI, WebSockets

Concepts: mobile application development

As I was working with WebSockets a fair bit, I wanted a simple debugging application, and thus I built WebSocketDebug, a simple SwiftUI-based app for connecting to WebSocket endpoints and logging messages. Pretty simple, and pretty helpful.

SyncRelay (August 2021)

Tech stack: Cloudflare Workers and Durable Objects (initially), Node.js, TypeScript, PostgreSQL, listen/notify, GraphQL, React, Tailwind

Concepts: Public SDKs, session backends, PubSub

When the hype of collaborative applications was peaking and everyone wanted presence features and live cursors, I built SyncRelay, a simple collaboration-as-a-service application that would allow developers to plug in a React and Node.js SDK into their stack and receive live events to add collaboration features in minutes.

graphql-sonar

Tech stack: GraphQL, TypeScript

Concepts: End-to-end testing

When building Hygraph, we often wondered about the best way to add tests on different levels. While we had unit tests in place, integration tests were quite slow and expensive, and we couldn’t capture the entire stack anyway (mocking the cloud component that might fail wasn’t helping in production). So we put in some work on end-to-end tests against the deployed production environment to catch critical bugs, and I built graphql-sonar to simplify writing assertions against typed APIs by using code generation.

workouts

Tech stack: MapKit, SwiftUI, HealthKit

Concepts: Map application

I always wanted to look up my recent cycling routes, so I built a small app to retrieve workout information from HealthKit and render the recorded routes on a map.

Anzu resource management (Winter 2021 - Summer 2022) 🌟

Tech Stack: TypeScript, Node.js, React, gRPC, Go, Protobuf, AWS, Cloudflare, NewRelic

Concepts: dependency graphs, infrastructure-as-code, code generation, ASTs, decoupling services, public SDKs

Anzu was by far the most architecturally complex project I worked on with Tim. We wanted to bring infrastructure-as-code to a broader audience by switching the presentation layer from code to a visual editor, and we decided to build the entire backend instead of building on top of Terraform or Pulumi. This meant that we had to build every step, from resource providers with dynamic resources and schemas to creating a dependency graph and execution plan to executing that plan in a managed worker by starting up the providers and communicating resource CRUD instructions via gRPC.

Because we planned to support a range of cloud providers from AWS, Azure, and Google Could as well as service providers like NewRelic and Cloudflare, we created a provider-based model where each service could encode the resources and their inputs/outputs in a schema, which would then be published to a shared registry. Users could set up resources and use provider-based or global functions to concatenate multiple inputs into a string, use outputs from other resources, and thus build a connected cloud resource graph.

The resource graph would then be diffed for changes by comparing current inputs with the status quo, creating a run plan to bring the system into the desired state by creating, updating, or deleting resources. Each deployment was run by a worker.

We built the workers using AWS Batch to start up as independent and isolated containers in a secure environment on Fargate and downloaded the required providers. We then started the workers which exposed a gRPC endpoint (configured through our provider SDK) and sent CRUD instructions this way.

To make the provider authoring experience as streamlined as possible, we would ask provider developers to write their configuration including resources with their inputs and outputs as JSON, and generate the language-specific code to serialize inputs and outputs properly. Providers could be written in any language that would support gRPC, decoupling from the Go-based worker service. This way, we transported and stored values in an AST form and “hydrated” them into language-specific data types like Strings at runtime, as well as serializing return values back into the AST representation using Go interfaces and code generation.

We also made sure provider binaries were uploaded to the registry in a working state by running the build pipeline including static code analysis using the Anzu CLI.

The biggest engineering challenge in building Anzu was handling untrusted code (the providers), running deployments and gracefully handling failures and retries (using idempotency keys), diffing the desired vs. current state without running provider code (using dependency tracking), and generating types and glue code to make building providers as easy as possible (using gRPC and our in-house AST format). While the product did not work out commercially, we ended up with a powerful architecture for serializing values, generating code bindings to these values, and tracking dependencies.

Anzu Codegen (Spring - Summer 2022) 🌟

Tech Stack: Go, gRPC, Protobuf

Concepts: code generation, ASTs

Once we had resource management in place, we wanted to make it easier to integrate the resources into applications. We started by abstracting services and allowing environment variables to be configured in the UI and pulled in at runtime using type-safe generated glue code.

We continued this work by extending the codegen functionality of the CLI with a sync feature: Every configured resource could define a service connector that would link cloud resources to services. This way, a managed database resource could expose the glue code for connecting and returning a well-defined database client data structure to the application. The CLI simply fetched all service connectors and wired them up correctly.

Anzu Platform (Summer 2022) 🌟

Tech Stack: Go, Cloudflare, AWS

Concepts: dev environments, managed resources

To make the dev experience even better, we introduced dev environments, ephemeral infrastructure deployments with variants of production resources (smaller databases, no code deployments to run services locally, etc.). This way, developers could quickly spin up a replica of the production environment, with minor modifications to save costs or focus on developing a specific service.

We also started to expand the catalog of basic resources with managed resources like managed containers, which users could deploy in a couple of seconds. We ran the containers in dedicated EC2 instances and exposed


Looking back on Anzu, the result of all the pieces coming together was truly amazing, yet it took a long time due to the complex architecture and handling a lot of cases. We should have decided on a very limited MVP scope instead of accounting for most problems upfront (even though this yielded a great experience), because we still failed to find product-market fit. Ah well, building products isn’t easy.

Anzu building blocks (Fall 2022 - Spring 2023) 🌟

Tech stack: React, Node.js, TypeScript, PostgreSQL, AWS, Docker, D3/visx, Radix UI, Framer Motion, ClickHouse

Concepts: in-product “Databases”, webhooks, public SDKs

Once we understood that resource management wasn’t the issue for most companies, Tim and I moved on to providing common building blocks like authentication, user management, product analytics, and a CRM, in a completely integrated platform.

We started with user management and authentication via a hosted auth page, redirecting users to the developer’s application with an issued token and sending webhooks to create the account in the backend. We collected and stored analytics events in ClickHouse, providing a highly scalable event search experience.

For the CRM, we created a custom schema architecture, building on some of the ideas of the initial iteration of Anzu and my learnings building the infrastructure around user-generated schemas at Hygraph. The Anzu CRM supported multiple views, filters, custom sorting, fuzzy search, pagination, and automatic currency conversion before sorting. We designed the system to allow users to create custom fields for contacts, companies, deals, and notes.

We also built a custom code highlighter service to create a Stripe-like webhook creation experience with code examples side by side. With the new Anzu CLI, users could forward events locally and test their integrations for reacting to signups and other changes.

Atlas (Fall 2022)

Tech stack: Go, gRPC

At Hygraph, we always struggled to make the local development experience ergonomic. We had too many services and the sprawl of compose and .env files wasn’t getting any better. Ideally, every service could define its own build and local dev configuration close to the codebase. To start up the local dev environment, all configuration files would need to be combined, dependencies resolved and services started.

To propose a better workflow, I proposed Atlas, a simple system based on decentralized configuration files written in any language. This idea was largely based on Anzu providers using the same gRPC server architecture, and it offered the simple but attractive possibility of having different teams write their service configurations in their language of choice. In the end, Atlas was designed around collaboration: Each team or service owner would supply an Atlasfile, enabling any developer to spin up a local development environment by running one command. This did away with the limited configuration syntax allowed pulling in environment variables from infrastructure as code or .env files, and made it easier to keep track of service configs.

Final Thesis: Scheduling for Serverless FPGAs (Summer 2023) ⭐️

Tech Stack: Kubernetes, FPGAs, containers/virtualization (Docker, containerd, kata-containers, kvm), Go, Python, matplotlib, pandas, LaTeX

Concepts: FPGAs, hardware acceleration, serverless computing, orchestration systems

For my final thesis at the Chair of Distributed Systems & Operating Systems at TUM, I worked on feeding FPGA usage information back to the Kubernetes Scheduler to add FPGA awareness for serverless scenarios.

While most public clouds offer restrictive access to FPGAs and other hardware accelerators by binding them to compute instances, the chair designed a serverless platform using partial reconfiguration for real-time function invocation handling on shared and partitioned FPGAs.

Recording usage metrics and creating a utilization score across the distributed system to inform future deployments and function migration balances system utilization for FPGA-heavy use cases.

Working at the cutting edge with Gradients & Grit

To help teams build better AI-enabled applications, Tim and I recently launched Gradients & Grit, a new publication exploring production-ready AI at the frontier of research.

PromptCanvas (August 2023) ⭐️

Tech Stack: OpenAI APIs, Next.js, tldraw, Framer Motion, upstash, Neon

Concepts: UX, LLMs

In our first issue of Gradients & Grit, we introduced PromptCanvas, a spatial prompting experience. Similar to whiteboard and collaborative canvas applications used for brainstorming, PromptCanvas allows to represent prompts visually and spatially, using templates and connecting other prompts and text elements to create powerful pipelines.

The PromptCanvas backend was built using Next.js, upstash, and Neon, as well as the OpenAI APIs to access the best LLMs, while we customized tldraw for rendering the canvas.


Over the last years I’ve learned more than I ever anticipated, and the learning rate has been getting steeper ever since, it’s almost compounding the more I know. I’m incredibly grateful to everyone who helped and inspired me along the way and showed me that software engineering is about so much more than just writing code or knowing a technology. I truly couldn’t have done it without the teams and friends I made along the way, and I’m looking to pay it forward and mentor the next generation of software engineers. If this is you, feel free to reach out to me via email!

It’s about building bridges to other roles and stakeholders, understanding and predicting complexity, communicating topics at different levels of abstraction, evaluating and questioning assumptions, measuring results and created value, and working effectively in a cross-functional team to deliver reliable and sustainable results while making sure everybody on the team feels like they’re doing their best work as part of a group of friends (I intentionally avoided the term family which is often used in toxic and exploitative environments, your job couldn’t be further from your family).

I started as a very junior developer, teaching myself everything I needed to build projects along the way, understanding the context of different roles, the importance of solving real business problems (instead of throwing tech at anything I can find), and different growth stages and requirements in startups. I’m looking forward to applying and expanding my engineering skills to further areas, and gradually moving closer to customer-facing and team management roles. I’ve gathered the necessary engineering and architecture experience to find the best action plan to building, deploying, and running complex systems, and I’m eager to learn more about enterprise use cases in the time ahead.