Refactoring English: Month 9

Michael Lynch

Refactoring English(《重構英文》):第 9 個月

一句話總結

剪輯影片訪談的喜與憂

重點整理

  • 我從早期讀者那裡獲得了關於章節清單的實用回饋。
  • 剪輯訪談影片的過程令人沮喪,但製作文字逐字稿卻很有趣。
  • 我推廣自由接案部落格編輯服務的計畫,成果比預期更好。

目標成績單

每個月月初,我都會宣告本月想完成的目標。以下是我達成目標的情況:

寫個人化電子郵件給 20 位從未交流過的讀者

和幾位讀者聊過後,我意識到現階段更好的策略是進行對所有讀者進行的廣泛問卷調查

發布《重構英文》的新章節

  • 結果:已發布「Get to the Point」
  • 成績:A

我終於完成了關於引言的章節。這是最難寫的一章,因為引言是我覺得寫作中最具挑戰性的部分。所以,這既是一篇關於引言的文章,也是我試圖逆向拆解自己如何撰寫引言的嘗試。

這一章我也嚴重超支。原本僅編列六小時來完成,但最後卻花了 19 小時。

完成剩餘的行銷任務

  • 結果:完成了訪談剪輯,但尚未完成行動呼籲
  • 成績:B+

我已完成訪談的剪輯,這是尚未完成的主要工作。我還沒空調整書籍網站的設計,將重點從訂閱免費電子報轉為購買搶先體驗版。

《重構英文》數據指標

指標2025 年 7 月2025 年 8 月變化
不重複訪客8,0612,863-5,198 (-64%)
預購收入$800.04$312.63-$487.41 (-61%)
贊助收入$48.25$48.25$0.00 (0%)
總收入$848.29$360.88-$487.41 (-57%)

上個月,我以為書籍的數據表現很健康。儘管沒有熱門的新文章,網站造訪次數和收入都有所成長。

從那之後,我為數據新增了圖表,現在看到了不同的模式。書籍的收入似乎與書籍網站的訪客數密切相關。即使我以為七月沒有熱門文章,但當八月沒有在書籍網站上發布任何內容時,數據卻急劇下滑。

我的結論是,我確實需要持續在網站上發布新內容,才能持續找到新讀者,尤其是願意付費購書的讀者。

解讀讀者對章節清單的回饋

在與讀者的一對一對話中,大家覺得相關的章節差異很大。我覺得更好的做法是發送問卷調查,了解讀者最關心哪些章節。

我原本預期回覆率會很低,因為之前在電子報中徵求回饋時,只收到少數回應。令我驚訝的是,讀者對這次問卷調查熱情得多,兩週內就收到了 133 份回覆。

我在書籍網站上對回覆做了詳細分析:

簡而言之,我獲得了實用的回饋,並據此重新排序了章節,也重塑了一個讀者不喜歡的章節。

這次與以往徵求回饋時的回覆率差異也很有趣。過去我在寄送範例章節後徵求回饋,我認為差別在於我要求讀者付出的工作量。這次問卷調查只需幾分鐘就能完成,而要對某一章節提供回饋,則需要花 30 分鐘閱讀章節並思考,也許你在收到問卷時還沒準備好投入那麼多時間。

剪輯 30 分鐘影片訪談時意想不到的困難

早在 2024 年 7 月,我為了重啟我的寫作課程 Hit the Front Page of Hacker News,錄製了一場與 Adam Gordon Bell(亞當·戈登·貝爾) 的訪談。我在請陪產假前最終沒能完成課程,因此無限期擱置了重啟計畫。

這讓我處於一個尷尬的境地。亞當慷慨地空出時間幫忙,我卻完全沒有發布訪談,心裡感到很過意不去。

當我開始提供《重構英文》的搶先體驗時,我覺得正是發布這場訪談的好時機。如果人們喜歡這場訪談,也許會去看看這本書。

你知道有那種你一直拖延的任務,心裡想著:「我拖了這麼久真是太傻了,只要坐下來做,一小時就能完成,就不用一直放在心上了。」我確信這場訪談就是那種任務。

結果完全不是那樣。

音訊偏移夢魘再度來襲

我使用名為 Riverside 的服務錄製訪談。通話結束後,Riverside 為通話雙方各自產生了影片檔,以及一個合併、同步後的對話版本。我當時抽樣檢查了影片,確認可以播放,但從未仔細觀看。

我以為工作只需要把合併後的版本上傳到 YouTube 就好。也許如果有中斷或冗長的離題內容,我會剪掉,但我以為影片已經接近完成了。

