How I Think

This page explains how I avoid overengineering and make systems safe to change. If this resonates, we'll probably work well together.

Systems thinking, not layer thinking

Most problems span multiple layers. A slow page might be a frontend render issue, a backend query problem, or a missing index. Fixing it requires understanding the full path — not just one part.

I think in systems: how data flows from database to screen, where failures can happen, what happens when load increases. This context makes local decisions better.

Simplicity is not the absence of complexity

Real systems are complex. Users have edge cases. Business logic has exceptions. The goal isn't to pretend complexity doesn't exist — it's to organize it so each piece is simple in isolation.

I aim for systems where a new developer can understand any single component without holding the entire system in their head. Clear boundaries. Explicit dependencies. No magic.

Trade-offs are the job

Every decision involves trade-offs. More abstraction means more indirection. Better performance often means more complexity. Microservices mean operational overhead.

The skill isn't avoiding trade-offs — it's identifying them, communicating them, and making intentional choices based on actual constraints rather than general best practices.

Reliability over features

A system that works is more valuable than one with more features.

Readability over cleverness

Code is read far more often than it's written.

Explicit over implicit

Dependencies should be visible, not discovered through debugging.

Incremental progress

Ship value continuously while improving the system.

Boring technology

Novel solutions only for novel problems.

Premature optimization

Measure first, then optimize the actual bottleneck.

Architecture astronautics

Solving problems that don't exist yet.

Microservices by default

Start with a monolith, split when you have evidence.

Resume-driven development

Using technologies to learn rather than to solve problems.

Deployment & Operations

Code that can't be deployed reliably isn't done. I think about deployment from the start: how will this run in production? How will we roll back? What happens when it fails?

Good infrastructure is invisible — it just works. But someone had to make decisions about containers, CI/CD, monitoring, and rollback strategies. Those decisions compound over time.

Collaboration

The best technical decisions come from understanding full context. That means talking to stakeholders about user needs, understanding business constraints, and having honest conversations about what's actually possible.

I prefer working with teams that value transparency over politics, treat estimates as forecasts rather than commitments, and understand that sustainable pace produces better outcomes than heroics.

If your product works but feels fragile, let's talk.

Start a conversation