Refactoring English: Month 1

Michael Lynch

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

一句話總結

我已經發表了本書的第一章。

重點回顧

  • 我發表了本書的第一章,對迴響感到滿意。
  • 聘請書籍封面設計師的嘗試以失敗告終。
  • 我可能已經找到讓 PicoShare 支援大檔案的方法。

目標達成評分

每個月月初,我都會設定當月想完成的目標。以下是本月的達成狀況:

完成《重構英文》的兩個章節

  • 結果:完成一個章節,第二章完成了 75%。
  • 評分:B

第一章花的時間比預期更長,因為我不斷發現想重寫的地方。不過,我發現先休息一週去寫第二章,再回頭修改,確實很有幫助。

與設計師合作完成《重構英文》的封面設計

  • 結果:決定自行設計封面。
  • 評分:C

我與設計師合作到一半就喊停,因為我不喜歡設計的方向。最後決定暫時自己來做封面。

關於完成《重構英文》第一章的想法

我發表了新書《重構英文》的第一章。這一章的標題是「撰寫軟體教學的規則」,內容是根據我多年來跟著各種教學操作,並觀察它們做得好與不好的地方所累積的心得。

第一章獲得超出預期的迴響

這一章的迴響落在我預期的高標。由於內容只是關於教學的規則清單,我原本不認為會在網路上爆紅,但在幾個我認為合適的網站上,確實獲得了不錯的回應:

我主要追蹤的指標是郵件訂閱人數。文章發表後的一週內,新增了 245 位訂閱者,讓本書的總訂閱人數增加了 31%。

第一章讓本書郵件訂閱人數大幅成長。

發表後,該如何迭代修改文章才是正確的做法?

幾年前,Redis 的創造者 Salvatore Sanfilippo(薩爾瓦托雷·桑菲利波)暫停了程式開發工作,轉而撰寫一部科幻小說。在創作過程中,他觀察到

我認為寫作與程式設計最顯著的差異在於,小說一旦寫完、編輯並定稿,大致上就會保持不變。

薩爾瓦托雷接著說,程式設計師應該向小說家學習,克制在應用程式完成後重寫核心邏輯的衝動。但我卻得到了相反的啟示:作者應該像程式設計師一樣,用更迭代的方式來寫書。

對於《重構英文》,我試著以接近完稿的狀態發表各個章節,但同時也希望讓讀者的回饋來形塑我的寫作。

讓章節內容持續處於變動狀態,帶來了我以前從未遇過的問題:我把留言串搞亂了。在 Hacker News、Lobste.rs 和 reddit 上,留言者針對我「讓電腦來評估條件邏輯」這個觀點提出不同意見。我認為他們是對的。那是我最薄弱的論點,所以我已經將它刪除。

問題在於,之後閱讀那些討論的人會感到困惑,不明白為什麼大家在反對一個文章中根本不存在的觀點。

我目前能想到最好的解決方式,是在文末加上備註,說明本書仍在修訂中,並附上原始版本的連結以及重要修改的清單。

該如何持續找到願意提供回饋的讀者?

到目前為止,我覺得根據讀者回饋來迭代的計畫運作得不錯。

我對第一章發表的內容感到滿意,同時也收到了許多讀者深思熟慮的批評,這些都有助於我後續的修訂。

我心想:「好吧,我可以繼續在那些相同的管道分享預覽章節。」

接著,我檢視了目錄,才發現其他章節都不適合我分享第一章的那些管道。那些網站大多有明文或不成文的規定:「如果文章裡沒有程式碼,就不屬於這裡。」舉例來說,/r/programming 的讀者大概不會對我充滿熱情地剖析為何討厭被動語態的章節感到興奮。

我想到的一個點子是,為其他寫作者提供自由接案的編輯服務,並將這些經驗回饋到《重構英文》中。

不過,我覺得「編輯」並不完全是我擅長的。人們聽到「編輯」,會以為我會幫他們潤飾文章。但我真正想做的是,找出他們寫作中的問題,並說明相關的原則與技巧,幫助他們自己提升。我不知道該怎麼稱呼這種角色。寫作導師?教練?

無論如何,如果你對此感興趣,歡迎與我聯繫。我可以協助你處理部落格文章、文件,或任何與軟體相關的寫作。我可以教你如何吸引更多讀者、讓寫作更引人入勝。基本上,如果你喜歡我在這個部落格上的寫作風格,我可以向你展示我在此使用的技巧。

  • 兩輪審閱收費 100 美元。
    • 費用包含我審閱你的初稿,以及根據我的回饋審閱你修改後的版本。
  • 文章長度最多可達 2,500 字。
  • 收費主要是為了讓你更有投入感,所以如果 100 美元超出你的預算,或許我們還是可以商量出其他方式。