當我一年後終於坐下來仔細觀看影片時,才發現音訊和視訊不同步。在影片中,你可以在嘴唇動作之前就先聽到我們的聲音。

在 Riverside 產生的影片中,音訊和視訊有些微的不同步。

好吧,沒問題。我可以用 FFmpeg 重新處理影片,稍微位移一下音訊。

不行,結果發現對話兩端的音訊偏移量不同。亞當·戈登·貝爾那端的偏移約 425ms,而我的則約 150ms。這意味著我必須回到各自原始、未合併的影片,修正其中的偏移,然後再自行重新合併。

尋找可用的開源影片編輯器

我過去剪輯影片的標準工具是 Adobe Premiere,但去年我改用 Linux 後,Premiere 就無法在 Linux 上使用。而且到了這個地步,我已經對 Adobe 這家公司感到厭煩

我開始在 Shotcut 中剪輯影片,這是我去年夏天開始學習的影片編輯器。要搞清楚如何在 Shotcut 中將兩段影片並排,就花了我一段時間,但我最終用縮放和裁剪濾鏡拼湊出了一個方法。

在 Shotcut 中剪輯時,播放非常卡頓,因為即使在我的相當新穎、高階的桌機上,合併兩段 1080p 影片時還是會卡住。所以,要聽到影片實際的聲音,我必須匯出影片。而 Shotcut 不支援只匯出影片的一部分,所以我每次都要匯出完整的 30 分鐘,每次都要花上好幾個小時。題外話:我後來發現你可以在 Shotcut 中降低播放時的解析度,以在剪輯時獲得更快的效能。

匯出後我注意到,每當我分割剪輯片段時,Shotcut 就會插入一個很大的爆音。即使我實際上沒有在分割點剪掉任何內容,仍然會發生。僅僅是將一個連續的剪輯片段分割成兩個相鄰的剪輯片段,就會產生這種爆音瑕疵。

僅僅分割剪輯片段而不做任何修改,就會在音訊中產生「爆音」。

我發現這些爆音是 Shotcut 中的已知問題,這讓我難以置信。每次分割都會加入干擾性的音訊瑕疵,這樣要怎麼剪輯影片?但許多留言者說,每個影片或音訊編輯工具都有同樣的問題。

什麼?!?

我用其他工具編輯過數百個媒體檔案,從未見過有任何工具會在分割剪輯片段時插入爆音。

我嘗試了其他適用於 Linux 的開源影片編輯工具。Kdenlive 在我嘗試編輯幾分鐘後就當掉了。Flowblade 完全無法載入,但我最終找到一個變通方法。而 Flowblade 看起來像是 Shotcut 的簡化版,所以我又在 Flowblade 中重新開始編輯過程,並得弄清楚如何製作並排影片。

在 Flowblade 中編輯了約一小時後,我嘗試匯出影片,結果爆音又出現了。他們也有一個關於此問題的錯誤回報,而他們對此的理解是基於丹·丹內迪的解釋,而他……正是 Shotcut 的作者。而且 Flowblade 似乎是建構在 MLT 之上,也就是驅動 Shotcut 的同一個媒體框架。所以,我又回到了完全相同的錯誤。

無論如何,這段剪輯歷險記的敘述已經太長又太無聊,所以直接跳到結尾:我最終透過將影片的音訊取樣率從 44.1 kHz 轉換為 48 kHz 來繞過爆音問題。這消除了爆音瑕疵,但我不知道為什麼。

我在剪輯影片時還遇到了許多其他錯誤,但那些都太瑣碎,不值得在這裡贅述。

剪輯影片的心得

  • 盡可能使用 FFmpeg 指令稿進行前處理。
  • 儲存 FFmpeg 指令稿,以備日後需要調整前處理時使用。
    • 即使你非常有把握再也不需要做任何前處理,也要儲存指令稿,最好納入版本控制。
  • 用極端數值測試 FFmpeg 指令稿,確認它們確實如你所想的那樣運作。
    • 我嘗試透過將音訊位移 200ms 來校正音訊偏移,但仍然不同步。接著我試了 300ms,還是不同步。然後是 400ms。我最後直接跳到 2000ms,才意識到指令稿中一定有錯誤,因為 200ms 和 2000ms 的校正聽起來完全一樣。
  • 當你不確定正確設定時,讓 FFmpeg 產生多個不同版本以便比較選項。
    • 我就是這樣測試用來消除我這端對話背景噪音的不同策略。
  • 音訊取樣率為 44.1 kHz 顯然會在剪輯時造成問題。
    • 在前處理期間將取樣率轉換為 48 kHz 可修復爆音瑕疵。
    • 我完全不知道為什麼。
  • 在開始剪輯後盡早嘗試匯出影片,以檢視最終輸出。
  • 將視訊/音訊編輯濾鏡套用在軌道層級,而非剪輯片段層級。
    • 即使你一開始只有一個巨大的剪輯片段,一旦開始剪輯,就會產生數十個具有獨立濾鏡設定的剪輯片段。
    • 如果你發現濾鏡設定錯誤,就得在每個剪輯片段中重新設定。

