
When setting out to build a personal website after 16 years in IT, one of the first decisions I had to make was architecture.
In enterprise software development, it is easy to get caught up in high-end architectural trends. We talk about microservices, event-driven message buses, Kubernetes clusters, and distributed tracing before we even write a single line of code. But for my website, I asked myself a very simple question: What is the cleanest, most maintainable architecture that delivers production performance without unnecessary overhead?
The answer wasn't a complex web of microservices. It was a clean, modular Go backend paired with a React frontend.
The Microservice Trap for Small Projects
Throughout my career, I have seen many projects over-engineered right out of the gate. Teams split a straightforward application into half a dozen microservices, only to realize they now spend 80% of their time managing network latency, API contracts, deployment pipelines, and local Docker setups.
Microservices solve organizational problems for massive engineering teams. They allow hundreds of developers to work on separate domains without stepping on each other's toes. But when you are running a single application, microservices often introduce network boundaries where simple in-memory function calls would work better.
For my site, splitting blog posts, portfolio items, and photo galleries into separate microservices would have added massive complexity for zero practical gain.
Why Go is Perfect for a Modular Monolith
When I chose Go for the backend, I wanted speed, low resource consumption, and straightforward code structure.
Go's built-in concurrency model and fast compilation make it ideal for building lightweight REST APIs. Using the Gin framework along with a clean architecture pattern, the entire backend runs as a single compiled binary:
Clean Domain Separation: The code is organized into clear packages (
handlers,services,repositories,models). Each feature domain has its own boundary, making it easy to reason about.Low Memory Footprint: The Go backend boots in milliseconds and consumes minimal RAM, making it extremely cost-effective on AWS infrastructure.
Simple Local Development: Running
docker-compose upspins up the entire stack—Go API, React frontend, and local DynamoDB—in seconds.
Because the code is cleanly modularized inside a single codebase, adding new features or refactoring data models stays fast and frictionless.
Keeping Deployment Lean on AWS
One of my main goals during the 100% AI vibe-coding build was keeping deployment simple and cost-effective.
Because the backend is a single Go service backed by DynamoDB and static S3/CloudFront assets for the frontend, I avoided the headache of orchestrating multiple container instances or paying for heavy cloud infrastructure.
A modular monolith gives you the best of both worlds. You get the simplicity of single-repo deployment alongside the clean code boundaries that make future expansion easy. If a specific domain ever needs to be isolated into a standalone service down the road, the clean service interfaces are already there.
Pragmatism Over Hype
It is tempting to adopt complex architectural patterns just because major tech giants write engineering blogs about them. But good engineering isn't about using the most complex tools available. It's about picking the right tool for your specific scale and constraints.
Building a clean Go backend reminded me of the beauty of simplicity in software development. Write clear code, keep your architecture modular, and focus on delivering value rather than managing infrastructure.
Until then, see you at the top!