2.1free~6 min

What humans type now

1. The shrinking keyboard

Look at what a working engineer types in a day now. Not what they did five years ago — what they do this week.

They type prompts. They type specifications. They type the function signature and let the model fill the body. They type comments that explain why the code exists, because the model can already see what it does. They type the edge cases the model didn't ask about. They type "no, the other way." They type "show me the type." They type the test names. They type the commit message.

What they don't type, mostly, is the function bodies. The model types those.

2. The five things humans type

Specifications. Plain prose describing what you want. The clearer the spec, the closer the first generation is to shippable.

Intentions. What this code is for. Why it exists. What it's allowed to do and what it isn't. The model is good at the how. It can't read your mind on the why.

Constraints. "Must work in a Node 20 runtime." "Must not call the network." "Must be deterministic given the same input." Constraints narrow the space the model is searching in.

Examples. One concrete input and the expected output beats a paragraph of abstract description. Models are pattern-matchers; show them the pattern.

Edge cases. "What about an empty array?" "What if the user is logged out?" "What if two requests arrive in the same millisecond?" These are the gaps the model leaves. Filling them is your job.

3. The spec is the new code

Here's a TypeScript example. The human types the comment block and the function signature. The function body — the implementation — is what the model fills in.

tsWhat the human types — a spec comment and a signature
/**
* Merge two sorted arrays of timestamps into a single sorted array.
*
* - Both inputs are already sorted ascending.
* - Duplicates across inputs are kept (not deduplicated).
* - The result must be sorted ascending.
* - Must run in O(n + m), not O((n + m) log(n + m)).
*
* Edge cases:
* - Either input may be empty.
* - Inputs may be the same length or wildly different lengths.
*
* Example:
*   merge([1, 4, 7], [2, 3, 9])  ->  [1, 2, 3, 4, 7, 9]
*/
export function mergeTimestamps(a: number[], b: number[]): number[] {
// model fills this in
}

Read the comment. It contains everything the model needs: the goal, the constraints, the complexity requirement, the edge cases, an example. That comment took longer to write than the function body would have. That's the trade.

4. Comments that say why, not what

The old advice was "write self-documenting code, comments are a smell." That advice came from a world where the code was the thing humans typed. The code was the documentation, so duplicating it in a comment was waste.

The new advice is different. The code is what the model typed. The comment is where you, the human, write down what you wanted. The comment is the contract. The code is the answer the model gave. When they diverge, the comment is correct and the code is wrong.

So you write comments that say why this exists, what it's for, what it must guarantee. Not "increments the counter by one" — the code already says that. "Tracks unique daily-active users; must not double-count repeat sessions." The model can't infer that from the code.

5. The skill, in one sentence

The skill is writing specs that are precise enough to generate code from, and complete enough to verify code against. Both directions. If your spec is fuzzy, the generated code will be fuzzy too — and you won't know if it's wrong, because you didn't pin down what right looks like.

That's the new keyboard work. It's less of it. It matters more.