樂在其中的訪談逐字稿製作

當我完成與亞當·戈登·貝爾的影片剪輯後,應該就大功告成了,對吧?我花了那麼多時間剪輯影片,肯定迫不及待想發布然後收工。

錯了!

完成影片剪輯後,接著就是為逐字稿鑽牛角尖的時候了。不過,這部分我倒是真的樂在其中。

我覺得我在網路上讀到的每一份訪談逐字稿,設計師都像是說:「讓我們把 60 年前的打字機法院筆錄,原封不動地搬到網路上,帶來同等程度的樂趣與互動性。」

如果我們能以某種方式利用網頁瀏覽器,讓對話逐字稿變得更有趣呢?

拜託!讓我們利用網路來做些打字機做不到的事吧。

因此,我用 whisper-ctranslate2 產生了初步的逐字稿,並花了很多時間讓它準確、具互動性且閱讀起來有趣:

我在訪談逐字稿中加入了一些小功能,讓閱讀變得有趣。

  • 對話的每一方都以不同顏色的對話泡泡呈現,因此一眼就能看出是誰在說話。
  • 每個對話泡泡中都有小小的播放按鈕圖示。點擊圖示時,頁面會捲動到影片並從逐字稿中對應的時刻開始播放。
  • 我把最喜歡的引言拉出來做成重點引述。
  • 我加入了標題來幫助呈現討論的架構。
  • 我校對了文字以修正轉錄錯誤。

我還沒發布這支影片,因為我週五才剛寄送新章節給電子報訂閱者。它將會在本週末前(2025-09-12 前)上線到書籍的部落格

幫助泰勒·西普里亞尼登上 Hacker News 第一名

有時候,計畫的成果就是比我期望的還要好。

幫真實的寫作者提供回饋有助於我撰寫本書,因此我一直在為其他獨立開發者部落客提供自由接案的編輯服務。在說明我編輯服務的頁面上,我想放上一個編輯範例,但我不想要求付費客戶將他們已經付費的作品拿來當作我的行銷素材。

所以,我的計畫是找一個願意讓我免費編輯他的文章的人,條件是能公開發布編輯筆記,並讓對方標註我是編輯。

我的延伸目標是讓這篇文章在我的書的潛在讀者可能出沒的地方獲得關注,例如 Hacker News、Lobsters 和 Reddit。如果讀者讀到文章結尾看到「由《重構英文》編輯」的字樣,他們會想:「嘿,那是什麼?」

如果我能指著過去的客戶對潛在客戶說:「你看,這個人聘請了我,而他的文章在你想成功的地方獲得了成功。」這對潛在客戶來說也很有吸引力。

幾個月前,泰勒·西普里亞尼聘請我為他的部落格做高層次的審閱。他似乎對結果很滿意,所以我向他提出了免費編輯的想法,他也同意了。

我與泰勒針對他的文章 「The future of large files in Git is Git」 進行了幾輪回饋。我們合作得很愉快,也為我的書帶來了不少好點子。

我原本的額外目標只是讓文章登上 Hacker News 首頁,但結果遠超預期,一路衝上 Hacker News 第一名LobstersReddit

對我們兩人來說,最大的收穫之一是針對目標讀者調整寫作的重要性。泰勒文章的早期草稿假設讀者熟悉 Git LFS,這是一個用於管理大型檔案的 Git 擴充功能。

我建議,一般的 Git 使用者不一定對 Git LFS 了解得足夠透徹,無法理解文章中的所有內容。泰勒則持不同意見,因為他覺得曾處理過大型檔案的一般 Git 使用者一定知道 Git LFS。

