Practice / Lab
From Drawings to Release
LoopFlow 2.0 rebuilt relationships rather than buttons: markdown as construction drawings, multi-model review, and a Package Manager release that does not mix with 1.0.
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.
當程式碼不再是進入軟體最主要的門檻,設計者仍然用原本就會的方式開始:先畫關係,再蓋東西。