Paternity Leave: Month 3

Michael Lynch

育嬰假:第 3 個月

一句話總結

逐步回歸工作。

亮點

  • 身為新手爸爸,我越來越能平衡時間。
  • 我曾為兩篇部落格文章表現不佳而鬱悶,後來它們卻獲得了不錯的迴響。
  • 我嘗試了 stacked diff(堆疊式差異) 工作流程來開發軟體,除了 Git 的弱點之外,整體體驗還不錯。

目標評分

每個月一開始,我都會訂下想完成的事。以下是本月的達成狀況:

享受家庭時光

  • 結果:與妻子和兒子共度了愉快的時光。
  • 評分:A

提醒自己很有幫助:即使看似有很長一段時間沒工作,那也是我自己的選擇,而且我的時間大致上仍在掌控之中。

我仍在尋找工作與家庭時間之間的最佳平衡,整體感覺也越來越好。

發表我的 Nix fuzz testing(模糊測試) 教學

逐步回歸工作

當我坐下來寫這篇回顧時,對於沒時間工作的焦慮彷彿已是很久以前的事。我以為那應該是兩個月前的事了,因此當發現那其實就是上一篇回顧時,感到相當意外。

幸好,我對於與家人相處時間的分配,現在感到放鬆許多。我享受了許多家庭時光,同時也發表了比以往更多的文章

幾個影響因素如下:

兒子晚上睡得更好了

他一開始每晚會醒來三、四次,每次醒來都要吃奶 60 到 90 分鐘,但現在每晚只會醒來兩、三次,而且能在 15 到 60 分鐘內重新入睡。

昨晚,他睡了整夜(7 小時 45 分鐘),令人非常開心。

家人提供了更多協助

隨著兒子漸漸長大,我們也更放心讓家人來家裡、在我們不在時照顧他。我們現在每週約有五小時的幫忙,而且這個時數可能會持續增加,因為家人們其實願意提供比現在更多的協助。

兒子可以在我工作時小睡

當有人抱著他或把他放在胸前背帶裡時,兒子會睡得比較久,所以我通常每天會把他抱在胸前工作一到三小時。這也能讓我太太喘口氣,因為她能連續幾個小時擁有自己的時間。

我有了固定的工作時間

我發現要在不固定的作息下工作很困難。即使有許多時間是我太太在照顧兒子,或是兒子在我胸前睡著,知道他們可能隨時需要我,就會讓我難以專心。

我太太主動提出每天給我一段 90 分鐘不受打擾的專注時間,這對提升專注力很有幫助。知道每天都有這段時間,也讓我能把需要高度專注的任務保留到那個時段處理。

我是否在部落格文章上投入過多?

我以前有個壞習慣:每當學到困難的東西,就覺得一定要寫一篇部落格文章來解釋它。

我會盡力把每篇文章打磨到最好,即使那篇文章的受眾非常小,或我根本沒有管道接觸到讀者。先前的例子包括「聘僱內容寫手:小型企業指南」(有受眾,但我沒有好的觸及管道)和「零程式碼改造應用程式以支援雲端儲存」(非常小眾,除了我那個特殊的使用情境外,幾乎沒人感興趣)。

我曾和一些表示喜歡那些文章的讀者聊過,但我也必須考慮機會成本。在寫那些文章的時間裡,是否還有另一篇文章能觸及更多讀者、或在整體上提供更大的價值?

此後,我在發文策略上變得更有規劃。如果我認為一篇文章無法觸及足夠多的讀者,我要嘛不寫,要嘛就在我的「Notes」專區寫一個快速簡易的版本。

「使用 Nix 對 PDF 解析器進行模糊測試」

對於在這篇文章上投入的時間,我感到有些矛盾。

寫這篇文章讓我學到了很多關於 Nix 和 fuzz testing 的知識,但花的時間比我預期的久。一開始我想:「喔,幾個小時就能快速寫完」,結果最後花了 20 多個小時。