為了讓泰勒相信讀者對 Git LFS 的了解比他文章假設的還要少,我列出了自己對 Git LFS 的認識與經驗:

  • 如果我的 Git 儲存庫中有大型檔案,或我經常在 Git 儲存庫中更新二進位資料,我就應該使用 Git LFS
  • 我從未使用過 Git LFS
    • 我可能曾參與過 1 到 2 個使用 Git LFS 的開源專案,但我從未碰過任何 LFS 相關的部分。
  • 我不知道各種程式碼託管平台(forge)的大小限制是多少,但我假設如果達到了限制,平台會發出警告,到時候再處理就好
    • 如果我想在 Git 儲存庫中儲存超過 5 MB 的檔案,我就會開始尋找避免這麼做的方法
  • 我以為 Git LFS 是一個與託管平台無關的功能,在哪裡都可以使用。
  • 我以為 Git LFS 是一項超過十年的技術,已經成熟且穩定
  • 我不知道一旦開始使用 Git LFS,你的儲存庫就會被它綁住
  • 我會對在 Git 中儲存大型檔案的方法感興趣,也會在 Hacker News/Lobsters 上點開相關的文章,但除非我真的遇到需要在 Git 儲存庫中儲存大型檔案的情況,否則我不會主動去思考並嘗試解決這個問題。

泰勒說,這份清單對他而言是「恍然大悟」的時刻。他之前抗拒這項回饋,是因為他確信讀者會了解 Git LFS。看到我的清單後,他才意識到,即使讀者表面上知道 Git LFS 及其用途,他們可能也不知道它是如何運作的。

泰勒這次領悟的有趣之處在於,他自己本來就能寫出我的這份清單。他對目標讀者會知道什麼有著相同的預測;他只是需要再深入一層思考,讀者「知道」一項技術究竟意味著什麼。

業餘專案

Hacker News Observer 切換至 time-series database(時序資料庫)以獲得 500 倍加速

過去幾年,我聽過人們談論「time-series database」,但我從未理解它們的作用或與一般關聯式資料庫的差異。去年我甚至為了需要與 Grafana 相容的東西而在一個業餘專案中使用了 InfluxDB。但我仍然不明白是什麼讓它成為「時序」資料庫,或者為什麼不能直接用 SQLite 就好。

最近我和另一位開發者聊天,他提到使用 time-series database 來呈現資料的不同視圖,例如秒級粒度與日級粒度的對比。他甚至沒有進一步解釋,但我腦中靈光一現,心想:「喔!那一定就是 time-series database 的用途!」

Hacker News Observer 是一個業餘專案,每分鐘查詢 Hacker News 並記錄過去幾週每則故事的按讚數、留言數和排名。我希望能更深入挖掘並找出有趣的模式,但目前我只是在看高層次的彙總資料,例如首頁的總按讚數和留言數:

切換到 DuckDB 讓這個頁面的載入速度提升了 500 倍

我最初使用 SQLite 作為資料庫,上圖需要兩分鐘才能渲染完成。這也合理,因為每天有數千則故事,每則故事有數千個快照,然後我必須在每個快照中找出前 30 名(首頁),再將它們放入以小時為單位的區間。SQLite 沒有任何特殊函式可將每分鐘的資料彙總為小時級別的視圖,因此需要執行大量昂貴的查詢。

一旦我有了 time-series database 的概念,我便請 LLM 推薦類似 SQLite 的 time-series database 選項,它推薦了 DuckDB。接著我就讓 LLM 將我的資料庫從 SQLite 遷移到 DuckDB。光是這次遷移,就將圖表的載入時間從兩分鐘縮短到 250ms,加速了約 500 倍。

所以,我想這就是 time-series database 的用途吧。

Gleam Chat Log Parser 逐步處理舊日誌

我在這個聊天日誌解析器專案上只取得了一點點進展。我處理了包含暫離訊息的日誌,以及含有 Windows 風格換行符號(\r\n的日誌。奇怪的是,在 Erlang(因此在 Gleam 中也是如此)中,\r\n 算作單一字元,這讓我困惑了一陣子。

總結

完成了什麼?

經驗教訓

  • 在剪輯影片時要更有紀律
  • 剪輯訪談影片很枯燥,但編輯和美化逐字稿卻很有趣。
  • 如果回饋只需要幾分鐘而非 30 分鐘,會有十倍以上的客戶願意提供回饋。

下個月的目標

  • 發布能為《重構英文》網站吸引新讀者的內容。
  • 發布《重構英文》的新章節。
  • 寫個人化電子郵件給 20 位從未交流過的讀者。

原文由 Michael Lynch 發布

本文章由 muse-spark-1.2-contributor 進行翻譯