Skip to content
AI Full-Stack Wiki

Writing About Your Engineering Work: Case Studies and Technical Posts

Turn projects into case studies and posts people read: a structure that shows judgment, numbers that make claims credible, and AI as an editor rather than the author.

Difficulty: Beginner12 min readUpdated
On this page· The structure that works

Why this matters

Engineers who write clearly get more opportunities: their projects get noticed, their design docs get approved, and their pull requests get reviewed faster. A good technical write-up about one of your projects does three jobs at once: it is portfolio evidence, interview preparation (you will tell the same story out loud), and proof that you can communicate decisions, a skill every senior role demands. In AI engineering, where everyone has seen the same demos, how you reasoned is what makes your work memorable.

The structure that works#

The structure of a technical case studyA strong technical write-up moves from the problem and its constraints, through the approach and the key decision with its alternatives, to measured results and honest lessons.Problemwho, why it mattersConstraintsbudget, latency, riskKey decisionand alternativesResultsmeasuredLessonsand next steps

Hover or tap a component to see what it does.

Case study structure: the problem, the constraints that made it hard, the key decision with its alternatives, measured results, and lessons.
Show text description

Readers skim. Put the decision and the numbers where they can find them.

  • Problem: One paragraph a non-expert understands. Who had the problem, and what did it cost them?
  • Constraints: What made it hard: cost limits, latency targets, accuracy needs, privacy.
  • Key decision: The interesting part: what you chose, what you rejected, and why. This is what shows judgment.
  • Results: Before and after numbers from evals, traces, or users. Include what did not improve.
  • Lessons: What you would do differently, and what you would build next.

Most project write-ups list features. Strong ones tell the story of a decision:

  1. Problem: who had it and what it cost them, in plain language.
  2. Constraints: what made it hard. Budget, latency, accuracy, privacy.
  3. Key decision: what you chose, what you rejected, and why. This is the heart of the piece.
  4. Results: measured, before and after, including what did not improve.
  5. Lessons: what you would do differently, and what comes next.

A one-sentence test: if a reader remembers only one thing, what should it be? Put that sentence in the first paragraph.

An example outline#

posts/hybrid-search-case-study.md
# Why our docs assistant missed error codes, and how hybrid search fixed it
 
Readers asked about errors like `E_CARD_DECLINED` and got answers about unrelated payment topics.
Retrieval recall on error-code questions was 52%. Adding keyword search beside vector search raised it to 96%,
for under 2 ms of extra latency.
 
## The problem
…who was affected, with one real (anonymized) example question.
 
## Constraints
- p95 time to first token under 1.5 s
- No new infrastructure: Postgres only
- Cost per answer under $0.01
 
## What we tried
| Approach | Recall@5 (error codes) | Recall@5 (all) | Notes |
| --- | --- | --- | --- |
| Vector only (baseline) | 52% | 88% | Embeddings blur exact tokens |
| Bigger embedding model | 58% | 90% | Higher cost, small gain |
| Hybrid search with RRF | 96% | 94% | One extra indexed query |
 
## The decision
Hybrid search with reciprocal rank fusion, because…
 
## What we learned
…including one thing that did not work.

The table does more work than paragraphs of prose: a reader sees the alternatives, the numbers, and the decision in ten seconds.

Writing that engineers read#

  • Lead with the result. The first paragraph says what changed and by how much.
  • Show real artifacts: a diagram, a short code excerpt, a table of numbers, a screenshot. Not your whole codebase.
  • Be specific: "p95 latency fell from 3.2 s to 1.1 s" beats "much faster".
  • Name the trade-offs and the alternatives you rejected. It is the most convincing evidence of judgment.
  • Short sentences, plain words. Define a term the first time you use it.
  • Be honest about limits. "It still fails on multi-hop questions" makes everything else more believable.

AI as your editor, not your author#

Readers notice generic AI prose, and a post that sounds like everyone else's defeats the purpose. Write the draft yourself, from your notes and numbers, and use AI the way you would use a sharp colleague: to find what is unclear, missing, or unsupported.

A quick deterministic lint catches the mechanical problems first:

lib/draft-lint.ts
export interface LintIssue {
  rule: string;
  message: string;
}
 
