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 8, 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
Cloud architecture isn't about using every service available—it's about choosing the right tools for the job and optimizing for both performance and cost. I focus on practical, real-world patterns that balance scalability with maintainability.
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 how I think about software development. Each one changed my perspective or clarified something I'd been struggling with.

This talk fundamentally changed how I think about TDD. Ian Cooper clarifies what Kent Beck actually meant—test behaviors, not implementation details. It's the antidote to the brittle test suites that make people hate TDD. Every developer should watch this.

Martin Fowler's classic article that finally made the mock vs stub distinction click for me. Understanding when to use each approach has made my tests clearer and more maintainable. This is essential reading for anyone serious about testing.

Fowler's reflection on Thoughtworks' three-pillar model—Sustainable Business, Software Excellence, and Social Justice—resonates deeply with how I think about building companies. It's a reminder that great software companies balance commercial success with craft and social responsibility.

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.

Dex Horthy's talk on context engineering for AI coding tools is essential viewing. His 'frequent intentional compaction' approach and the concept of 'dumb zones' vs 'smart zones' has directly influenced how I use AI tools in production codebases. Practical, measured, and immediately applicable.
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 principles naturally lead to workflows like Research → Plan → Implement 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.
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.
The ecosystem is standardizing around a set of tools and configurations. Select a configuration to see an example.
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
A collection of slash commands and workflows I use regularly. Select a command to view its documentation or watch a demo.
Document codebase using parallel Explore agents. Spawns locator, analyzer, and pattern finder agents to map code without suggesting improvements. Outputs to docs/research/.
Document codebase using parallel Explore agents. Spawns locator, analyzer, and pattern finder agents to map code without suggesting improvements. Outputs to docs/research/.
View full source at: .claude/commands/feature/research.md