Paternity Leave: Month 3

Michael Lynch

育嬰假:第三個月

原文由 Michael Lynch 發布,訂閱此部落格

一句話摘要

慢慢重回工作節奏。

亮點

  • 身為新手爸爸,我越來越能平衡好自己的時間了。
  • 我曾為兩篇表現不佳的部落格文章感到沮喪,結果後來它們反而表現得不錯。
  • 我嘗試了 stacked diff 的軟體開發流程,還滿喜歡的,只覺得 git 在這方面的支援有些不足。

目標評分

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

享受家庭時光

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

我發現提醒自己很有幫助:即使好像有很長一段時間都沒在工作,那也是我自己做的選擇,而且時間的主導權大致上還是在我手上。

我還在摸索工作與家庭時間的平衡,但感覺正越來越上軌道。

發表 Nix 模糊測試教學

慢慢重回工作

當我坐下來寫這篇回顧時,之前那種沒時間工作的焦慮感,感覺已經是很久以前的事了。我還以為那是兩個月前的事,沒想到一看,竟然就是上一篇回顧。

好在,現在對於家庭時間的分配,我感到放鬆許多。我享受了不少家庭時光,同時寫作的產量也比以往任何時候都多

有幾個因素帶來了這樣的轉變:

兒子晚上睡得更好了

一開始他每晚會醒來三、四次,每次都要吃上 60 到 90 分鐘,現在每晚只會醒兩、三次,而且 15 到 60 分鐘內就能再睡著。

昨晚他一覺睡滿全夜(7 小時 45 分鐘),讓人很興奮。

家人的幫忙變多了

隨著兒子慢慢長大,我們也更放心讓家人來家裡幫忙照顧他,不用我們一直在旁。現在每週大約有五個小時的幫忙,而且應該還會持續增加,因為家人們其實願意幫更多。

兒子可以在我工作時小睡

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

我有了固定的工作時段

我發現作息不固定很難專心工作。雖然有很多時間是我太太在顧兒子,或是兒子在我胸前睡著,但知道他們可能隨時需要我,就很難集中精神。

我太太主動每天給我一段 90 分鐘保證不受打擾的專注時間,這對提升專注力很有幫助。而且知道每天都有這段時間,我就可以把需要高度專注的工作留到那時候做。

我是不是在部落格文章上投入太多了?

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

我會把每篇文章都打磨到最好,即使那篇文章的受眾很小,或我根本沒管道接觸到讀者。之前的例子包括「Hiring Content Writers: A Guide for Small Businesses」(有受眾,但我沒有好的管道接觸到他們)和「Retrofitting Apps for Cloud Storage with Zero Code Changes」(非常小眾,除了我那個奇怪的使用情境外,沒什麼人會感興趣)。

我也遇過很喜歡那些文章的讀者,但我也得考慮機會成本。花時間寫那些文章的同時,是不是有另一篇文章能觸及更多讀者、或整體上提供更多價值?

後來我寫文章變得更有策略性。如果覺得一篇文章無法達到一定的讀者數量,我就乾脆不寫,或是在「Notes」專區寫個快速、簡易的版本就好。

「Using Nix to Fuzz Test a PDF Parser」

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

寫這篇文章讓我對 Nix 和模糊測試學到很多,但花的時間比預期久。一開始我還想:「喔,幾個小時就能快速寫完吧」,結果最後花了 20 多個小時。

在 LLM 的時代寫軟體教學也讓人有點氣餒。幾年前,教學文章還有長期的回報,因為人們之後還會透過搜尋找到它。但現在就算我寫了一篇小眾教學,LLM 也只會直接拿去用,讀者根本不會知道內容是來自於我。

「Lessons from my First Exit」

我一開始就知道這篇文章有點冒險,因為有幾個不利因素:

  • 這篇文章在講賣掉一間公司的瑣碎細節,而 99% 的讀者根本沒打算這麼做。
    • 我上一篇關於出售的文章有引起迴響,但那是一則故事,就算讀者自己沒興趣賣公司,也能享受過程。
  • 文章超長。
    • 我每篇部落格文章的目標是讓人讀 10 分鐘左右,而那篇估計要讀 33 分鐘。
  • 唯一有機會獲得不錯曝光的社群管道只有 Hacker News。

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