在大型語言模型當道的時代,寫軟體教學也令人沮喪。直到幾年前,教學文還有長期的回報,因為人們之後會透過網路搜尋發現它們。如今,如果我寫一篇小眾教學,LLM 只會直接拿走我寫的內容,而讀者根本不會知道那是出自我手。

「我的第一次退場教訓」

我從一開始就知道這是一篇有風險的文章,因為有幾個不利因素:

  • 內容是關於出售公司的繁瑣細節,而我有 99% 的讀者根本沒打算這麼做。
    • 我上一篇關於出售的文章獲得了迴響,但那是一個故事,所以即使讀者本身沒興趣親身經歷,也能享受閱讀的過程。
  • 文章超級長。
    • 我的目標是每篇部落格文章的閱讀時間約 10 分鐘,而那一篇估計要讀 33 分鐘。
  • 唯一一個比較有機會獲得關注的社群媒體管道是 Hacker News。

我把它投稿到 Hacker News,但完全沒有上首頁。

我認為它在 Hacker News 上仍有不錯的機會獲得關注,但就算完全沒迴響,我還是很慶幸寫了它。它幫助我自己釐清了這次收購的過程,未來若再出售另一家公司,也會是很有用的參考。我也從經歷過收購或正在考慮收購的創辦人那裡,得到了正面的回饋。

而突然間,那些文章獲得了關注

在寫完上述內容後,我發現Hackaday 報導了我的 Nix 模糊測試教學,這讓人感到肯定。

接著,在我寫完「我的第一次退場教訓」反應冷淡那一節的隔天,有位讀者再次將它投稿到 Hacker News,結果衝上了第 2 名

不過,我認為我最初的分析還是正確的。我在模糊測試那篇文章上投入過多,而在那篇關於出售 TinyPilot 的文章上則投入得恰到好處。

透過 stacked diffs 實作大型功能

過去幾週,我大部分的業餘程式設計時間都花在ScreenJournal 上,這是我開發的影視評論網頁應用程式。它的概念類似 Letterboxd 或 Goodreads,但評論僅對你的朋友可見,而且程式碼是開源的。

使用者在 ScreenJournal 上評論《Weird: The Al Yankovic Story》的動畫示範

ScreenJournal,我的開源影視評論網頁應用程式

我一直希望 ScreenJournal 同時支援電影和影集,但我先實作了電影,因為比較簡單。我刻意沒有把程式碼通用化到支援影集。因為不確定未來是否真的會做,所以我想先針對已有的功能做最佳化。

10 月時,我新增了對影集評論的支援,因此必須修正程式碼庫中許多假設評論一定是針對電影的邏輯。

那次完整的變更最終達到了 2k 行程式碼,放在單一 changelist(變更清單) 中有點難以理解。我使用「changelist」這個詞,但以 GitHub 來說就像 pull request,以 GitLab 來說則像 merge request。

過去,我處理這類大型變更的方式是開一個功能分支,在完成功能前它都處於損壞或未完成的狀態。我要嘛直接在該功能分支上修改,要嘛再從該分支開出子分支來處理子任務,完成後再合併回來。

這種做法的問題在於,功能分支會變成一大團難以理解的變更。你可以在我將 What Got Done 從 Firestore 遷移到 SQLite 的例子中看到這一點。那次變更中有許多子步驟,但因為全部混在一起而無法逐一檢視。

因此,對於這次 ScreenJournal 的變更,我嘗試了不同的方法。我沒有保留一個龐大、混亂的功能分支,而是採用了 stacked diffs。

什麼是 stacked diff?

Stacked diffs 是指你有一個 main 分支,想要合併一個大型功能,因此將該功能拆成變更 ABC。你從 main 分支出 A,再從 A 分支出 B,以此類推。

GitHub 對 stacked diffs 的支援還算可以:如果你的堆疊是 ABC,你會建立一個從 A 合併到 main 的 PR,再建立一個從 B 合併到 A 的 PR。當你把 A 合併到 main 的 PR 合併後,從 B 合併到 A 的 PR 會自動更新為從 B 合併到 main 的 PR。

我把工作拆開,為影集評論流程中的每一頁各建立一個 changelist。

