CONTENTS
Once 1.0 had actually been used, 2.0 did not need to invent the buttons again. It needed rules for how objects, drawings, tags, and published data should live together—and a way to issue the result as a real install.
01 — 操作跟 1.0,底層重做
到了 2.0,情況完全不同。這次已經有一套真正工作過的 1.0,很多功能不需要重新發明。
我甚至可以直接告訴 AI:
操作方式參考 1.0,底層按照 2.0 的架構重新做。
1.0 於是變成一份 executable reference(可執行的參考,不是拿來複製的程式碼)。它回答一個非常重要的問題:
這件事情實際上應該怎麼操作。
移除櫃體與 2D 工具之後,整條工具鏈才開始清晰的表達自身。剩下的是:依 Dictionary 寫入模型、檢核通過後發布一版給圖紙讀取、用 Rhino 剖面出圖、再把同一版資料注入 Tag。模型改完不會自動灌進圖面;3D 也不會被圖紙反向改掉。每一步都要由人來確認,隨時可以停下。
02 — 不是重寫功能,而是重新定義關係
2.0 真正重新處理的,是底下的關係。
物件有自己的 identity(穩定身分,像構件編號,而不是今天才取的名字)。
視圖有自己的身分,以及固定的 transform(2D 與 3D 怎麼對在一起)。
Drawing 是可以獨立人工修改的成果。
圖紙保存自己的資料。
Tag 保存自己的 binding(它綁的是誰:物件、視圖,還是某一張圖)。
Registry 是某一次經過驗證後發布的模型快照——像蓋過章的正式版圖說,不是桌上那堆還在改的草圖。
原本散落在各支 Python 裡的責任,逐漸被重新放進自己的位置。從軟體角度來看就是 module boundary 與 ownership(模組邊界與所有權):誰可以改什麼、誰只能讀什麼。對我而言,它非常像設計與施工裡的專業分工。修改一間浴室,不應該整棟樓的空調、消防、外牆與電梯一起被迫重畫。
| 軟體概念 | 我用來理解它的建築映射 |
|---|---|
| Data Contract | 施工圖上的共同尺寸、標高與規格 |
| Stable ID | 構件編號或圖號,而不是容易改的名稱 |
| Single Source of Truth | 唯一正式版圖說 |
| Revision | 圖說版次 |
| Refactor | 不改變使用目的,重新整理結構與管線 |
結果非常直接。1.0 花了一個多星期反覆嘗試的 Laser,在 2.0 幾乎一次完成。Grab、Index Tag 也開始出現第一次實機就成功的情況。功能並沒有變簡單,而且一切都更順利了,因為很多未知問題已經被提前消除。
03 — Markdown 成為施工圖
LoopFlow 2.0 最大的改變之一,是開始出現大量 Markdown 文件。
一開始只是因為事情愈來愈多,我不可能每換一個 AI,就重新解釋一次整個系統。後來這些文件逐漸被分成不同責任:整套系統要做什麼、資料契約、使用者真正的操作流程、開發工作的前後依賴、系統設定,以及一份只回答「現在到底做到哪裡」。
AI 開始工作以前先讀文件,實作完成後跑測試,我在 Rhino 裡實際驗收,確認之後再把新的狀態寫回文件。下一個 AI 接手時,再讀更新後的版本。
於是 Markdown 不再只是說明書。它開始變成整個開發工作的共同環境。用建築來比喻的話,比較接近的理解會是施工圖:不需要站在每一個工班旁邊重新口頭說明建築應該怎麼蓋。大家先讀同一套圖;現場發現問題,釐清後改圖;下一個人再從新的版本繼續施工。
需要被保留的不是某一次對話,是共同依據。
2.0 也因此不是打開 1.0 的檔案修一修。它是乾淨重建,正式發布時一次切換。同一專案不可混用 1.x 的資料、Tag、指令或工具列。舊案若要過來,不是一鍵升級,而是另案處理。
04 — 多 AI 不是一個人
規劃一套新架構時,我很少再把所有事情交給同一個 AI 從頭做到尾。
規劃 LoopFlow 下一階段時,我把同一批 repo 同時交給不同模型。第一輪各自獨立分析。某一次才發現,其中一個模型讀的是 Dropbox 裡一份舊快照,不是當下的 git repo,中間已經差了十幾次修改。
多 AI 協作,第一個要檢查的,其實不是誰比較聰明,而是確認大家都在看同一份東西,並且提出各自觀點。
後面幾輪變成交叉檢查:哪些結論一致、哪些只有一方抓到、哪些互相矛盾。後手的 AI 若每一輪都想證明自己更厲害、整份重寫一次,協作只會無限發散。有用的角色是「檢視與補充」,不是另起爐灶。
這套做法後來被固定成決策表。每一列是一個還沒定案的問題;兩邊各自寫建議,並標上強烈、一般或輕鬆。兩邊都強烈建議而且沒有衝突,就直接採用。我真正要看的,只剩下有分歧、或只有一邊講到的那一小撮。
高程基準、模型單位、Layout 複製後 Index Tag 仍指向舊頁——這些都是圖面上會印到現場的錯,而且有的錯,既有檢查根本看不見。兩邊談不攏的,表上並排列出,我再來判定。有一題只有一邊給過意見,另一邊欄位就留白,寫「尚未提供,不代替它推測立場」。留白比造假可靠。
要不要照單全收、調整到什麼規模、什麼時候才真的動手改,這些決定還是在我身上。但軟體工程並不是我所擅長的,也因此才會採取這種多 AI 協同作業的方式進行。
05 — 來做一些離奇的事
Edge Case(邊界條件)這個詞,我自己的理解比較簡單:來實際做一些離奇的事情,看它會不會爆炸。
操作到一半按 Esc。不做前面的檢核,直接發布。只選一部分物件就要求發布全案。把物件鎖住、藏起來。連續發布兩次。拿一個完全沒有資料的物件去看資料面板。
這類事情 AI 可以幫忙列出,但最後我還是會在 Rhino 中一個一個實際操作。因為使用者可能會有一些我開發時根本沒想過的操作方式,所以得在前期先把這些可能性都找出來。
圖面上看起來完全合理,蓋起來不一定真的沒有問題。自動測試通過,也不代表工具真正使用時一定順手。最後還是需要有人走進去,開門、關門、亂按、繞路,然後看看哪裡會壞掉。
我需要做決定的,也不是某段程式怎麼寫,而是釐清責任關係:這個資料應該由誰負責、什麼可以自動改、什麼一定要保留人工、失敗之後該留下什麼狀態、使用者按下取消時什麼絕對不能被破壞。AI 施工快速,但我怕有點太快了。
06 — 上架:從解壓拖放,到 Package Manager
1.0 的安裝方式很像把工作室裡的工具箱直接遞給別人:解壓縮、跑 install_LoopFlow.bat、把工具列拖進 Rhino。它能用,但那是組合包的交付,不是產品的發行。
2.0 改成一份 .yak,用 Rhino 8 的 Package Manager 搜尋 LoopFlow 安裝。功能版是 2.0.0;接著有一版只改圖示與說明的 2.0.1。目前安裝版是 2.0.6。識別名維持小寫 loopflow。同一專案不可混用 1.x 與 2.0。裝完要完全關掉 Rhino 再開。
這對我而言很像:施工期間可以用臨時工法,交屋時必須發出一套正式圖說與材料。使用者不應該再管理 Python 路徑,也不應該從舊按鈕走進新契約。
從前期計畫到上架,中間並不是「寫完就放上去」。先有契約與流程,再一批一批重建主鏈,測試與 Rhino 實機驗收,文件改成對得上真實安裝方式,最後才把那一份可以搜尋到的套件推出去。推出去之後,1.0 與 2.0.0 的發行紀錄都不移動、不覆寫——像已經送審過的圖說版次,不能因為後來想改封面,就把舊圖抽掉重印。
07 — 不會寫程式,仍可以設計軟體
雖然 LoopFlow 愈來愈像一個真正的軟體系統,我卻沒有因此開始把自己理解成程式設計師。我依然不會寫 code。真正大量增加的,是我對系統關係的理解。
AI 把「不會寫程式」和「不能設計軟體」拆開了一部分。我不會寫程式,但我可以描述工作流程、定義資料之間的關係、指出哪些操作不合理、要求保留人工控制、安排不同 AI 互相 review、閱讀測試結果,也可以打開 Rhino,用真正工作的方式驗收它。
整理複雜關係、建立層級、定義介面、控制例外、保留修改空間,以及不斷在整體與局部之間來回——這些事情本來就是設計。只是最後被建造出來的,不再是一棟建築,而是一套軟體。
結尾
現在回頭看,LoopFlow 1.0 與 2.0 最大的差異,也許不是程式碼品質,而是問題已經改變了。
1.0 問的是:這件事情做不做得到。所以先讓它活。
2.0 問的是:如果這套東西要持續成長,它們之間應該用什麼規則相處。於是開始出現身分、契約、所有權、版次、綁定與狀態。
從 Prototype 逐漸變成 Protocol。
Architecture should arrive late—after the work has been used, and after the real accidents have names.
架構應該晚一點進來。等系統被使用過,等事故已經有名字。
When code is no longer the main door into software, a designer still begins the same way: draw the relationships, then build.
當程式碼不再是進入軟體最主要的門檻,設計者仍然用原本就會的方式開始:先畫關係,再蓋東西。