我覺得它在 Hacker News 上還是有機會獲得關注,但就算完全沒起色,我還是很開心寫了它。這幫助我自己梳理了那次收購的過程,未來如果再賣另一間公司,也會是很有用的參考。我也從經歷過收購或正在考慮收購的創業者那裡,得到了不少正面的回饋。

然後,那些文章突然就有了迴響

在寫完上面那段後,我才發現Hackaday 報導了我的 Nix 模糊測試教學,這讓人感到很受肯定。

然後就在我寫完「Lessons from my First Exit」表現不佳那段的隔天,有位讀者又把它投稿到 Hacker News,結果衝上了第 2 名

不過,我還是覺得我最初的分析是對的。我在那篇模糊測試的文章上投入過度,而在那篇關於出售 TinyPilot 的文章上,投入的程度剛好。

透過 stacked diffs 實作大型功能

過去幾週,我的業餘程式時間大多花在ScreenJournal 上,那是我做的影集與電影評論網站。概念有點像 Letterboxd 或 Goodreads,但評論只會給朋友看,而且程式碼是開源的。

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

ScreenJournal,我開源的影集與電影評論網站

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

到了十月,我加入了影集評論的支援,所以得修正程式碼中許多「評論一定是針對電影」的假設。

完整的變更最後達到了 2000 行程式碼,如果放在單一 changelist 裡會有點難以理解。我這裡用的「changelist」一詞,指的就是以 GitHub 來說的 pull request,或以 GitLab 來說的 merge request。

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

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

所以,這次在 ScreenJournal 的變更中,我嘗試了不同的方法。我沒有維持一個又大又亂的功能分支,而是採用了 stacked diffs。

什麼是 stacked diff?

stacked diff 指的是你有一個 main 分支,想要合併一個大型功能時,把功能拆成變更 ABC。你從 main 開出分支建立 A,再從 A 開出分支建立 B,依此類推。

GitHub 對 stacked diff 的支援還算可以,如果你的堆疊是 ABC,你會從 A 發一個 PR 到 main,再從 B 發一個 PR 到 A。當你把 A 合併進 main 的 PR 合併後,B 合併進 A 的 PR 就會自動更新成 B 合併進 main 的 PR。

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

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

ScreenJournal 標題搜尋畫面中新增的「影集 vs 電影」單選按鈕截圖

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

接下來我需要一個讓使用者選擇影集季度的方式,因為以前只有電影時不需要這個。所以那也是獨立的一次變更

ScreenJournal 影集季度選擇畫面的截圖

我的第二個任務是實作一個讓使用者選擇要評論的影集季度的網頁介面。

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

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

優點:stacked diffs 更能激勵我

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

把變更拆成更小的部分,讓我更有成就感、也更能感受到進展。完成一個 changelist 並知道它已經 100% 完成,遠比在一個又大又亂的分支上,完成一個子任務只讓整體進度從 30% 推到 35% 來得有滿足感。

缺點:我得不斷刪除變更紀錄

我最不喜歡 stacked diff 流程的一點是,最後會把原始碼的歷史紀錄刪掉,這等於抹煞了版本控制的一大好處。

每當我發現某個修改應該更早在堆疊中完成時,就得執行 git rebase,這會重寫歷史。也就是說我得對 GitHub 強制推送,結果讓我的 changelist 裡充滿這些醜醜的 force-pushed 紀錄:

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

在 git 中頻繁 rebase 會導致醜陋的 force-pushed 紀錄散落在我在 GitHub 上的 changelist 中

我知道有些人希望所有變更都像謀殺案的證據一樣,完全照發生的原樣被保留下來。我倒不在乎那個,但我確實想要一個合理的復原紀錄,以防我犯錯。我不喜歡強制推送會覆寫遠端的復原紀錄,而且還得在本地端做複雜的手術才能救回來。

