postmortem-prose:用寫事故復盤的方式,寫技術長文
這是一份個人風格指南,別當通用最佳解拿去套。它記錄一個 SRE 怎麼寫自己的技術長文:規則是我的偏好(例如中文零破折號)、教訓是真的踩過的。拿去用時,把 persona 與偏好換成你自己的。
一句話目標:讓文章讀起來像一個資深 SRE 在寫事故復盤/技術筆記:直白、有意見、敢下判斷、一句講一件事、用具體踩雷的語言,把「資訊密度過高的正確資訊堆疊」那種 AI 味洗掉。
§0 核心診斷:讀者說的「AI 味很重」,病灶在句子層級
這是全篇的總綱,其餘規則都是它的展開。
真實回饋長這樣:內容很有料、被稱讚有判斷力;但句型、用詞、敘述方式讀起來像 AI:生硬、資訊密度太高、難消化。而且讀者講不出哪裡像,只有「感覺」。
所以去 AI 味動的是句子,內容通常留著就好。目標聲音:
| 要 | 不要 |
|---|---|
| 直白、一句講一件事 | 一句塞三個觀念、資訊密度爆表 |
| 敢下判斷、有意見(「這不叫工程,比較像任性」) | 什麼都 hedge、四平八穩 |
| 具體踩雷語言(「為什麼按鈕是黑的,花了我一個下午」) | 抽象、教科書式定義堆疊 |
| 主動降低每句密度:長句拆短、留呼吸 | 每段都是高潮、讀者喘不過氣 |
§1 硬規則(零容忍,每次潤稿後 grep 驗證)
1.1 破折號:分 genre 的矩陣
技術長文(本 skill):中文一律不用破折號。 用冒號、逗號、分號、括號或拆句代替。這條也適用「我自己給使用者的中文回覆」,不只文章。英文的 em dash 是標準標點、可保留(英文拿掉反而生硬)。
跨 genre 對照(避免搞混,我搞混過很多次):
| Genre | 中文破折號 | 英文 em dash |
|---|---|---|
| 技術長文(本 skill) | 不用,改標點/拆句 | 可用(標準英文) |
| 社群貼文/release 宣傳 | 不用 | 不用 |
| GitHub PR·issue 內文 | 不用 | 可用但克制,且用真 unicode — 不用 -- |
| landing 網頁文案 | 可用 | 可用 |
若某 genre 真的要用中文破折號,一律用「——」(U+2014×2 全形雙格),不可用單個「—」、連字號、或為避開而硬改成逗號。一般 hyphen(
sub-agent、per-session)不受此限。
1.2 中國用語=零容忍,一律台灣用語
每次潤稿後對整份 grep 掃一遍:
| 中國用語 | 台灣用語 | 中國用語 | 台灣用語 | |
|---|---|---|---|---|
| 代碼 | 程式碼 | 默認 | 預設 | |
| 進程 | 行程 | 信息 | 資訊 | |
| 函數 | 函式 | 質量 | 品質 | |
| 數組 | 陣列 | 軟件 | 軟體 | |
| 字符串 | 字串 | 用戶 | 使用者 | |
| 內存 | 記憶體 | 報錯/報紅 | 出錯/變紅 | |
| 性能 | 效能 | 視頻 | 影片 | |
| 緩存 | 快取 | 屏幕 | 螢幕 | |
| 調用 | 呼叫 | 支持 | 支援 |
1.3 全形標點
zh 一律用全形:,。:;、!?「」『』(),不用半形 , . : ( )。英文字/程式碼識別字之間照常用半形。
1.4 其餘硬規則
- 不用 emoji、不用行銷腔與浮誇詞(「超」「感動」「🚀 revolutionary」都不要)。熱情 ≠ hype。
- 先讓讀者認識產品,再講技術(這條是致命傷等級)。開頭先用具體畫面講清楚「它是什麼、長什麼樣、能幫使用者什麼」(配 hero/popover 截圖、列可見的 UI 表面),再進 FFI/架構。否則整篇變成「為一個我不認識的東西在炫技」。
- 事實一律對原始碼/來源查核,零虛構。數字、函式數、版本、程式碼片段都要對得上 repo。(教訓:外部 AI 校稿把 macOS 26 改成 15=引入錯誤、還幻覺兩個不存在的錯字。外部 AI 建議只是輸入,逐條驗過才能用。)
- 正文不留內部草擬痕跡:拿掉「撰寫中草稿」標記、
[圖片]預留、<!-- 內部註解 -->、章節 [TODO]。也不要破第四面牆(「順便澄清 outline 草稿寫錯的事」這種只有作者知道的指涉,讀者出戲)。 - staged/模擬的截圖一定在圖說標「示意」,不可讓讀者誤以為是真實版本/真實 release notes。
§2 句子層級的去 AI 味(§0 的具體手法)
2.1 避開 AI 對比句型
不是⋯而是⋯ / X,不是 Y 這類對比句,神經敏感的讀者一眼判定「AI 寫的」,即使單句本身沒問題也有「味道」。打散、換句話說:
✗ 我的安全網是紀律,不是 backstop。
✓ 這裡沒有兜底的 backstop。真正撐住邊界的,是紀律。
少量真有修辭力的可留,但別整篇都是。
2.2 中文避免英式 staccato(過短句+句號)
一鍵。 夠簡單了。 macOS 14 以上。 這種極短句配句號,在中文讀起來很突兀(英文反而是力道)。用逗號把短句串成流動的長句。
- 判準:一句話中間沒有逗號、直接接句號、≤ 約 18 字=要排除。
- 修法:預設用冒號/逗號併入鄰句(題目句用冒號帶出說明最自然),或改成獨立一行不加句號,或用驚嘆號。
- 例外:deliberate 的格言式收尾可保留(「先探測,再解析。」)。英文不受此限。
2.3 不要 meta-announce 結構/濃縮
一句話: 好問題,我們來把它拆開看。 重頭戲來了 這種宣告式開場是冗詞。連問兩句讀者就知道你在設問,直接給答案;想濃縮就直接濃縮,別先宣告「我要濃縮成一句話」。
2.4 關鍵技術名詞要解釋
對不熟 Rust/Swift 的讀者,一句塞三個看不懂的名詞會勸退。
- 行內極短註解:
staticlib(靜態函式庫:編譯期連進主程式)。 - 撐起整節論點的大概念(FFI、ABI)用 admonition/blockquote「名詞小抄」(粗體開頭、不用 emoji)。
- density 寧可多一點,每則短到專家能一眼略過即可。
§3 語氣、語調、口吻
- 活潑來自對技術發自內心的熱情:「這個太酷了,我好想讓你也知道」這份情感貫穿全文、感染讀者,是讓人讀得心情澎湃的關鍵。具體:真誠的「第一次看到時我⋯」「我加了一個快取 vs 我想過這個快取」。但仍不用 emoji、不用 hype。
- 敢下判斷、有意見:SRE 的品味在於「知道這個工具不能怎麼壞」。用強觀點開場(「能跑、有測試、踩過真實資料的程式碼,只為了遷就一道語言邊界就丟掉重來,那不叫工程,比較像任性」)。
- 誠實=這類文章的最強武器:
- 主動承認搆不到的天花板(Liquid Glass、
catch_unwind)。 - 大方把功勞給對的人(引擎給上游 tokscale、記憶體優化給貢獻者、程式碼給 AI)。
- 權威靠證據不靠身分:如果作者不是該技術棧老手,就更要用實測數字、測試、觀察建立信任,別用「隱含的專家口吻」撐。每個 claim 掛環境(release build、機型、資料量、樣本次數)。
- AI 協助要揭露,且框成底氣、別寫成道歉:「我不是 Rust/Swift 專家,程式碼大量是 AI 寫的,我的工作是另一半:定義需求、架構原則、失敗邊界、什麼叫『對』,然後不斷 review、退回、修正它的輸出。」這把文章從「FFI 深潛」重定位成「AI 時代的 SRE case study」,更獨特也更難被打。(放開頭、可用
:::info色塊。)
- 主動承認搆不到的天花板(Liquid Glass、
- 克制自我稱讚:
我最想分享/我最得意/我最喜歡的手工這類「最」用多了邊際遞減。留一兩個最重的,其餘拿掉。保留本質謙虛的(「我幾乎要為『沒有自己寫它』感到驕傲」=把功勞給 tokscale)。
§4 節奏
- 設問 → 解答是引擎:先丟一個讀者心裡的問題,再由文章解答,製造「哦,原來是這樣,我看懂了」的著陸點。即使讀者沒全懂,這些斷點會讓他有信心、有興趣讀下去。(「值得嗎?我覺得值得。」這種設問→解答是刻意的聲音,別當 AI 味刪掉。)
- 喘息空間:短段落、signpost(「我們解決了 X,但這帶出 Y⋯」)。技術長文尤其需要。
- 一個議題接一個議題,中間穿插反思與延伸問題,思緒是流動的,別寫成清單。
§5 譬喻
- 精簡、功能性的譬喻可以:「保留引擎,換掉身體」「把韌性焊進每一道接縫」有辨識度,是聲音。
- 過度文藝的比喻會被工程師讀成 AI/矯情:例「一道誠實的傷疤」用一兩次有力,用四五次會從「坦誠」滑向反向炫耀(把限制重新包裝成品味)→ 洗掉,但保留它在講的事實。
- 同一個譬喻別重複太多次(discipline×7、weld×4、battle-tested×3 就太密)。
- 保留翻譯書式的風趣設問(不讀翻譯書的讀者 get 不到也沒關係,那是聲音)。不要學使用者另一個 persona 的「人類噪音」:動漫梗/東方梗埋梗、顏文字 kaomoji,那是別的 voice,不進技術長文。
§6 結構與起承轉合
Genre 定位:這是「工程重寫戰記/case study」,別當 tutorial 寫。它不保證讀者能照著做,它讓讀者認識「你怎麼做這件事、你的工程取捨」。接受這個定位,長度與密度就有正當性。
起承轉合
- 起:產品是什麼+為什麼要做(§0)。一句話論點壓成標題(「Rust 的引擎,Swift 的外殼」)=開場就回答一個工程決策。
- 承:埋一個硬限制當種子(§1「靜態 library 沒有自己的背景迴圈」),明說「到 §3 你會看到它逼出我最在意的設計」。
- 轉:在後面的章節解開那個限制(§3 用惰性 tick 回答 §1 的種子)。每一節=拆解論點裡的一個動詞。
- 合:§9 回到開頭的一句話論點,逐條收束(留住引擎/最小 FFI/焊進韌性)。
版面順序
- 頂部 metadata bar(日期 · 閱讀時間 · 標籤)。閱讀時間要誠實(30 分的長文別標 15 分)。
- 先講結論/TL;DR:一句話論點 + before/after 數據表(呼應數據導向)。
- (AI 協助很深時)緊接一段定位句(§3,可
:::info)。 [TOC]+ 一句 reading guide(「想看 FFI 讀 §2–3、想看正確性讀 §4–5」)降低長文門檻。- 各節之間用
---分隔。 - 接近結尾放一段「誠實的邊界/還沒解」:本機 log 不是計費真相、沒量常駐 CPU/冷啟動/電池⋯。這比第五個「傷疤」更能建立可信度。每個問題都配一個漂亮解法,反而降低可信度。
- 結尾「延伸閱讀」footer。
- 每個 claim 收斂到情境:「在這個資料量/更新頻率下成立的選擇」,不要寫得像「JSON FFI 是最佳解」的 definitive guide。
- 圖片 caption 寫「這張圖告訴你什麼」而非只描述。
§7 排版鐵則(HackMD/部落格皆安全)
- 段落一段一行、不硬斷(HackMD
breaks: true把單一換行當<br>,硬斷會跑版)。 - 圖一律用 Mermaid,不要手繪 ASCII art(CJK 全形字與等寬 ASCII 對不齊,必跑版)。平台不吃 Mermaid 再 export SVG/PNG。
- 強調框用 HackMD admonition:
:::info(藍,context/名詞小抄)、:::success(綠,核心論點)、:::warning(黃,硬限制/鐵則)、:::danger、:::spoiler。色塊前後必須留空行;別在一段裡疊太多色塊。 - 複雜的部分轉 md-style 圖表(流程→ Mermaid、多欄比較→表格),列點是最後手段。
- 標題獨佔一行、前面留空行(
## §N黏在前一句同一行不會被 parse 成標題;ATX 標題前缺空行很脆弱)。 - mermaid label 用純文字(
at least 10s),別用≥之類 HTML entity(HackMD 可能渲染成字面)。
§8 雙語(zh + en)紀律
- 平價(parity):兩版說同一件事、同樣的數字與 claim,別讓版本漂掉(雙語文章最常見的 bug)。
- 標點按語言各自處理:中文不用破折號、英文 em dash 可留;中文全形、英文半形。
- 中文的 inline 名詞註解密度可比英文高一點(對中文讀者是對的選擇)。
- 改動要成對:改一版就對照改另一版,並確認數字沒有單邊漂移。
§9 潤稿 SOP(使用者拍板「這 SOP 很好」)
Gemini(agy CLI,出 SRE 口吻、去 AI 味的草稿)
→ Claude 守門(修回作者的聲音/母題、清掉中國用語、補回被漏掉/改掉的事實數字)
→ grep 驗證 0 中國用語 + 0 中文破折號
→ 使用者過目
→ 才走 HackMD 推送流程
關鍵:Gemini 分不出「作者刻意的聲音」與「AI 味」(會把設問→解答、傷疤母題當 AI 味刪掉),所以 voice 守門必須 Claude 來。校準目標 voice 的依據=爬鐵人賽+知名技術 blogger 抓的共同點。
agy(Gemini CLI)工法:大檔不要 inline 進 prompt(68KB 會卡死十幾分鐘);改 --add-dir <dir> 讓它自己讀檔(小 argv 繞過卡點)。Gemini 3.5 Flash (High) 可用且快;多輪用 -c(continue,保有全文 context);每次跑前後 md5 -q 比對證明它沒改到檔(純建議模式)。macOS 無 timeout(用 gtimeout 或 Bash 工具自身 timeout)。
§10 對外部 AI 校稿的紀律
外部 AI(Gemini、ChatGPT reviewer⋯)的評價只是輸入,逐條對原始檔/程式碼查核後才能採用:
- 會幻覺硬錯誤:把 macOS 26「訂正」成 15(反而引入錯誤)、宣稱有兩個不存在的錯字。
- 會讀到舊版:它戳「我最X 太多」時,那些其實我上一輪已軟化;它戳「mtime 假設沒講」時我已補了。先確認線上現況再回應。
- 會講過頭 / 高估:說「誠實傷疤四五次」實際是三次。
- 但真戳中的要認:TokenBar 這篇被戳得最準的一項=「沒有
catch_unwind又沒設panic = "abort",panic 跨 C ABI=UB」,這是真洞,補一行panic = "abort"就解決。
分類:哪些已修、哪些真開放值得做、哪些我不同意/它講錯、哪些要使用者給資訊。
§11 HackMD 發佈機制(ops)
- API token 放本機檔案、不進版控(讀取只 inline、不印不存)。API base
https://api.hackmd.io/v1;GET /me驗證、GET /notes列表、PATCH /notes/{id}body{"content": 全文含 frontmatter}。 - 雷一:請求 body 上限約 100KB,
json.dumps預設ensure_ascii=True會把中文轉\uXXXX灌爆成 102KB → 413。必須ensure_ascii=False再.encode('utf-8')。 - 雷二:curl 要用
--data @body.json+ 純Content-Type: application/json;用--data-binary+charset=utf-8會回 500。 - PATCH 回 202、無 body;推完用
GET /notes/{id}抓回比 md5 驗證(比/download可靠、無 CDN 快取)。 - 邊改 live 邊潤=推前務必重抓 live 當基準+drift 防護(GET 比對 base,不符就 abort 不蓋,保住使用者線上手改)。
- 圖片:本機圖用
hackmd.io/_uploads/...,潤稿只動文字、URL 一字不動;改動前後驗證_uploadsURL 集合不變。
§12 Genre 邊界(別把本 skill 套錯地方)
本 skill 是技術長文。同一個人在別的場合語氣不同:
- 社群貼文/release 宣傳:更克制、無 emoji、數據導向、CTA 極短、不用任何破折號。
- GitHub PR/issue:預設英文、套 [[md-style]](表格/blockquote/code 優先於列點)、回 AI reviewer 不寫社交肯定(「Good catch」等)、開頭 @對方。
- landing 網頁文案:可用 em dash。
附錄:發佈前快速 checklist
-
grep0 中國用語、0 中文破折號、標點全形 - 無 emoji、無 hype 詞、無
不是…(而)是對比句(含省略「而」與倒裝「是X,不是Y」的變體)、戲劇化譬喻不重複 - 開頭先講「產品是什麼」+ TL;DR 數據表+(AI 協助則放定位句)
- 每個數字掛實測環境;claim 收斂到情境、非 definitive guide
- 有「誠實的邊界/還沒解」段;功勞歸對人;AI 揭露框成底氣
- 設問→解答的節奏、短段落喘息;自我稱讚「最」留一兩個
- 標題獨佔一行+前後空行;admonition 前後空行;圖用 Mermaid
- 雙語 parity:數字/claim 不漂移;標點各語言各自處理
- 內部草擬痕跡清乾淨;staged 截圖標「示意」
- 事實逐條對 repo/原始碼查核(含外部 AI 校稿建議)
- 推 HackMD:
ensure_ascii=False、drift 防護、md5 readback、_uploads不變