當我有一個專案點子時,它通常會朝以下兩個方向發展:
我直接動手做。也許我會做一些小修改,但很多時候結果會和我最初想像的一模一樣,我很滿意。
我會想:「我應該找找看有沒有類似的現有方案。」有很多現有的方案,而且它們的範圍比我最初想像的要廣泛得多。我開始想,我是否應該納入那個範圍?或者嘗試將我的東西建立在現有的、有點類似的解決方案之上?又或者我應該直接使用那個流行的東西。雖然我可以做得比那個東西更好,如果我投入很多時間的話。但實際上,我不想維護一個龐大熱門的專案,也不想在這個專案上投入那麼多時間。糟糕,現在我已經花了很多時間,既沒有解決最初的問題,也沒有體驗到創造的樂趣。
我比較喜歡第一種結果,我認為關鍵因素在於我對自身成功標準的內化程度。
例如,上週末我接待了我的朋友 Marcin,我們決定一起做些木工會很有趣,於是我們一起組裝了一個架子,並為我的廚房 3D 列印了掛鉤:
主要的成功標準是和朋友一起享受木工的過程,這幫助我沒有過度思考物件層面的成功標準:只要為我的廚房打造一個架子就好!
相比之下,上週五我注意到 difftastic 的表現不佳,所以我決定尋找結構性/語意性差異工具及相關工作流程(這是我從未研究過的主題,但隨著我審查越來越多的 LLM 生成的程式碼,我對它越來越感興趣)。
週末我花了 4 個小時研究現有的工具(見我下面的筆記),經歷了「語意樹狀差異是一個博士級的複雜問題」和「為什麼這些工具都有 MCP 伺服器?我不想用 MCP 伺服器」的黑暗時期,然後我恢復了理智,想起了我最初的成功標準:我只想在 Emacs 中獲得一個更好的差異分析工作流程,我應該自己動手做——這應該只需要大約 4 個小時。
我謹慎樂觀地認為,在有了這個領悟並將自己限制在最小範圍內後,我將能在失去動力之前完成一個原型。
然而,我其他長期的興趣:
似乎都陷入了第二種結果的深井。
也就是說,我已經在背景研究和小原型上花費了數百小時,但尚未合成任何能解決最初動機問題的東西。
並非我後悔花費的時間——我確實喜歡透過閱讀來學習——但我有一種揮之不去的憂慮感,我的內在批評者(對失敗的恐懼?)正在壓制我的創造性傾向,讓我無法獲得更令人愉快(也更有生產力!)的「透過實踐來學習」。
我認為在這些情況下,成功標準一直模糊不清:我是在試圖取代我自己對 Rust/Clojure 的使用嗎?只針對某些問題子集?還是我實際上只需要一個遊樂場來學習語言設計/實現,即使我最終沒有使用它也沒關係?
CAD 也是如此:我是在試圖用我自己的 CAD 工具取代商業 CAD 工具嗎?只針對某些簡單或特別參數化的零件子集?我是否在意它對他人是否有用?我的工具是否需要與現有的開源工具明顯不同?
考慮這些問題當然是值得的。但歸根結底,我寧願做了很多事情,也不願只考慮了很多事情。
所以我正試圖擁抱我內心那個不拘小節的 20 歲年輕人,直接動手做——即使有些事情事後看來「顯然很糟糕」,我最終還是會有所收穫 =D
當然,「直接動手做」的時間是有限的,需要找到平衡點。我不確定我會在職業生涯中重學多少次 YAGNI(「你不會需要它」)的教訓,但在用 LLM 代理寫了一堆程式碼,最終恢復理智並將其全部刪除後,我又一次被提醒了。
我想要一個類似 Finda 的、用於 Emacs 的全檔案系統範圍的模糊路徑搜尋器。自從我以前(手工,自己打字寫程式碼!)構建過這個功能後(遍歷檔案系統收集路徑,按 trigram 索引,透過位元組圖交集進行快速模糊查詢),我認為監督 LLM 寫出所有程式碼只需要幾個小時。
我從一個「計畫模式」的聊天開始,LLM 建議了一個函式庫 Nucleo,它在我寫 Finda(10 年前,嗚嗚)之後出現了。我閱讀了它,發現它設計得相當不錯且文件齊全,並決定使用它,這樣我就可以獲得它聰明的字元大小寫和 Unicode 正規化功能。(例如,查詢 foo 匹配 Foo 和 foo,而查詢 Foo 不會匹配 foo;cafe 和 café 也是如此。)
找到一個很棒的函式庫不是問題,問題在於 Nucleo 也支援一些額外的功能:錨點(^foo 只匹配行開頭)。
這讓我開始思考,在完全由檔案路徑組成的語料庫中,這可能意味著什麼。錨定到行開頭沒有用(所有路徑都以 / 開頭),所以我決定嘗試解釋錨點相對於路徑片段。例如,^foo 會匹配 /root/foobar/ 但不會匹配 /root/barfoo/。
但為了有效率地做到這一點,索引需要追蹤片段邊界,以便查詢可以快速地針對每個片段進行檢查。
但然後我們還需要處理錨定查詢中出現的斜線(例如,^foo/bar),因為當只單獨查看片段時(匹配路徑 /root/foo/bar/baz/ 的 root、foo、bar 和 baz),這將無法匹配。
解決這個問題花了好幾個小時:首先與 LLM 討論設計想法,讓它編寫程式碼來包裝 Nucleo 的類型,然後意識到它的程式碼臃腫且不令人愉悅,最終自己編寫(更小的)包裝器。
所以我把所有錨定程式碼都扔掉了。
我非常確定,與我試圖自己編寫所有程式碼(沒有 LLM 或與他人討論)相比,我仍然有所收穫,但我並不確定。
也許這裡存在某種守恆定律:程式設計速度的任何增加都會被不必要功能的相應增加、兔子洞和轉移所抵消。
說到不必要的分心,讓我告訴你我最近學到的關於結構性差異分析的一切——如果你在這個領域有任何想法/感受/參考資料,我很想聽聽!
當我們談論程式碼時,「差異」通常意味著兩個檔案版本之間逐行變更的摘要。這可能會呈現為「統一」視圖,其中變更的行前面會加上 + 或 - 來指示它們是新增還是刪除。例如:
我們移除了咖啡,加入了蘋果。
相同的差異也可能以並排視圖呈現,當變更較複雜時,這種視圖可能更容易閱讀:
這些逐行差異的問題在於它們無法感知函數、類型等較高級別的結構——如果某些大括號在不同版本之間以某種方式匹配,它們可能根本不會顯示出來,即使這些大括號「屬於」不同的函數。
有一個很棒的工具 difftastic,它試圖透過使用 treesitter 提供的具體語法樹來計算差異,從而解決這個問題。這比基於行的差異有了巨大的進步,但不幸的是,它並不總能很好地匹配不同版本之間的實體。
這是促使我進行這次探索的差異:
請注意,它沒有匹配 struct PendingClick,而是將其顯示為左側的刪除和右側的新增。
我還沒有深入研究 difftastic 為何在這裡無法匹配,但我確實覺得這是錯誤的——即使總體差異會更長,我仍然希望看到 PendingClickRequest 和 PendingClick 在兩側都匹配起來。
以下是該領域工具/參考資料的摘要:
我發現最「成熟」且經過深思熟慮的語意差異工具,或許不出所料,是 semanticdiff.com,這是一家小型德國公司,提供免費的 VSCode 外掛程式和網頁應用程式,用於顯示 GitHub PR 的差異。不幸的是,他們沒有任何程式碼函式庫可以作為我想要的工作流程的基礎。
上下文相關的關鍵字尤其是一個持續的煩惱來源。語法看起來是正確的,但由於詞法分析器的工作方式,它將無法解析。你不會希望你的工具僅僅因為有人將參數命名為「async」就中止。
mergiraf:基於 treesitter 的合併驅動程式,用 Rust 編寫
weave:同樣是基於 treesitter 的合併驅動程式,用 Rust 編寫
diffast:基於 2008 年學術論文演算法的 AST 樹編輯距離。
autochrome:基於動態規劃的特定於 Clojure 的差異
Tristan Hume 有一篇關於使用動態規劃和 A* 設計樹狀差異演算法的精彩文章。
我的主要用例是逐回合審查 LLM 輸出——我始終處於掌控之中,我不會讓我的代理(或數十個代理,哈哈)失控一次生成 10k+ 行程式碼。
相反,我給代理一個範圍化的任務,然後幾分鐘後回來,想看到它做了什麼的概覽,然後在 Emacs 中手動修改/調整它,或者將其全部刪除並重試(或者乾脆自己寫)。
基本上,我想要類似 Magit 的工作流程來審查和暫存變更,但針對實體層級而不是檔案/行層級。
鑑於我第 n 次重新學到的「最小範圍,完成你的專案」的教訓,我的計畫是:
一旦這看起來合理(即,它在該特定提交上的表現比 difftastic 好),我將:
也許,如果我對它滿意,我最終會發布一些東西。但我不是為了收集 GitHub 星標或 HN 積分,所以我可能會在家裡愉快地使用它,而不試圖「商業化」它。
畢竟,有時候我只想做個架子。
我正在尋找幾平方公尺的 Tyvek 或其他適合製作濾光器的半透明無紡材料——如果你有任何推薦的、可以運送到歐洲的供應商,請告訴我。
他們是如何製作的 - Coinbase 商業廣告解析。加密貨幣是對生產性經濟活動的負和寄生蟲,但其優點是將大量資金導向奇怪的創意人士。
一個尾遞迴解釋器(在(夜間)Rust 中)
設計家具的最簡單方法……。Laura Kampf 談論如何擺脫電腦,用膠帶、小木棍和紙板設計物理空間。
Hotel California - 在傳統中國古箏上重新演繹
C 不是低階語言:你的電腦不是快速的 PDP-11。
我教我的狗如何 vibing 程式碼遊戲 - Caleb Leak
Loon 是一個 Lisp。很高興發現我不是唯一一個想將 Clojure 和 Rust 結合起來的人。目前的實現似乎經過了瘋狂的 vibing 編碼,我很快就遇到了一些嚴重的錯誤,但另一方面,它確實存在,所以我不會討厭它。
製作了一個即印即用的盒子,方便我分發印刷的蜜蜂🐝。「我對結果很滿意,蜜蜂們緊密貼合,盒子開合順暢。」
基於酵母的疫苗對生物安全很重要
「關於如何購買防毒面具,特別是為了在國家鎮壓下生活,可靠的資訊並不多。但希望閱讀完本指南後,您會覺得自己有能力做出明智的決定。」
這個可縮放的地圖顯示了 BYTE 每一期的每一頁,從第一期的封面(左上角)到最後一期的最後一頁(右下角)。搜尋欄對所有 10 萬頁進行 RE2 正則表達式搜尋。一個美好的提醒,使用者介面可以非常快速且資訊密集。
贊成嘗試新事物 – Daniel Frank
凝視深淵作為一項核心生活技能