Thoughts
What I have learned from building, debugging, scaling, and untangling software over the past two decades. The subjects range from code and tests to architecture, operations, and the business constraints behind technical decisions.
- Testing the Go Port Against PHP
- Retire the Browser, Keep the Test Runner
- Recover the First Useful Service, Not Every Server
- A Rewrite Can Change Data Without Changing the Price
- Replication Copies Corruption Too
- A PHP Test File Isn't One Migration Case
- The Migration Plan Was Solving the Wrong Problem
- When the Framework Sets the Latency Floor
- A Backup Is Only an Input to Recovery
- Repository Evidence Is Not an Instruction
- Is Your Benchmark Doing New Work?
- A Cache Hit Still Has a Payload
- Index Tariffs Without Losing Charges
- Implementation Without Understanding Is Borrowed Code
- Compile Published Rules Before the Quote Arrives
- AI Should Shorten the Evidence Loop
- The Order of Charges Changes the Price
- Quality Needs a Risk and Capacity Budget
- One Parcel Doesn't Have One Pricing Weight
- The Engine Prices Parcels, Not Copies
- Choose a Stack from Constraints, Not Identity
- A Valid Pricing Row Can Still Be Wrong
- Not Every Pricing Rule Belongs in a Formula
- A Decision Record Needs a Way Back
- How a Shipping Quote Gets Its Price
- A Short-Lived Token Can Still Have a Large Blast Radius
- A Lockfile Gives Repeatability, Not Provenance
- Supply-Chain Security Begins with Who Can Change the Artifact
- Rollback Cannot Restore a Contract You Already Removed
- Observability Must Answer the Next Operator Question
- From Commit to Changelog: An Intent-Aware Release Pipeline
- Unreleased Is Not a Junk Drawer
- A Pull Request Is a Review Narrative, Not a Template
- Intent Commits: Commit Types Are Not Release Decisions
- A Cache Hit Is Not a Freshness Guarantee
- Octane Removes Repeated Boot and Adds State
- Eager Loading Is Not a Query Shape
- A Worker Count Is Not a Throughput Plan
- Cache the Deployment, Not the Assumption
- A Slow Request Is Not a Capacity Plan
- Boundaries Follow Work Without Becoming Destiny
- Enforce Architecture at the Cheapest Reliable Layer
- Name the Independent Thing
- A Module Is Cheaper Than a Network Boundary
- Decompose by Change, Not by Layer
- A Design Is Good for a Change, Not in Isolation
- A Characterization Test Is a Boundary, Not a Recording
- A Surviving Mutant Is a Question, Not a Score
- An Interface Does Not Make a Fake Substitutable
- A Mock Fortress Tests a Call Script
- Choose the Test Boundary from the Defect
- Coverage Tells You What Ran, Not What Your Tests Would Catch
- Test Process State, Not Message Choreography
- A Process Manager Remembers What the Queue Cannot
- An Outbox Moves the Failure Window
- Publishing Events Is Not Event Sourcing
- A Domain Event Is a Fact, Not a Question
- CQRS Starts When Reads Need a Different Model
- A Queued Command Changes the Contract
- A Command Bus Must Pay for Its Indirection
- A Valid Command Can Still Be Refused
- A Version Column Is Not Concurrency Control
- Loading State Is Not Creating It Again
- A Mapper Connects Two Honest Models
- A Repository Is a Domain Collection, Not an ORM Wrapper
- A Composition Root Makes Choices Visible
- A Hexagon Is Not a Directory Layout
- An Open Host Service Is Not a Published Language
- An API Cannot Tell You Who Has Influence
- An Anti-Corruption Layer Must Own the Translation
- A Context Map Must Say What the Arrow Means
- Shared Kernel or Published Language: Choose Where Coordination Lives
- EventStorming Finds Disagreement Before It Finds Services
- Entity, Value Object, Aggregate, Model, DTO: Name the Role
- A Constructor Should Leave a Usable Object
- A Null Object Should Mean Nothing Happened
- The Law of Demeter Is About Knowledge, Not Dots
- Tell, Don't Ask Means Keep the Decision with the State
- Strategy Chooses How; Command Records What to Do
- Composition Over Inheritance Is a Decision, Not a Rule
- Dependency Inversion Lets Policy Own the Boundary
- Interfaces Belong to Their Clients
- Substitution Is a Behavioral Contract
- Open–Closed Protects Stable Policy from Repeated Variation
- Single Responsibility Is About Change, Not Class Size
- A Design Principle Is a Compressed Failure History
- Design Becomes Valuable When the Next Change Arrives
- The Type a Caller Receives Defines the Role
- A Method Should Tell You What Changed
- Construction Should Not Hide Durable Writes
- Global State Makes Local Reasoning Impossible
- Framework Convenience Has a Boundary
- Dependencies Should Be Visible at Construction
- A Service Class Can Become a Procedural Junk Drawer
- A Primitive Can Hide a Domain Decision
- Boolean Parameters Hide Different Operations
- Invalid State Should Be Difficult to Construct
- A Class Name Should Describe a Role
- Stored Data Is a Caller You Cannot Find with Code Search
- The Strangler Pattern Still Needs an Exit Plan
- Deprecation Is a Migration, Not a Warning
- Static Analysis Turns Assumptions into Questions
- A Code Review Should Test the Decision, Not the Author
- A Small Change Limits the States a Reviewer Must Hold
- Technical Debt Is a Change Tax You Can Name
- A Rewrite Needs a Behavior Ledger
- Parallel Implementations Are Not a Replacement Seam
- A Characterization Test Is Not a Product Decision
- A Characterization Suite Is Scoped to a Change
- A Directory Map Is Not a Redesign Plan
- A Capability Interface Is Smaller Than a Vendor Client
- Renaming a Field Is a Protocol Migration
- A Cache Must Distinguish Empty from Unavailable
- Partial Work Needs a Child Ledger
- Retry Budgets Multiply Across Layers
- A Rate Limit Belongs to All the Workers Sharing It
- An Idempotency Key Is Not an Identity
- A Webhook Delivery Is Not a Unique Event
- Map External Data Before It Enters Your Model
- Validate at the Boundary You Control
- A Third-Party API Is an Unreliable Collaborator
- An HTTP 200 Does Not Mean the Operation Succeeded
- Data Outlives the Code That Created It
- Audit History Is Different from Application Logging
- An Index Must Serve a Real Query
- Pagination Needs a Stable Order
- Soft Deletes Preserve Ambiguity Too
- An Identifier Should Outlive Its Storage Engine
- Time Zones Are Part of the Data Model
- Money Is Not a Floating-Point Number
- Null Is a Domain Decision
- A Migration Is a Production Change
- A Transaction Defines What Must Succeed Together
- Let the Database Reject Impossible State
- Debugging Ends with an Explanation, Not a Green Build
- A Release Gate Must Fail Before Incompatible Code Goes Live
- Test Cannot Prove Production When It Runs Different Rules
- A Correlation Identifier Is a Boundary Contract
- Retries Can Multiply the Original Failure
- A Timeout Is Part of the Contract
- Silencing an Error Does Not Protect the Customer
- Runtime Configuration Is Process State
- A Failure Timeline Can Eliminate the Best-Looking Suspect
- Logging Is a Workload, Not a Side Effect
- Production Bugs Can Live in the Data, Not the Code
- Reproduce the Failure Before Repairing It