留下評論的第一步是搜尋你想評論的作品。以前只能搜尋電影,所以我在支援影集時的第一步,就是新增一個單選按鈕,讓使用者可以在電影或影集之間做選擇:

已新增至 ScreenJournal 標題搜尋畫面的影集與電影單選按鈕截圖

我的第一項任務是修改標題搜尋介面以支援影集。

接下來,我需要讓使用者能選擇影集的季數,這是在只有電影時不需要的功能。因此,那也是一個獨立的變更

來自 ScreenJournal 的影集季數選擇畫面截圖

我的第二項任務是實作一個用於選擇要評論的影集季數的網頁介面。

我就這樣持續下去,流程中的每個階段都是一個新的分支和獨立的 pull request。

以下是這種開發方式的一些心得。

優點:Stacked diffs 更能激勵我

Stacked diffs 的好處在於,功能的每個子任務都是獨立的 changelist。

將變更拆成較小的部分,讓我更有成就感,也更能感受到進度。完成一個 changelist 並知道它已 100% 完成,遠比在一個龐大混亂的分支中,完成一個子任務只讓整體進度從 30% 推到 35% 更令人滿足。

缺點:我得不斷刪除變更歷史

在 stacked diff 工作流程中,我最不喜歡的一點是最後會刪除原始碼歷史,這抵銷了版本控制的一大好處。

每當我發現應該在堆疊中更早的地方做某個修改時,就必須執行 git rebase,這會重寫歷史。也就是說我必須對 GitHub 執行 force push,這會讓我的 changelist 充斥著難看的 force-pushed 紀錄:

顯示大量 force-pushed 紀錄的 GitHub PR 截圖

在 Git 中頻繁執行 rebase 會導致難看的 force-pushed 紀錄充斥我在 GitHub 上的 changelist

我知道有些人希望所有變更都完全按照發生的順序被保留,就好像每個 commit 都是謀殺案審判中的證據一樣。我不在乎那種程度,但我確實希望有一個合理的復原歷史,以防我犯錯。我不喜歡 force push 會覆蓋遠端的復原歷史,而且若要從本地端復原,還得進行複雜的操作。

優點:--update-refs 簡化了 stacked diffs 的 rebase 操作

在嘗試 stacked diffs 工作流程的過程中,我發現了 Git 的 --update-refs 旗標,它可以讓你一次 rebase 多個分支。

這個技巧讓 stacked diffs 變得更簡單,因為我之前是依序對每個分支做 rebase,當堆疊中有四個分支後,那個過程變得非常繁瑣。

缺點:執行 --update-refs 後的推送仍然很麻煩

如果我有分支 ABC,並一次對它們全部做 rebase,Git 的輸出會像這樣:

$ git rebase master --update-refs
Successfully rebased and updated refs/heads/C.
Updated the following refs with --update-refs:
        refs/heads/A
        refs/heads/B

雖然 --update-refs 簡化了 rebase 的操作,卻沒有「好,現在把我剛 rebase 的分支推送出去」這樣的指令。相反地,我必須把 Git 的輸出複製到文字編輯器中,編輯以擷取出分支名稱,再放回像 git push origin A B C -f 這樣的指令中。這是個惱人的過程,總是會打斷我的工作流程。

缺點:我經常陷入非預期的 Git 狀態

即使我自認為是以正確的方式在做 rebase,我還是經常發現自己處於令人困惑的狀態。例如我做了 rebase,然後它又要我去解決那些我已經解決過的衝突。

我透過壓縮 commit 再重新做 rebase 來繞過這個問題,但這同樣會重寫歷史,讓復原錯誤變得更困難。我也很懊惱自己把心力浪費在思考如何向 Git 好好道歉,而不是專心寫程式。

或許我該試試 jujutsu

我越來越常聽到關於jujutsu 的討論,這是一個有望在 Google 內部成為標準的新版控系統。

幾個月前,我曾考慮試試看,但心想:「算了,Git 已經能滿足我的需求,何必去追逐下一個新奇的東西?」但經歷了這次 Git rebase 的體驗後,我才想起自己已經把許多令人沮喪的 Git 體驗當成常態來接受了。

