A few years ago, I started building a platform called Nudges. It was meant to be a distributed, scalable system for orchestrating marketing messages—think small business campaigns, automation, scheduled sends, etc. As it evolved, I realized something that felt counterintuitive:
The codebase nearly doubled in size between v2 and v4... and yet the cost dropped by ~80%, and performance increased by nearly 300%.
This is the story of why—and how—more code led to less waste, faster response times, and far greater maintainability.
The Before: v2 and the Monolith Mindset
When I first wrote the v2 version of Nudges, it was a smaller codebase—about 18,000 lines spread across mostly TypeScript and C#.
The kicker, though, was that while in production, even at the low volume I was handling, those 18k lines of code cost me ~$350/mo.
It was built fast—for proof of concept—but like all tech debt, that speed came due. It was:
Tightly coupled.
Inefficient (a lot of polling, redundant I/O, unoptimized workers).
And maintenance? Painful. Shared logic was scattered across services.
Scaling horizontally was expensive and wasteful.
The Rewrite: v4 and the Modular Architecture
For v4, I refactored the entire system. The line count nearly doubled to 36,000. But this time, that code was intentional. Here’s what changed:
✅ Clearer Separation of Concerns
Each domain was split into its own service. Shared logic was extracted. Configurations were centralized and managed as code (HCL use jumped significantly).
✅ Smarter Asynchronous Processing
We leaned heavily into event-driven design. Kafka queues replaced internal polling. Stateless workers picked up tasks from streams, reducing overhead and latency.
✅ Infrastructure as Code
Terraform and container orchestration allowed for right-sized deployments. Some functions moved to serverless, others to low-cost containers. YAML, HCL, and Dockerfile counts all increased.
✅ Observability and Resilience
More lines, yes—but those lines brought retry logic, error handling, diagnostics, and traceability. Debugging went from wild goose chase to surgical precision.
What I Learned
More Code Isn’t Always Worse
This wasn’t code for code’s sake. This was architecture as documentation. Splitting things into modular components made the system easier to reason about and scale.
Engineering Maturity = Knowing When to Add Complexity
v2 was minimal but brittle. v4 is robust but structured. The trick was adding complexity in service of clarity.
Invest in Dev Experience
Time spent making your system observable and debuggable pays itself back many times over.
Final Thought
Sometimes, the best optimization isn’t shaving off a few lines of code. It’s reshaping the system so the code serves the architecture, not the other way around.
If you’re deep in a rewrite and worried about bloat: remember, intentional structure scales better than accidental simplicity.
Happy building. ✨
Top comments (0)