The Secret Life of Go: Execution Flow
The Secret Life of Go: Execution Flow
Why your deferred logs always show zero seconds (and how to fix it)
#Go #Coding #Defer #BackendDev
Eleanor is a senior software engineer. Ethan is her junior colleague. They work in a beautiful beaux arts library in Lower Manhattan — the kind of place where coding languages are discussed like poetry.
Episode 38
The Beaux Arts library was quiet, the kind of quiet that usually helped Ethan focus, but today it only made the sound of his failing logs feel louder. He stared at a terminal output that refused to make sense.
"Eleanor, I think I’ve found a bug in the time package," Ethan said, his voice dropping to a library-appropriate whisper. "I’m trying to profile this migration function, but the logs are reporting zero seconds every time. It clearly takes nearly a minute to run."
The Argument Evaluation Trap
Eleanor walked over, carrying a stack of architectural journals. She didn't look at the screen; she looked at Ethan. "Show me how you’ve scheduled the contract."
Ethan pulled up the function:
func MigrateLegacyRecords(records []string) {
start := time.Now()
defer log.Printf("Migration completed in %v", time.Since(start))
for _, record := range records {
process(record) // Each record takes significant time
}
}
"It looks correct," Ethan insisted. "I capture the start time, then I defer the log. I thought defer meant 'run this later,' so I assumed everything inside that line was delayed until the function exits."
"That’s the mistake," Eleanor said, setting her journals on the edge of the table. "You’ve fallen into the evaluation trap. In Go, the defer keyword schedules the function call for later, but it evaluates the arguments immediately."
Ethan squinted at the code. "Immediately? Even though it doesn't print until the end?"
"Exactly," Eleanor said. "The moment the program hits that defer line, it looks at time.Since(start). It calculates the duration right then—which is effectively zero—and it packages that result up. It waits until the function finishes to deliver the message, but the message was written the moment you hit the keyword."
Ethan leaned back, the logic finally clicking. "So I’m trying to report the duration of a race before the runners have even left the blocks."
The Closure Solution
"Precisely," Eleanor said. "To fix it, you have to delay the calculation. You need to wrap the logic in a closure—an anonymous function."
She reached over and updated the code:
func MigrateLegacyRecords(records []string) {
start := time.Now()
// Wrap the log in a closure to delay evaluation
defer func() {
log.Printf("Migration completed in %v", time.Since(start))
}()
for _, record := range records {
process(record)
}
}
"Now," Eleanor explained, "the only thing Go evaluates immediately is the existence of the function. The math inside—the time.Since(start)—isn't touched until the defer actually executes at the very end."
Ethan ran the migration again. The terminal flickered, waited, and then finally spit out the truth: Migration completed in 58.2s.
"I see it now," Ethan said. "A naked defer captures the world as it is right now."
"Exactly," Eleanor smiled, picking up her journals. "Think of defer as a suitcase you set by the door. You have to be very careful about what you pack inside it before you close the lid."
Key Concepts from Episode 38
Argument Evaluation
When you use defer, Go evaluates the arguments to the deferred function call immediately. If you pass a variable or a function result (like time.Since()) directly to the defer call, it captures the value at that specific moment in time, not when the function exits.
The Closure Solution
To ensure variables are evaluated at the moment of execution rather than the moment of declaration, wrap the logic in an anonymous function: defer func() { ... }(). This creates a closure that defers the internal logic until the surrounding function returns.
Aaron Rose is a software engineer and technology writer at tech-reader.blog.
Catch up on the latest explainer videos, podcasts, and industry discussions below.


Comments
Post a Comment