When Goroutines Got in the Way: Mia's Thursday Night
When a race condition taught her that sometimes the most elegant code needs the most careful testing
FAIL: TestOrderProcessingConcurrent
Expected 500 orders, got 497
race detected: write at 0x... concurrent with write at 0x...
Mia stared at the terminal, the red text somehow angrier in the empty office than it had been five minutes ago. Three orders. Three orders had vanished, and Go's race detector was screaming about concurrent writes, but the code looked perfect.
It was 9:15 PM on a Thursday. The Seattle tech hub had emptied out hours ago—the coffee machines in the break room were cold, the standing desks were all down, and the only sound was the white noise hum of servers somewhere in the building and the occasional creak of the building settling into night.
Mia had been promising this feature for two weeks.
The Setup
That morning, she'd demoed the order processing pipeline to David, her boss and the engineer who'd brought her into the Go ecosystem three years ago when she was still figuring out what concurrent programming even meant.
"Look," she'd said, pulling up the performance metrics on her monitor. "Parallel processing on incoming orders. We went from handling 100 orders per second to 500. The benchmarks are clean."
David had leaned back in his chair, the kind of approving nod that made her feel like she'd actually leveled up. "That's solid work, Mia. Really solid. You comfortable pushing this to staging?"
"Tomorrow morning," she'd said. "Just want to run one more comprehensive test tonight to make sure the concurrent load handling is bulletproof."
One more test.
The phrase that has haunted developers since programming was invented.
Now her phone sat on the desk, dark. She'd texted her parents at 6 PM saying she'd be working late, and her mom had immediately responded with: Make sure you eat something. I made extra teriyaki chicken yesterday.
The chicken was still in her apartment's fridge, probably. She'd meant to stop home and grab it before coming back to the office. Instead, she'd grabbed a mediocre coffee from the lobby café and returned to her desk like someone drawn back to a crime scene.
Into It
Mia pulled up the code. The structure was elegant—exactly the kind of thing that made Go beautiful. A channel pipeline that received orders, processed them through validation, enrichment, and finally persistence. Goroutines handling each stage, clean separation of concerns, everything orchestrated through channels that were supposed to handle the concurrency for her.
That was the promise of Go, right? Make concurrency easy. Let the language handle the hard parts.
Except something wasn't.
She ran the test again with the race detector enabled:
go test -race ./order-processor -count=5
The race detector was Go's best friend—it caught the tiny moments where two goroutines tried to write to the same memory location without synchronization. It was catching something in her code, and that something was making orders disappear.
She traced through the logic. The order comes in on a channel. Gets validated. Gets enriched with customer data. Then... there. The persistence layer. She was writing to a map that stored processed orders:
// Store the processed order
orders[order.ID] = order
Simple. Clean. Correct... except when two goroutines hit it at the same time from different enrichment pipelines. Then it became a race condition. Then orders got overwritten or lost entirely.
Mia felt that familiar tightness in her chest. The one that came right before self-doubt took over. She could Slack David. He was always available, always generous with his time. That was the job of a senior engineer, right? To help junior and mid-level developers solve problems?
But she wasn't junior anymore. She was mid-level. She was supposed to be able to figure this out.
Her stomach rumbled. She ignored it.
The Wrong Turns
She tried a sync.Mutex first—wrapping the map access with locking:
orderMutex.Lock()
orders[order.ID] = order
orderMutex.Unlock()
Ran the test. Still failing. The race detector still screaming.
She paced the office, her footsteps loud in the quiet. Went to the bathroom. Stared at herself in the mirror under fluorescent lights that made her look like a ghost. Came back.
Tried a sync.Map instead, designed for concurrent access:
orders.Store(order.ID, order)
Test again. Still red. Still angry.
It was past eleven. The building was so quiet she could hear her own breathing.
She sat back down and pulled up her phone. Opened the thread with her parents.
The Text
Mom: Did you eat?
The message was from an hour ago. Her mom had probably sent it and then gone back to whatever she was doing—probably reading, her mother's eternal hobby. Her dad would be asleep in his study, the small lamp on his desk still on, a book open on his lap.
Mia: Working on something stubborn. Will eat soon.
Three dots appeared immediately.
Dad: What kind of stubborn?
She almost smiled. Her dad, who'd spent thirty years in manufacturing, who understood the particular frustration of something not working the way it should.
Mia: Goroutines are writing to the same place at the same time. The code looks right but the race detector hates it.
The three dots took longer this time. Her dad, hunting and pecking, probably asking her mom how to spell something.
Dad: Can you make them take turns instead of going at the same time?
She stared at that message. Something about her dad's question—so simple, so non-technical, so perfectly on-point—made something shift in her thinking.
Take turns.
Not by locking them down. By making sure only one of them ever needed to write to that map in the first place.
She texted back: Dad you're a genius.
Dad: Your mother says I should clean the garage more. But I'll take the genius compliment.
Mia set her phone down and turned back to the code. The issue wasn't the map. The issue was architecture. She'd designed the pipeline so that multiple enrichment goroutines could all write to the same orders map. Instead, she should funnel all the enriched orders back through a single channel, let a single goroutine do the writing.
Single writer. Multiple readers allowed. That was the Go way.
She redesigned the pipeline:
// Enriched orders come back through a single channel
enrichedOrders := make(chan Order, bufferSize)
// Single goroutine owns the write to our map
go func() {
for order := range enrichedOrders {
orders[order.ID] = order
}
}()
Her fingers found their rhythm on the keyboard. The flow state where architecture became code without thinking about it. She refactored the enrichment pipeline to send completed orders to a single channel instead of having multiple goroutines fight over map access.
Ran the test.
PASS: TestOrderProcessingConcurrent
500 orders processed successfully
No race detected
Green.
Then again. Green.
Then the full test suite. Green, green, green.
It was 12:47 AM.
She'd figured it out.
Friday Morning
Mia pushed her code at 7 AM sharp, running on three hours of sleep and a container of teriyaki chicken she'd grabbed from her apartment fridge at five in the morning. The staging tests ran clean. No red. No failures.
David came by her desk at nine, holding his usual pour-over coffee in a ceramic mug she'd seen him with for at least two years.
"Saw your commits," he said, and there was something in his voice—not surprise, exactly, but recognition. "Race condition in the order pipeline?"
"Yeah." Mia tried to sound casual, like she hadn't spent four hours hunting it down, like she hadn't doubted herself a dozen times. "The architecture was wrong. I had multiple goroutines writing to the same map. Redesigned it so there's a single writer channel."
David nodded slowly, and she could see him walking through the logic in his head. "That's the right call. Elegant solution. Could've been tempting to just mutex everything and call it done."
This was the moment. Mia could have said "I almost did" or "I wasn't sure" or downplayed how long it took. Instead, she met his eyes.
"I almost did. But then I realized the real problem was the design, not the synchronization."
"That's the thing that separates people who write Go from people who understand Go," David said. He tapped her desk twice with his knuckle, a gesture she'd seen him use with other engineers on the team. "You're thinking like a concurrency engineer now, not just someone who knows the syntax. Keep going like this, and you're going to be the one I'm asking for advice in six months."
After he walked away, Mia sat very still for a moment, letting those words settle. Then she pulled out her phone.
Fixed it. The architecture was the problem, not the locking. Thanks for the reality check last night.
Mom: I have no idea what that means but your father is very proud. He's been telling everyone at breakfast about the goroutines.
Dad: Your mother's spelling of goroutine is creative. Either way, knew you'd figure it out. You always do.
Mia pocketed her phone and pulled up the next ticket in the backlog. She could see the teriyaki chicken container on her desk, half-empty from her midnight snack. She smiled and cracked her knuckles.
Three weeks later, she'd find herself sitting across from one of the junior devs at lunch, listening to him describe a concurrency issue he was wrestling with in a side project. She wouldn't offer to fix it.
Instead, she'd ask: "So what's the actual problem? Is it the synchronization, or is it the architecture?"
He'd think about it. Then his eyes would light up. "Oh. Oh, it's the architecture."
"Then you already know how to fix it," she'd say.
Because sometimes the best mentor is the one who asks the right question instead of providing the answer. And sometimes, the best way to honor what someone taught you is to teach it forward, one question at a time.
Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.


Comments
Post a Comment