First, Make Me Care: Refactoring Your Communication Architecture
First, Make Me Care
Early in my career, I was a Context Monster.
Every design document, post-mortem, or pull request description started at the very beginning. The legacy constraints, the history of the database schema, the three previous attempts to fix the bug. I'd lay it all out before arriving at the actual point.
I thought I was being thorough. In reality, I was being ignored.
My team didn't hate me. They just skimmed everything I wrote. Because I was treating human attention like an infinite buffer when it's actually a volatile L1 cache. If you don't get a cache hit in the first sentence, the eviction policy kicks in.
We spend hours optimizing First Contentful Paint for our web apps, then serve our human readers a 5MB blocking JavaScript file in the <head> of our documents.
The eager loading problem
In system design, we use lazy loading. We don't fetch heavy relationship data until it's actually needed. In writing? We eager load everything.
Eager load approach (the boring default):
"After the fall of the Western Roman Empire, refugees fled to marshy lagoons. Over centuries, due to geographical constraints..."
The reader disconnects. This is the public static void main(String[] args) of storytelling.
Lazy load approach (the hook):
"Venice was an empire without farms. How does a city that can't feed itself dominate the world for centuries?"
Exception thrown: KnowledgeGapError. The brain detects an anomaly. A city without farms violates the dependency graph of civilization. Now the reader needs to resolve this error.
How to create the knowledge gap
Humans are pattern-matching machines. If you present a pattern that fits perfectly ("We built a React app..."), they sleep. If you present a pattern break ("We built a React app that doesn't use the DOM..."), they wake up.
Your opening sentence is an API contract. It promises: "Allocate resources to this stream and I'll resolve a conflict in your understanding."
Inverting the dependency graph
We usually communicate chronologically:
Background -> Context -> Problem -> Solution
That's logical but psychophysically inefficient. Invert it:
Paradox/Hook -> Solution (high level) -> Context (on demand)
BLUF (Bottom Line Up Front) with a twist. Not just summarizing but teasing the intellectual payoff.
The "system error" pattern
Ask yourself: what is the most counter-intuitive fact about this topic?
-
Bad: "Here's a tutorial on TypeScript Generics for reducing code duplication."
-
Good: "You're writing the same interface three times because you trust your compiler too much. Here's how to make TypeScript write your code for you."
-
Bad: "Our server crashed because of a memory leak in the image processing service."
-
Good: "We took down production with a 4KB JPEG. Here's the post-mortem."
The NarrativeEngine
If we formalize this as code: score information snippets on an intrigueFactor and serve the highest one first.
type InfoNode = {
id: string;
content: string;
type: 'background' | 'conflict' | 'resolution' | 'data';
intrigueFactor: number; // 0-10: likelihood of a "Wait, what?" reaction
timestamp: number;
};
class NarrativeEngine {
private nodes: InfoNode[] = [];
constructor(initialNodes: InfoNode[]) {
this.nodes = initialNodes;
}
// The old way: chronological (boring)
public getChronologicalReport(): string {
return this.nodes
.sort((a, b) => a.timestamp - b.timestamp)
.map(node => node.content)
.join('\n\n');
}
// The new way: by intrigue (the hook)
public getCompellingStory(): string {
const hook = this.nodes.reduce((prev, current) =>
(prev.intrigueFactor > current.intrigueFactor) ? prev : current
);
const bodyNodes = this.nodes
.filter(n => n.id !== hook.id)
.sort((a, b) => b.intrigueFactor - a.intrigueFactor);
return `
# ${hook.content}
${bodyNodes.map(n => n.content).join('\n\n')}
`;
}
}
// Example: a post-mortem
const postMortemData: InfoNode[] = [
{
id: '1',
type: 'background',
content: 'We use Redis 6.0 on a t3.medium instance.',
intrigueFactor: 1,
timestamp: 1620000000
},
{
id: '2',
type: 'conflict',
content: 'The cache eviction policy was set to noeviction.',
intrigueFactor: 4,
timestamp: 1620000100
},
{
id: '3',
type: 'data',
content: 'A single user session object grew to 4GB in size.',
intrigueFactor: 9,
timestamp: 1620000200
},
{
id: '4',
type: 'resolution',
content: 'We restarted the instance and patched the session serializer.',
intrigueFactor: 5,
timestamp: 1620000300
}
];
const engine = new NarrativeEngine(postMortemData);
// Chronological: "We use Redis... eviction policy... session grew... we fixed it."
// By intrigue: "A single user session object grew to 4GB..."
console.log(engine.getCompellingStory());By opening with "A single user session object grew to 4GB," you create a vacuum. The reader immediately asks: How? Why? Who allowed this?
Now they're willing to read about your Redis version and eviction policies. Those facts are no longer background context. They're clues to the mystery you established.
Apply it everywhere
Whether it's a commit message, a tech spec, or an email to your CEO, don't act like a logger dumping chronological text. Act like a query optimizer.
Find the anomaly. Present the paradox. Make them care.
Only then have you earned the right to explain the history of the Roman Empire.