<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Things I've Written on Mike Mwita</title><link>https://mikemwita.com/thoughts/</link><description>Recent content in Things I've Written on Mike Mwita</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://mikemwita.com/thoughts/index.xml" rel="self" type="application/rss+xml"/><item><title>Forget Everything You Know About Time</title><link>https://mikemwita.com/thoughts/forget-everything-you-know-about-time/</link><pubDate>Sun, 02 Aug 2026 11:00:00 +0300</pubDate><guid>https://mikemwita.com/thoughts/forget-everything-you-know-about-time/</guid><description>&lt;p>&lt;span class="dropcap">M&lt;/span>
itch Hedberg had a bit about late-night television:&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;I saw a commercial on late-night TV, it said, &amp;lsquo;Forget everything you know about slipcovers.&amp;rsquo; So I did, and it was a load off my mind. Then the commercial tried to sell me slipcovers, but I didn&amp;rsquo;t know what the hell they were.&amp;rdquo;&lt;/p>
&lt;/blockquote>
&lt;p>So here is my pitch: forget everything you know about time.&lt;/p>
&lt;p>I mean it. Put the intuition down and step away from it. You learned clocks and calendars before you could read, you have used them every single day since, and that fluency is precisely the problem — it is &lt;em>conversational&lt;/em> fluency. It survives on ambiguity, because a human listener quietly patches the gaps for you. A computer will not. It takes your assumption, applies it with total consistency, and hands you back something wrong in a way you never thought to check.&lt;/p></description></item><item><title>Beyond Backend Basics</title><link>https://mikemwita.com/thoughts/beyond-the-backend-basics/</link><pubDate>Wed, 07 Jan 2026 13:10:00 +0300</pubDate><guid>https://mikemwita.com/thoughts/beyond-the-backend-basics/</guid><description>&lt;h1 id="beyond-backend-basics">
Beyond Backend Basics
&lt;a href="#beyond-backend-basics" class="heading-anchor">#&lt;/a>
&lt;/h1>
&lt;p>Most backend developers can build APIs, wire up databases, and scale services.
That’s good. But “good” is not enough if your ambition is to become the kind of engineer who can design &lt;strong>distributed systems that survive chaos&lt;/strong> and influence organizations at scale.&lt;/p>
&lt;p>It’s a checklist of some of the skills you need to learn now if you want to operate at the highest levels of engineering.&lt;/p></description></item><item><title>Write Once, Test Everywhere: Sharing Common Tests in Python’s unittest</title><link>https://mikemwita.com/thoughts/unit-test/</link><pubDate>Tue, 21 Oct 2025 07:00:00 +0300</pubDate><guid>https://mikemwita.com/thoughts/unit-test/</guid><description>&lt;p>A while back, I was writing tests for a project using Python’s unittest.
Nothing dramatic — just the usual rhythm: write a class, test it, move to the next one.
After a few classes, though, the déjà vu hit.&lt;/p></description></item><item><title>Generating Go Code from OpenAPI Specification</title><link>https://mikemwita.com/thoughts/generating-go-code-from-openapi/</link><pubDate>Sun, 12 Oct 2025 07:00:00 +0300</pubDate><guid>https://mikemwita.com/thoughts/generating-go-code-from-openapi/</guid><description>&lt;p>A quick and practical walkthrough for developers who want to generate type-safe Go code directly from OpenAPI specs.&lt;/p></description></item><item><title>Behavior-Driven Development in Go</title><link>https://mikemwita.com/thoughts/bdd-tests-in-go/</link><pubDate>Tue, 12 May 2020 07:00:22 +0300</pubDate><guid>https://mikemwita.com/thoughts/bdd-tests-in-go/</guid><description>&lt;p>Testing is often seen as a technical safeguard — a way to ensure code correctness.
But what if tests could do more than that?
What if they could express intent, document behavior, and communicate meaning across developers, testers, and product owners alike?&lt;/p></description></item><item><title>Caching Is Easy. Invalidation Is Where Systems Falter.</title><link>https://mikemwita.com/thoughts/cache-invalidation/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/cache-invalidation/</guid><description>&lt;h1 id="caching-is-easy-invalidation-is-where-systems-falter">
Caching Is Easy. Invalidation Is Where Systems Falter.
&lt;a href="#caching-is-easy-invalidation-is-where-systems-falter" class="heading-anchor">#&lt;/a>
&lt;/h1>
&lt;p>Adding a cache is a one-afternoon task. You pick a layer, set a TTL, watch your database load drop. It feels like engineering.&lt;/p>
&lt;p>Invalidation is the part nobody writes down. It is also the part that wakes you up at 3am. Users seeing stale data after an update. A rollback that leaves garbage in cache for 24 hours. A race condition where two services update the same key in the wrong order and nobody notices for a week.&lt;/p></description></item><item><title>Escape Analysis in Go</title><link>https://mikemwita.com/thoughts/escape-analysis-in-go/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/escape-analysis-in-go/</guid><description/></item><item><title>Flow Control in Distributed Systems: Understanding Backpressure</title><link>https://mikemwita.com/thoughts/understanding-backpressure/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/understanding-backpressure/</guid><description/></item><item><title>Foreign Function Interfaces (FFI)</title><link>https://mikemwita.com/thoughts/foreign-function-interface/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/foreign-function-interface/</guid><description/></item><item><title>Hexagonal Architecture in Go</title><link>https://mikemwita.com/thoughts/hexagonal-architecture-in-go/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/hexagonal-architecture-in-go/</guid><description>&lt;p>&lt;span class="dropcap">M&lt;/span>
ost Go services start out reasonable. A handler calls a database. A function returns a struct. Six months later, your HTTP handler is importing your database package, your database package is calling an external API, and your tests require a live Postgres instance to run a single unit.&lt;/p>
&lt;p>This is not a Go problem. It is an architecture problem — and hexagonal architecture is the structural answer.&lt;aside class="sidenote">Also called &lt;strong>ports and adapters&lt;/strong>, coined by Alistair Cockburn in 2005. The hexagon shape has no special meaning — it just illustrates that an application has multiple sides to connect.&lt;/aside>
&lt;/p></description></item><item><title>Multitenancy Lessons from Slack</title><link>https://mikemwita.com/thoughts/multitenancy-lessons-from-slack/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/multitenancy-lessons-from-slack/</guid><description>&lt;h1 id="multitenancy-lessons-from-slack">
Multitenancy Lessons from Slack
&lt;a href="#multitenancy-lessons-from-slack" class="heading-anchor">#&lt;/a>
&lt;/h1>
&lt;p>Slack looks like a messaging app. Under the hood, it is a multi-tenant distributed system solving problems that every SaaS platform eventually runs into — just at a scale that makes the problems impossible to ignore.&lt;/p>
&lt;p>If you think about it carefully, every architectural decision Slack makes is shaped by one central tension: &lt;strong>every workspace feels isolated, but you cannot afford isolated infrastructure per customer.&lt;/strong>&lt;/p></description></item><item><title>My Thoughts on Domain-Driven Design in Golang</title><link>https://mikemwita.com/thoughts/domain-driven-design/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/domain-driven-design/</guid><description>&lt;p>&lt;span class="dropcap">C&lt;/span>
ontrary to what most people think, DDD is not about folder naming. It is not about having directories called &lt;code>domain&lt;/code> and &lt;code>infrastructure&lt;/code> and calling it a day.&lt;/p>
&lt;p>Here is my lightweight approach that helps you think about what your app domain actually is. The concept is straightforward: you see a domain, you create a directory for it. The real value is not in the structure itself — it is in the thinking the structure forces you to do.&lt;/p></description></item><item><title>Reading Flame Graphs in Go</title><link>https://mikemwita.com/thoughts/reading-flame-graphs-in-go/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/reading-flame-graphs-in-go/</guid><description>&lt;p>&lt;span class="dropcap">I&lt;/span>
nvisible performance bugs are the ones that scale with you. A function that takes 800 nanoseconds at 100 rows and 130 microseconds at 10,000 rows looks fine in every test you write on day one, and quietly becomes the reason a page hangs on day three hundred. You cannot fix what you cannot see — and a guess is not seeing.&lt;/p>
&lt;p>This is a walkthrough of making one such bug visible: write a benchmark, capture a CPU profile, and read the flame graph until the cost stops being a mystery. The example is a real lookup from &lt;a href="https://github.com/MikeMwita/PayMeter">PayMeter&lt;/a>, a small Go payments service, but the workflow is the same for anything.&lt;aside class="sidenote">Everything here uses only the standard toolchain — &lt;code>go test&lt;/code>, &lt;code>go tool pprof&lt;/code>, and Graphviz. No third-party profilers.&lt;/aside>
&lt;/p></description></item><item><title>SQL Doesn't Run in the Order You Write It</title><link>https://mikemwita.com/thoughts/sql-execution-order/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/sql-execution-order/</guid><description>&lt;p>&lt;span class="dropcap">E&lt;/span>
very developer who has written SQL has made the same mistake at least once: used a &lt;code>SELECT&lt;/code> alias in a &lt;code>WHERE&lt;/code> clause, or tried to filter on an aggregate without &lt;code>HAVING&lt;/code>, and gotten an error that felt completely arbitrary. It is not arbitrary. It is the database telling you that you wrote the query in one order and expected it to execute in that order. It does not.&lt;/p>
&lt;p>Understanding the actual execution order is one of those things that turns SQL from a language you fight into a language you reason with.&lt;/p></description></item><item><title>That Username Is Taken. How Does Google Know Instantly?</title><link>https://mikemwita.com/thoughts/username-availability-at-scale/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/username-availability-at-scale/</guid><description>&lt;p>&lt;img src="https://mikemwita.com/images/gmail-username-check.png" alt="Gmail username availability check — &amp;ldquo;newuser&amp;rdquo; is taken, n12205707 is suggested">&lt;/p>
&lt;p>You type &amp;ldquo;newuser&amp;rdquo; into the Gmail signup screen. Already taken. The UI suggests &amp;ldquo;n12205707&amp;rdquo; before you have even stopped typing. No spinner. No network flicker. Just instant.&lt;/p>
&lt;p>You are not doing an Elasticsearch query on every keypress. That would be a crime.&lt;/p>
&lt;p>So how does it work? I want to walk through what I think is the right solution — the math behind it, and why most engineers reach for the wrong tool first.&lt;/p></description></item><item><title>The Thundering Herd Problem</title><link>https://mikemwita.com/thoughts/cache-stampede/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/cache-stampede/</guid><description>&lt;h1 id="the-thundering-herd-problem">
The Thundering Herd Problem
&lt;a href="#the-thundering-herd-problem" class="heading-anchor">#&lt;/a>
&lt;/h1>
&lt;p>Your site&amp;rsquo;s homepage is heavily cached. The cache key expires every 60 seconds. At 12:00 PM, the cache expires. At 12:00:01 PM, 10,000 concurrent user requests come in. None of them find anything in cache. All 10,000 hit your database simultaneously to regenerate the exact same content.&lt;/p>
&lt;p>Your database crashes. The site goes down.&lt;/p>
&lt;p>This is a &lt;strong>cache stampede&lt;/strong>, also called a thundering herd. The irony is that the cache was there to protect the database. The moment it failed to do its job, it caused something worse than if it had never existed.&lt;/p></description></item><item><title>What It Takes to Be a Real Go Engineer</title><link>https://mikemwita.com/thoughts/what-it-takes-to-be-a-real-go-engineer/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://mikemwita.com/thoughts/what-it-takes-to-be-a-real-go-engineer/</guid><description>&lt;p>&lt;span class="dropcap">M&lt;/span>
ost developers can learn Go&amp;rsquo;s syntax in a weekend. Goroutines, channels, interfaces, error handling — the surface area is deliberately small. That is one of Go&amp;rsquo;s design strengths. It is also the trap.&lt;/p>
&lt;p>The hard parts of Go are invisible in the syntax: knowing &lt;em>when&lt;/em> to reach for concurrency, &lt;em>why&lt;/em> a value is escaping to the heap, &lt;em>what&lt;/em> your goroutines are doing when the load spikes at 3am.&lt;/p>
&lt;aside class="pullquote">
 Syntax is the easy part. Judgment is what production actually tests.
&lt;/aside>

&lt;div class="section-divider">
 &lt;span>&lt;/span>&lt;span>&lt;/span>&lt;span>&lt;/span>
&lt;/div>

&lt;h2 id="concurrency-is-a-tool-not-a-default">
Concurrency Is a Tool, Not a Default
&lt;a href="#concurrency-is-a-tool-not-a-default" class="heading-anchor">#&lt;/a>
&lt;/h2>
&lt;p>Go makes concurrency syntactically trivial. That is a feature and a footgun in the same breath. In older systems languages, spawning a thread was expensive and awkward — the friction forced you to think. In Go, you write &lt;code>go&lt;/code> and move on. The language removes the friction. The problem does not.&lt;/p></description></item></channel></rss>