粗略看過 Steve Kalabnik(史蒂夫·卡拉布尼克)的教學後,聽起來 jujutsu 在支援 stacked diffs 和多重 rebase 方面比 Git 做得更好

推薦

「為何 15 年後我仍在寫部落格」 作者:Jonas Hietala(喬納斯·希耶塔拉)

我對這篇關於寫部落格的文章很有共鳴。當我進一步探索希耶塔拉的網站時,我心想:「喔,這傢伙簡直就是瑞典版的我。」所以如果你喜歡我的寫作,應該也會喜歡他的。

「烏克蘭札記」 作者:Matt Lakeman(麥特·萊克曼)

我上週發現了萊克曼的部落格,從那之後每天都在想:「這傢伙到底是誰?」

萊克曼會前往一些不那麼熱門的目的地,通常停留約十天,然後發表一篇關於該國家的部落格文章。但這不是那種寫給媽媽的明信片式部落格文章;這些是中篇小說篇幅的文章,基於數小時對該國歷史的研究以及與當地人的對話。

我也發現萊克曼在網路上其他地方以使用者名稱 dormin111 有著長期的發文歷史,例如這篇對電影《大災難家》的詳細分析

關於他所有作品最令人驚訝的是,似乎沒有任何目的性。通常當你看到有人在寫作上投入這麼多時,往往很明顯能看出對他有什麼好處:他們有 Substack 或某種付費課程來賺錢,免費文章則是虧本商品。但我在萊克曼的任何作品中都找不到任何目的或獲利動機。他似乎只是單純熱愛深入思考並分享想法

總之,回到這篇烏克蘭的文章。我原本以為他是在戰前去的,結果發現他是在戰爭爆發兩個月後前往,並在距離前線僅數英里處訪問了軍人和平民。看到一位非職業記者卻仍在烏克蘭訪問了各種真實人物所帶來的戰爭報導,我覺得很有意思。比起我在傳統媒體管道上看到的任何報導,這感覺更真實、更貼近個人。

Cyberpunk 2077(電玩遊戲)

我不太常玩電玩。我一年只買一款新遊戲,然後玩到膩為止,通常會在幾天內玩 5 到 25 小時。這款遊戲我已經玩了約 25 小時,仍然樂在其中。

我覺得遊戲的深度令人驚嘆。儘管已經玩了 25 小時,我覺得自己大概只探索了遊戲的 5%,這讓我驚訝於現代遊戲的世界竟如此廣闊。

我通常不在乎電玩中的劇情,而且當遊戲要我看完無聊的背景說明時會覺得很煩,但Cyberpunk 是少數讓我覺得劇情夠吸引人、值得專注的遊戲。看到他們在配音上投入這麼多,甚至讓 Keanu Reeves(基努·李維)在遊戲中擔綱重要角色,也覺得很酷。

Detroiters(電視影集)

我聽過這部影集,但我想名字總是讓我打消觀看的念頭。一部以角色住在底特律為主要特色的影集?聽起來很無聊。

然後我看到了來自該劇的這段片段,才發現裡面有很棒的演員,而且風格就像是稍微寫實一點的情境喜劇版《I Think You Should Leave》。我剛看完第一季,覺得非常棒。

《Detroiters》劇照,顯示 Tim Robinson(提姆·羅賓森)與 Sam Richardson(山姆·理查森)在昏迷的 Jason Sudeikis(傑森·蘇戴西斯)面前吃洋芋片

Detroiters 是稍微寫實一點的情境喜劇版 《I Think You Should Leave》

總結

完成了什麼?

學到的教訓

  • Stacked diffs 為大型變更提供了不錯的工作流程,但 Git 對它的支援並不好。
  • 讓部落格文章的投入與預期回報相匹配。
    • 雖然我熱愛記錄所學的一切,但我需要讓部落格在財務上可持續,而這只有在很大比例的完整長文能吸引到可能對我的營利專案感興趣的讀者時,才能實現。

下個月的目標

原文由 Michael Lynch 發布

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