我把 2021 年寫的 Vision App 拿出來,開始用 AI 一步步重構它

Darren
iOSAI CodingRefactoringVisionPose Coach

Pose Coach 是我在 2021 年開始開發的 iOS / Vision 專案。2026 年重新打開它時,我開始用 AI 補 spec、拆 plan、加測試,並一步步把它重構成更完整的分析工具。

這系列想記錄一件我最近做得滿有感的事:

我把一個 2021 年開始寫的 iOS 專案重新拿出來,然後開始用 AI 一步一步重構它。

這個專案叫 Pose Coach。

一開始它其實不是什麼很完整的產品,比較像是我想試試看 Apple Vision framework 可以做到什麼程度。當時的核心想法很單純:做一個影片播放器,然後在播放影片的時候做人像辨識,把骨架 overlay 疊在畫面上。

換句話說,它的起點就是:

  1. 匯入影片
  2. 播放影片
  3. 用 Vision framework 做 body pose detection
  4. 把辨識結果畫在播放器上

以 2021 年的時間點來說,這已經是滿有趣的實驗了。

但問題也很明顯。

那時候沒有現在這種 AI coding workflow。遇到功能想法,大多就是自己打開 Xcode,邊想邊寫。架構不一定一開始就拆得很好,文件通常也不會先補齊,測試更常常是「先手動跑看看」。

專案可以動,但久了之後就會變成一種狀態:

「我大概知道它在幹嘛,但要改之前要先重新想一下。」

2026 年重新打開它

到了 2026 年,我又重新開始整理 Pose Coach。

這次不太一樣的是,我手上已經有 AI 可以用了。

一開始我也很自然地想說,那是不是可以直接叫 AI 幫我加功能?

例如:

幫我加一個螢幕分享功能。

或是:

幫我在影片分析裡面加球棒軌跡。

聽起來很合理,但是這種要求其實太大了。

專案開發不像一個單純的 script。它會牽涉到:

  • Xcode project 設定
  • SwiftUI / UIKit 的生命週期
  • AVFoundation 的 sample buffer
  • Vision framework 的座標系
  • 相機與相簿權限
  • Simulator 跟真機差異
  • 非同步 pipeline
  • UI 狀態與 thread safety

我相信隨著 AI 的進步,可能不遠的未來我們就不需要考慮這些了

但在當下,AI 這些還是會寫出「看起來合理」的 code,但軟體開發的麻煩通常不是看起來合理就可以。

可以 build 嗎?

真機可以跑嗎?

權限有補嗎?

座標有沒有上下顛倒?

慢動作影片的時間軸有沒有算錯?

這些問題都不是一句「幫我實作」就能處理乾淨的。

所以後來我慢慢把流程調整成另一種方式:

先讓 AI 幫我讀懂舊專案,再把想法整理成 spec,接著拆成 implementation plan,最後才開始小步實作與驗證。

不是重寫,而是慢慢重構

重新整理舊專案時,很容易冒出一個念頭:

不然整個重寫好了。

隨著 AI 進步,或許完全重寫這件事已經不再如以往那麼遙不可及,

但現階段我比較偏好先重新認識這個已經存在的專案,一步一步重構它。

我的理由是 AI 寫的很快,但人理解的速度肯定跟不上 AI 產出的速度。

至少在 2026 的今天,我還是覺得作為一名軟體開發人員應該要理解要交付出去的產品。

因此我先列出了已經存在的功能:

  • 影片匯入
  • 播放器
  • Vision body pose detection
  • skeleton overlay
  • 多語系
  • CoreData 儲存影片資訊
  • 一些已經驗證過的 UI 流程

每次只處理一個明確問題:

  • 播放器太散,就先收斂播放器架構
  • Body detection UI 不好操作,就先寫 spec 重設互動
  • 想把畫面分享到第二台裝置,就先定義 MVP
  • JPEG / H.264 串流路線不好維護,就再往 WebRTC 重構
  • 想做球棒軌跡,就先把幾何計算拆成純函式
  • 想算速度,就先補 frameIndex 與 metrics 計算

這種方式比較慢,但比較不會失控。

而 AI 在這裡最有幫助的地方,不是「一次幫我寫完整個功能」,而是幫我把每一步變小、變清楚、可以驗證。

第一個大整理:播放器

近一年 commit 裡,第一個明顯的大重構是播放器。

當時做了幾件事:

  • 重構 player architecture
  • 修正 pose overlay alignment
  • 收斂成單一 player
  • 加入 pinch zoom / pan
  • 支援 portrait orientation
  • 把截圖、frame step、pose analysis、clip export 拆成 feature

過去想法驗證時欠下的技術債,現在有機會還了 XD

過多的依賴,職責混亂的 function 開始進行拆分

例如播放器不同的功能放倒 Modules/Player/Features 這種比較明確的位置,讓播放器真的只是播放器。

這也是我後來用 AI 重構時很常做的一件事:

先讓邊界變清楚。

一個功能如果講不清楚它屬於哪裡,AI 通常也很難改得乾淨。

從「直接做」變成「先寫 Spec」

到了 body detection UI redesign 和 screen sharing 的時候,我開始比較明確地使用 spec / plan。

以前可能會直接說:

幫我改一下 body detection UI。

但這種 prompt 對 AI 來說太模糊了。

什麼叫「改一下」?

是改 UI layout?

是改狀態模型?

是改 overlay?

還是改使用流程?

所以我開始先寫 spec,把事情講清楚:

  • 現在的問題是什麼
  • 目標是什麼
  • 這次要包含什麼
  • 這次不包含什麼
  • 架構怎麼切
  • UI 怎麼動
  • 錯誤怎麼處理
  • 要怎麼測