優點:--update-refs 讓 stacked diff 的 rebase 變簡單

在嘗試 stacked diff 流程時,我發現了 git 的 --update-refs 參數,它可以讓你一次 rebase 多個分支。

這個技巧讓 stacked diff 變得更輕鬆,因為我之前都是依序逐一 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 合併(squash)後再重新 rebase,但這又會重寫歷史,讓錯誤更難復原。我也很煩自己浪費了那麼多腦力去想該怎麼好好跟 git 道歉,而不是去寫程式。

或許我該試試 jujutsu

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

幾個月前我曾想過要試試看,但心想:「唉,git 已經夠用了,何必去追逐下一個新潮的東西?」但經歷了這次 git rebase 的體驗後,我才想起自己已經把太多令人沮喪的 git 經驗當成理所當然了。

從快速瀏覽 Steve Klabnik 的教學來看,jujutsu 似乎比 git 更能支援 stacked diff 和多重 rebase

推薦

「Why I still blog after 15 years」 by Jonas Hietala

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

「Notes on Ukraine」 by Matt Lakeman

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

Matt 會去一些不太熱門的地方,通常待個十天左右,然後發表一篇關於那個國家的部落格文章。但那不是那種寄明信片給媽媽的遊記;這些是中篇小說長度的文章,背後是數小時對該國歷史的研究以及與當地人的對談。

我還發現 Matt 在網路上其他地方以 dormin111 這個帳號有很長的發文歷史,例如這篇對電影《The Disaster Artist》的詳細分析

他所有作品最瘋狂的一點是,似乎完全沒有任何目的。通常看到有人在寫作上投入這麼多,很容易就能看出對他有什麼好處:他們有 Substack 或某個付費課程可以賺錢,而免費文章只是虧本招攬生意的手段。但我在 Lakeman 的任何作品中都找不到任何目的或獲利動機。他似乎只是單純喜歡深入思考事物並分享自己的想法

總之,回到這篇關於烏克蘭的文章。我本來以為他是在戰前去的,結果他是在戰爭開始兩個月後去的,還在離前線僅數英里處訪談了士兵與平民。能看到一位非職業記者卻仍訪談了烏克蘭各式各樣真實人物的戰爭報導,我覺得很有意思。比起我在傳統媒體上看到的任何內容,這感覺是對當地情況更真實、更個人化的觀點。

Cyberpunk 2077(電玩遊戲)

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

我覺得它的深度令人驚艷。玩了 25 小時,我覺得自己大概只探索了遊戲的 5%,所以現代遊戲能擁有如此龐大的世界,讓我感到很驚訝。

我平常不太在乎電玩的故事,還覺得被迫看冗長的說明很煩,但 Cyberpunk 是少數讓我覺得故事夠吸引人、值得專心看的遊戲。而且看到他們在配音上投入這麼多,甚至讓基努·李維在遊戲中擔綱重要角色,也覺得很酷。

Detroiters(影集)

我以前就聽過這部影集,但覺得片名總是讓我不想看。一部定義特色就是角色住在底特律的影集?聽起來很無聊。

然後我看到了這個影集的這段片段,才發現裡面有很多厲害的人,而且它的調性有點像比較貼近現實的《I Think You Should Leave》情境喜劇版。我剛看完第一季,覺得非常棒。

《Detroiters》劇照,Tim Robinson 和 Sam Richardson 在昏迷的 Jason Sudeikis 面前吃洋芋片

《Detroiters》有點像是更貼近現實的《I Think You Should Leave》情境喜劇版。

總結

完成了什麼?

學到的教訓

  • stacked diff 為大型變更提供了不錯的工作流程,但 git 對它的支援還不夠好。
  • 寫部落格文章的投入要與預期回報相符。
    • 雖然我喜歡把學到的每件事都記錄下來,但我的部落格需要財務上能持續經營,而這只有在很大比例的長文能吸引到可能對我的營利專案感興趣的讀者時,才有可能實現。

下個月的目標

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

留言