How to reduce your AWS NAT Gateway bill
Cost optimization strategies for AWS networking infrastructure, covering NAT Gateway alternatives and best practices for reducing cloud networking expenses.
I'm a software developer, consultant, entrepreneur, CTO, & co-founder of Compoze Labs.
I've been building software for 15 years, building teams for 10, and running an engineering organization for 5.
I started building software in the JVM world, and will always have a soft spot for Java. I quickly moved up the stack into the Cloud world, AWS will always be my favorite, but I have built and designed a lot of workloads in Azure and GCP. I'm obsessed with developer experience, and in 2025 I became officially AI-pilled.
You can find my writing and videos that have influenced my view of the software world as well as work that I think is worth sharing.
CONTENT
The AWS Well Architected framework is more than a set of best practices; it's one of AWS' best Marketing initiatives. It's trained thousands of engineers and architects on the best way to spend the most money in AWS. And while the values are sound, it requires a practical approach to build the right thing, for the right price.
Cost optimization strategies for AWS networking infrastructure, covering NAT Gateway alternatives and best practices for reducing cloud networking expenses.
A deep dive into the hidden costs of AWS NAT Gateway when using Fargate and ECR, and how to avoid unexpected networking charges.
Best practices for securing your AWS infrastructure through proper VPC network segmentation and isolation strategies.
A practical guide to publishing custom CloudWatch metrics from your Node.js applications using TypeScript and the AWS SDK.
Automating SSL/TLS certificate provisioning and DNS validation using AWS Certificate Manager and Terraform.
Practical guide to building a CLI tool for automated S3 bucket cleanup during infrastructure teardown using Go and Cobra.
Implementing custom email confirmations for AWS Cognito user signups using Lambda triggers and Terraform configuration.
Creating Amazon Machine Images with encrypted root devices using Packer—a repeatable solution for meeting PCI, HIPAA, and FISMA compliance requirements.
RECOMMENDATIONS
These are the articles, talks, and resources that have shaped the values I hold on building software.

This talk solidified my practical approach to TDD. Ian Cooper clarifies what Kent Beck actually meant: test behaviors, not implementation details. Every engineer that cares about building quality code should watch this.

Martin Fowler's classic article explaining the two fundamental approachs to TDD. While he doesn't firmly take a stance, it made me staunchly anti-mocks. Spoiler: I'm a clasical TDDisk

This article inspired me to start Compoze Labs. I think a company's values should be in conflict with one another.

Blake Smith nails what code review is actually for: keeping the team mentally aligned, not nitpicking style. His hierarchy of needs for code review (team alignment > correctness > design discussion > style) has shaped how I approach PRs. The advice on framing feedback as questions is gold.

Fowler explains how useful terms lose their meaning as they spread—'agile' becoming meaningless, 'refactoring' used for any code change. Understanding this phenomenon helps you recognize when buzzwords have drifted from their original intent and why going back to primary sources matters.

This talk gave me an initial foundation on how to safely and responsibly use AI to build software. While the details will continue to evolve, the fundamentals that Dex Horthy lays out I think will continue to be important.
I've spent the past year working intensively with coding agents—Claude Code, Cursor, and others. These are my hard-won convictions about what actually works.
These values have led me to adopting a Research → Plan → Implement workflow and patterns like Spec-Driven Development. The specific terminology will suffer from semantic diffusion eventually, but the underlying practices are sound.
LLM performance degrades significantly as context windows grow. This isn't a minor detail—it fundamentally shapes how you should work. Keep sessions focused. Know when to start fresh and pass context forward. Use compaction strategies (like Claude's /compact) before you hit the wall, not after.
Stop trying to one-shot features. The pattern that consistently works: start with "help me figure out how to build this," flesh out product and technical details, and only move to implementation when the plan is solid. Most harnesses have planning modes now—use them. Track plans in markdown files. Your future self (and your future agents) will thank you. Not everything needs a formal plan, of course, but when you're doing real work it will help you in the long run.
A lot of valuable context evaporates when we don't write down the decisions we make with our agents. I think of this like the ADR pattern, but for both human and AI consumption. Don't track everything—track the important decisions. Plans, architectural choices, the "why" behind non-obvious implementations.
Based on research, trusted industry voices, and my own experience: a human still needs to be in the loop. Not as a rubber stamp, but actively steering technical direction, product direction, and maintaining the context needed to support the software long-term. Think of it as code review—but for the entire development process.
Slash commands and skills are what turn coding agents from chat interfaces into repeatable development workflows. Commands let you codify how you work — research, planning, implementation, testing — into reusable, composable steps. Skills provide the building blocks: patterns for exploration, documentation formats, and verification criteria that commands compose together. The terminal below shows what this looks like in practice.
The ecosystem is standardizing around a set of primitives that make agent-driven development repeatable and shareable across teams. These are the key building blocks.
Project context and instructions loaded at startup
~/.claude/ (global) or ./CLAUDE.md (project)# Project: My Application ## Overview This is a Next.js application using TypeScript, Tailwind CSS, and shadcn/ui. ## Architecture - /app - Next.js App Router pages - /components - Reusable React components - /lib - Utility functions and configurations ## Conventions - Use functional components with TypeScript - Prefer server components where possible - Use Tailwind CSS for styling - Follow the existing patterns in the codebase ## Important Notes - Always run tests before committing - Use conventional commit messages - Keep components small and focused