透過 Reedsy 聘請書籍封面設計師的不愉快經驗

11 月時,讓我分心而無法專心寫書的一件事,就是說服自己需要一個專業設計的封面。我在 11 月開始進行這件事,但實際工作是在 12 月發生的。

我是透過 Reedsy 找到設計師的,這是一個在 Write Useful Books 社群中多人推薦的平台。大家普遍的評價是價格偏高,但值得。

我寫了一份設計需求說明,解釋我想要的內容,並將它寄給 Reedsy 上的四位設計師。我列出的預算是 350 至 650 美元。有一位設計師的報價比我的最高預算高出 20%,回覆也只是罐頭訊息:「當然,我可以幫你做。」完全看不出他有讀過我的需求說明。另一位設計師則以預算太低為由婉拒,還有一位完全沒有回應。

唯一一份有效的報價來自 Gary(蓋瑞),他開價 350 英鎊(434 美元)來設計封面。他寄來一封用心的回覆,提到了我需求說明中的細節,他的作品集裡有數十個書籍封面,而且在 Reedsy 上擁有完美的 5.0 分評價。他提出為期一個月的時程,費用分三期支付。這聽起來很合理,所以我就聘請了他。

與蓋瑞的合作過程

過了一週,我都沒有收到蓋瑞的消息。在第一筆款項被自動扣款後,我詢問初稿的預計完成時間。蓋瑞說他隔天就會寄來設計概念,他也確實這麼做了。

透過 Reedsy 聘請的設計師所提供的初始書籍封面構想

範例 1 看起來不錯,但幾乎是直接抄襲我在需求說明中提及的Beautiful Code(《程式之美》),手法相當明顯。我覺得其他範例都差強人意,但我把原因歸咎於自己沒有在需求說明上花更多時間。

在檢視這些構想時,我意識到自己真正想傳達的是細心、審慎工作的意象。我覺得禪意庭園的範例 6 和黏土模具的範例 5 方向正確,所以請他深入發展這兩個方向。我建議使用雕刻家雕刻石頭的意象。

又過了一週,蓋瑞寄來了禪意庭園構想的一個微小變化版本。他也嘗試了雕刻家的概念,提供了一張顯示鑿子與原石的圖片。但照片中的石頭完全沒有被雕琢過,因此無法傳達細心工作的意象。

接下來的一週是聖誕節,我開始擔心專案無法在 12 月 30 日的截止日前完成。蓋瑞在聖誕節前的週一寄 e-mail 給我,說他會在 12 月 27 日恢復工作,所以進度仍然正常。

到了 27 日下班時,我仍未收到蓋瑞的消息,才意識到自己陷入了有點棘手的處境。

以我的美國東部時間來看,當時是週五下午 4 點,但蓋瑞在英國,他的上班時間早已結束。Reedsy 將在週一東部時間中午自動向我收費。而 Reedsy 允許對帳單提出爭議的最後期限是扣款前 24 小時,因此我已經沒有任何工作天可以取得完成的作品。

我請 Reedsy 的客服將我的最後一筆付款延後一週,因為蓋瑞尚未交付作品。Reedsy 卻告訴我必須自行與蓋瑞協商。我解釋說,如果等到下一個工作天才收到蓋瑞的回覆,就來不及異動付款了。但 Reedsy 客服仍堅持要我先試著與蓋瑞解決。

我在週五美東時間下午 5 點寄 e-mail 給蓋瑞,他回覆說自己不是朝九晚五的「上班族工時」,所以週末加班仍可在期限內完成專案。作為通融,他幫我延後了付款,但似乎對我向 Reedsy 客訴感到不悅。

相對地,我則盡量維持固定的工作時間,並不想花整個週末陪蓋瑞趕工完成這個專案。週一我再查看時,蓋瑞已針對兩個構想寄來更新,但兩者都相當平庸。一個看起來明顯是 AI 生成且不切實際,另一個則完全沒有捕捉到我要求的氛圍。

我詢問蓋瑞這些圖片是否為 AI 生成,以及是否符合我在需求說明中指定的授權要求。他在這時變得含糊其詞,因此我提出取消專案。我提議讓他保留我已支付的 231 英鎊(287 美元),若他同意取消最後一筆付款並終止專案。他答應了,事情就此結束。

我給了蓋瑞各項 3 顆星的評價。我不覺得他很糟,只是表現平庸,且在時程溝通上做得很差。我的評價是公開的,但 Reedsy 仍顯示蓋瑞擁有完美的 5.0 分評價,即使我給了他 3.0 分,而他總共只有另外四則評價。