這件事看起來像是在寫文件,但實際上比較像是在限制 AI 的發揮空間。

AI 不是不能發揮,而是不能亂發揮。

尤其是在舊專案裡,很多東西都已經有歷史包袱。你沒有先講清楚邊界,它很可能會「順手」幫你改一堆不該改的地方。

螢幕分享是第一次大型功能實驗

Pose Coach 原本是單機使用。

但如果真的拿來做運動分析,只在手機上看其實不太夠。有時候會希望第二台裝置可以同步看到畫面,例如教練看一台、使用者拿一台。

所以我開始做螢幕分享。

一開始的 MVP 很保守:

  • 同一個 Wi-Fi
  • 一對一連線
  • 廣播端把相機畫面加上骨架 overlay 傳出去
  • 接收端全螢幕顯示
  • 支援基本錄製與回溯剪輯

同時也明確寫了不做什麼:

  • 不做多台接收
  • 不做自動重連
  • 不一開始就做 WebRTC
  • 不把所有進階 overlay 都塞進 MVP

這個「不做什麼」非常重要。

因為如果沒有邊界,AI 很容易把 MVP 做成一個看起來很完整但其實很難驗證的大怪物。

後來這條線也真的走了好幾次重構:從 JPEG / MCSession,到 H.264 delayed playback,再到 WebRTC。中間有很多 thread safety、播放延遲、真機權限、連線狀態的問題。

這些東西都不是 AI 單靠想像能一次寫對的。

但有 spec 和 plan 之後,至少每次出問題時,我知道目前是在修哪一層。

從人像辨識走到球棒軌跡

另一條有趣的線是 Swing Arc。

Pose Coach 原本主要是做人像辨識,但最初就是我想分析自己的揮棒與投球

有先去做了一個 Python 版本,使用 YOLO 模型,在限定條件下看起來不錯

但是當要實作在 iOS 上還是得一步一步處理

  • YOLO 模型導入
  • 從偵測框推估球棒尖端 tipFromBbox
  • 用 pivot / tip 畫出球棒形狀 batPolygon
  • SwingArcState 管理軌跡
  • 加入 EMA 平滑
  • 加入 warmup
  • 加入 jump filter
  • 加入 speed threshold
  • 用 FIFO 控制 history 長度

這段我覺得很適合交給 AI 協助,但前提是要先拆成純函式和小狀態機。

tipFromBboxbatPolygon 這種幾何計算,如果直接藏在 Vision pipeline 裡,很難測,也很難知道 AI 寫錯哪裡。

但如果先拆成純函式,就可以先寫測試。

能先變成純函式的邏輯,就先抽出來測。

AI 寫 UI 或 pipeline 可能會受很多環境影響,但寫純函式時,只要測試夠清楚,就比較容易控制品質。

不只畫線,還要算速度

畫出球棒軌跡之後,下一個自然問題就是:

那速度呢?

這時候事情又變有趣了。

如果只是一般影片,可以用 frame 間距估速度。但慢動作影片會有時間軸問題。CMSampleBuffer 的 PTS 可能是放慢後的播放時間,不一定等於真實捕捉時間。

所以後來我在 spec 裡明確寫下:

速度計算要用 frameIndex + nominalFrameRate

也就是:

real_dt = frameDelta / nominalFrameRate

這樣 120fps 或 240fps 慢動作影片才不會被低估速度。

這個例子讓我更確定一件事:

AI 可以幫忙寫 code,但關鍵技術決策還是要先被講清楚。

如果 spec 沒有寫出 nominalFrameRate 這個決策,AI 很可能會直接用 PTS 算,然後得到一個看起來合理但物理意義錯誤的答案。

這系列會寫什麼

接下來這個系列,我想用 Pose Coach 當主線,記錄這幾個重構階段:

  1. 重新打開 2021 年的 Pose Coach
  2. 先把播放器救回來,重構成單一 Player + Feature 架構
  3. 用 Spec 重寫 Body Detection UI
  4. 讓第二台裝置也能看:螢幕分享 MVP
  5. 從 JPEG / H.264 重構到 WebRTC
  6. 從人像辨識到球棒軌跡:Swing Arc 的 TDD 開發
  7. 不只畫線,還要算速度:Swing Metrics 怎麼補上
  8. 回頭看:AI 對重構舊 iOS 專案最有幫助的地方

我不打算把它寫成 AI 工具教學。

比較想寫成一個真實的開發紀錄:

  • 哪些地方 AI 真的省了很多時間
  • 哪些地方 AI 很容易寫錯
  • 為什麼舊專案不能一口氣重寫
  • spec 和 plan 怎麼幫我控制重構範圍
  • TDD 怎麼讓 AI 產出的 code 比較可驗證
  • 專案哪些地方還是一定要靠工程師判斷

目前的感覺

如果要用一句話總結這段時間的感覺,我會說:

AI 沒有讓重構變得不需要思考。

它只是讓我可以把很多原本很花時間的步驟加速:

  • 幫我讀 code
  • 幫我整理 spec
  • 幫我拆 plan
  • 幫我補測試
  • 幫我做小步重構
  • 幫我檢查邊界情境

但方向要自己定。

哪些東西該保留,哪些東西該重構,哪些地方要先測,哪些問題必須上真機驗證,這些還是軟體開發人員自己的責任。

所以這系列比較像是一份紀錄:

一個舊 iOS 專案,在 AI 出現之後,可以怎麼被重新整理。

不是魔法,也不是重寫。

就是一步一步,把原本有點鬆散的東西,慢慢整理成更能繼續長大的樣子。