/** Mechanical checks for a technical post written in Markdown. */
export function lintDraft(markdown: string): LintIssue[] {
  const issues: LintIssue[] = [];
  const body = markdown
    .replace(/\r\n/g, "\n") // drafts saved on Windows use CRLF line endings
    .replace(/`{3}[\s\S]*?`{3}/g, ""); // ignore code blocks
  const blocks = body.split(/\n{2,}/).map((b) => b.trim()).filter(Boolean);
  // Prose paragraphs only: headings, lists, tables, and quotes are not sentences.
  const prose = blocks.filter((b) => !/^([#|>-]|\*\s|\d+\.\s)/.test(b));
 
  if (!/\d/.test(prose[0] ?? "")) {
    issues.push({ rule: "lead-with-result", message: "The first paragraph has no number. State the result up front." });
  }
 
  for (const sentence of prose.flatMap((p) => p.replace(/\n/g, " ").split(/(?<=[.!?])\s+/))) {
    const words = sentence.split(/\s+/).filter(Boolean).length;
    if (words > 35) issues.push({ rule: "long-sentence", message: `${words} words: "${sentence.slice(0, 60)}…"` });
  }
 
  const headings = [...body.matchAll(/^#{2,3} (.+)$/gm)].map((m) => m[1]!.toLowerCase());
  for (const required of ["decision", "learn"]) {
    if (!headings.some((h) => h.includes(required))) {
      issues.push({ rule: "structure", message: `No section about "${required}". Readers look for the decision and the lessons.` });
    }
  }
 
  for (const vague of ["very fast", "much better", "significantly", "blazing", "seamless"]) {
    if (body.toLowerCase().includes(vague)) issues.push({ rule: "vague", message: `"${vague}": replace it with a number.` });
  }
  return issues;
}
draft-lint.test.ts
import { test } from "node:test";
import assert from "node:assert/strict";
import { lintDraft } from "./lib/draft-lint.ts";
 
test("flags a vague draft", () => {
  const rules = lintDraft("# Post\n\nWe made search much better.\n\n## How\nStuff.").map((i) => i.rule);
  assert.ok(rules.includes("lead-with-result"));
  assert.ok(rules.includes("vague"));
  assert.equal(rules.filter((r) => r === "structure").length, 2);
});
 
test("passes a well-structured draft", () => {
  const draft = "# Post\n\nRecall rose from 52% to 96%.\n\n## The decision\nHybrid search.\n\n## What we learned\nMeasure first.";
  assert.deepEqual(lintDraft(draft), []);
  assert.deepEqual(lintDraft(draft.replace(/\n/g, "\r\n")), []); // same draft saved on Windows
});

Then ask a model for the editorial pass, with a structured answer so you get specific, actionable notes instead of a rewrite:

review-draft.ts
import Anthropic from "@anthropic-ai/sdk";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
import { readFileSync } from "node:fs";
import { z } from "zod";
import { lintDraft } from "./lib/draft-lint.ts";
 
const draft = readFileSync(process.argv[2] ?? "posts/draft.md", "utf8");
for (const issue of lintDraft(draft)) console.log(`lint  [${issue.rule}] ${issue.message}`);
 
const Review = z.object({
  oneSentenceTakeaway: z.string().describe("What a reader will remember, in one sentence"),
  notes: z.array(
    z.object({
      quote: z.string().describe("The exact passage, at most 15 words"),
      problem: z.enum(["unclear", "unsupported-claim", "missing-context", "jargon", "too-long"]),
      suggestion: z.string().describe("What to change, without rewriting the passage in full"),
    }),
  ),
});
 
const client = new Anthropic();
const message = await client.messages.parse({
  model: "claude-opus-5-5",
  max_tokens: 4096,
  output_config: { effort: "medium", format: zodOutputFormat(Review) },
  system:
    "You are an experienced technical editor. Find the passages a busy engineer would find unclear, unsupported, or too long. Do not rewrite the post and do not change the author's voice. At most 8 notes, most important first.",
  messages: [{ role: "user", content: `<draft>\n${draft}\n</draft>` }],
});
 
const review = message.parsed_output;
if (review) {
  console.log(`\ntakeaway: ${review.oneSentenceTakeaway}\n`);
  for (const n of review.notes) console.log(`[${n.problem}] "${n.quote}"\n  → ${n.suggestion}`);
}

If the model's one-sentence takeaway is not the one you intended, your draft's structure is the problem, not the model.

Where to publish#

  • Your own site for the canonical version (you own it, and it links to your portfolio).
  • The project README with a short summary and a link.
  • LinkedIn or a community forum with a 5-line version: the problem, the number, the decision, one lesson, and the link.
  • Talks at meetups: the same structure works as a 10-minute talk, and the slides are mostly your tables and diagrams.

Common mistakes#

  • Feature lists instead of decisions. Nobody remembers features; they remember why.
  • Burying the result. If the number is in the last paragraph, most readers never see it.
  • Generated prose. It reads as filler and costs credibility. Write it yourself; let AI edit.
  • Sharing confidential details. For work projects, anonymize data and get permission; focus on the reasoning.
  • Waiting for perfect. A clear, honest post about a small project beats an unpublished masterpiece.

Try it

Write one case study this week

  1. Pick your best project and fill in the five sections in bullet points only.
  2. Write the first paragraph so it contains the problem and one number. Draft the rest in under two hours.
  3. Run lintDraft and review-draft.ts on it, fix what matters, and publish it with a link from the project README.

Check your understanding

What is the most important section of a technical case study?
Where should the main result appear?
How should you use AI for writing about your work?

Key takeaways

  • Structure write-ups around a decision: problem, constraints, decision with alternatives, results, lessons.
  • Lead with the result, use tables and diagrams, and replace adjectives with numbers.
  • Write the draft yourself; use a lint and a model as editors, not authors.
  • Publish on your own site and share short versions where your audience is.

Next steps#

Finished this article? Track it to see your progress on the roadmap.