儘管我給了蓋瑞 3 顆星的評價,他在五則評價中仍顯示為完美的 5.0 分。

我自製的書籍封面

在不再與蓋瑞合作後,我決定嘗試自己製作封面。我在 Unsplash 上找到一張免版稅圖片,捕捉到了寧靜、細心工作的精神,並加上了一些文字。

我知道它看起來有點業餘,但滿意度大約是我對蓋瑞作品預期的 80%。而且這是免費的,只花了我一個小時。我將它視為暫時的替代方案,日後隨時可以再請人設計或投入更多時間。

支線專案

讓 PicoShare 支援大檔案

PicoShare 是我開發的一款極簡、易於自行架設、用於在網路上分享檔案的網頁應用程式。我在幾年前建立了它,並且每週都會使用。

關於 PicoShare,讓我有點不好意思的是它在處理大檔案時的擴展性很差。在一台配有共享 CPU 與 256 MB 記憶體的虛擬機器上,PicoShare 對於約 1 GB 以內的檔案運作良好。如果嘗試上傳超過 1 GB 的檔案,PicoShare 通常會耗盡記憶體並當機。雖然可以靠增加硬體資源來解決,但如果 PicoShare 能支援任意大小的檔案上傳會更好。

我已經深入研究這個問題好幾次,強烈懷疑效能問題的根源是 PicoShare 將所有檔案資料都儲存在 SQLite 中。這是個不尋常的選擇,但意味著 SQLite 資料包含了應用程式的完整狀態,包括檔案資料。因此,我認為發生的情況是 PicoShare 嘗試寫入大量資料到 SQLite,耗盡記憶體後當掉。

我一直很好奇是否可以使用SQLite 的 streaming I/O APIs(串流式 I/O API),因為它們似乎能讓我更有效率地寫入資料庫。但 PicoShare 是用 Go 寫的,而我使用的 Go SQLite 驅動程式並不支援 streaming I/O APIs。

幸好,Nuno Cruces(努諾·克魯塞斯)發表了一個全新的 Go 用 SQLite 驅動程式,支援 streaming I/O,並且主動提出協助我將 PicoShare 移植到他的函式庫上。我在 9 月時與他合作了一小段時間,也取得了一些進展,但我們發現即使使用 streaming I/O,PicoShare 在處理大檔案時仍然會耗盡記憶體。

努諾建議,如果我將檔案拆開並分塊寫入 SQLite,或許可以降低記憶體使用量。我其實在目前的實作中已經這麼做了,但不同的 streaming I/O 語意意味著我必須重寫大量精細的程式碼。因此,我在那時就後繼無力,暫時擱置了這項工作。

12 月時,我以全新的視角重新檢視 streaming I/O 的問題。我意識到分塊問題比我想像中簡單。PicoShare 在寫入大檔案時會耗盡記憶體,但在讀取時不會。因此,我只需要用更有效率的 streaming APIs 重新實作寫入的部分。

事實證明,使用 streaming I/O 分塊寫入檔案,比我用 SQLite 預設 API 實作的方式更簡單。我原本以為最簡單的做法是用一個 io.Writer 物件來抽象化 SQLite 資料庫,然後讓 io.Copy 把資料傾倒進去。但這一次我意識到,如果直接執行所有寫入而不透過 io.Copy,反而更簡單。

streaming I/O 版本在我的有限測試中表現穩定,但我仍需進行更廣泛的測試。目前的障礙是家裡的上傳速度非常慢,因此我一直在研究如何在 fly.io 上運行桌面作業系統,並透過 VNC 遠端存取。

總結

完成了哪些事?

經驗教訓

  • 聘請平面設計師的要點
    • 在聘請專業人士之前,先考慮自己做一個暫時的替代版本。
    • 將付款與專案里程碑掛鉤,而非日期。
    • 明確說明你是否接受設計師使用 AI 生成的圖片或 AI 輔助的影像合成。
    • 明確要求查看第三方素材(如照片或字型)的授權資訊。
      • 我在需求說明中曾說所有素材都必須具備相容的授權。
      • 更理想的做法是要求承包商必須提供授權資訊,而不只是口頭保證所提供的素材符合授權。
    • 不要規劃在聖誕節剛結束就截止的專案。
    • Reedsy 的體驗設計明顯偏袒承包商,而非客戶。

下個月的目標

  • 發表我的 2024 年度回顧部落格文章。
  • 完成本書的另一個章節。
  • 根據讀者回饋修訂我的教學章節。

徵求協助

  • 如果你有興趣聘請我協助你的寫作,歡迎與我聯繫

原文由 Michael Lynch 發布

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