開發日誌 #1 - 設定系統開發與架構優化

這次做了什麼?

嘿!這次的開發重點是幫 Fast CLI Tool 加上一個「設定系統」。聽起來好像很簡單對吧?但其實這是一個很重要的功能。

故事是這樣的:一開始我們的工具已經可以管理多個專案路徑,也能選擇要用哪個 CLI 命令(claude.cmd、gemini.cmd 或 codex.cmd)來開啟這些專案。但問題來了——每次新增路徑時,程式會自動給它一個預設的 CLI 命令。這個預設值原本是寫死在程式裡的,完全不能改。

你可能會想說:「這有什麼問題?」問題可大了!如果我是個超級 Gemini 愛好者,每次新增路徑都得手動改成 gemini.cmd,用久了真的會很煩。所以這次的目標就是:讓使用者可以自己設定預設的 CLI 命令

聽起來簡單,做起來可是有不少眉角要注意呢!

用了哪些技術?

從「魔法參數」開始說起

在正式開發設定系統之前,我先做了一個重要的優化:消除「魔法參數」。什麼是魔法參數?就是那些突然出現在程式碼裡,沒頭沒尾的字串或數字。

舉個例子,原本的程式碼裡,PathItem 預設是用 claude.cmd,但在 MainViewModel 裡的備用值卻是 gemini.cmd。這樣不只不一致,而且如果未來想改預設值,還得到處翻程式碼找這些字串,超級麻煩!

所以我做的第一件事,就是把這個預設值提取成一個常數。現在所有地方都參考同一個來源,想改的話只要改一個地方就好。這就是「單一真實來源」(Single Source of Truth)的概念——聽起來很高大上,其實就是別讓自己未來頭痛而已。

MVVM 架構的妙用

Fast CLI Tool 採用的是 MVVM(Model-View-ViewModel)架構。簡單說就是把資料、畫面、邏輯分得很清楚。這次開發設定系統時,MVVM 的優勢就發揮出來了:

首先我建立了一個 AppSettings 模型,專門用來存放應用程式的設定(目前只有預設 CLI 命令,但未來可以擴充)。然後建立了 SettingsService 服務,負責把設定存到電腦裡(具體來說是 AppData 資料夾下的 JSON 檔案)。

最酷的是什麼?我用了 PropertyChanged 事件來做「自動保存」!只要使用者在設定畫面改了預設 CLI 命令,程式就會自動把新的設定存起來,完全不需要按「儲存」按鈕。這種無感的自動化真的會讓使用體驗提升不少。

WPF 的 Data Binding 魔法

UI 的部分用了 WPF 的 Data Binding(資料繫結)功能。簡單說,我在畫面上放了一個下拉選單,然後把它「綁定」到 ViewModel 裡的設定屬性。這樣一來,當你在下拉選單選了新的選項,ViewModel 裡的值就會自動更新;反過來說,如果程式載入了之前儲存的設定,下拉選單也會自動顯示正確的選項。

整個過程就像魔法一樣,完全不需要手動寫程式碼去抓取或更新畫面元素。這就是為什麼我喜歡 MVVM 架構——它讓程式邏輯和畫面完全分離,寫起來清爽多了。

JSON 資料持久化

設定要存到哪裡?我選擇了使用者的 AppData 資料夾,存成 JSON 格式。為什麼選 JSON?因為它簡單、易讀,而且 .NET 有內建的序列化工具,用起來超方便。

路徑資料存在 paths.json,設定資料存在 settings.json,各司其職。這樣的設計不只清楚,也方便未來擴充。而且我還加了完整的錯誤處理——如果檔案不存在就自動建立預設值,如果檔案損壞就用預設設定,絕對不會讓程式直接炸掉。

遇到什麼挑戰?

挑戰一:UI 設計的抉擇

一開始我在想:設定功能要放在哪裡?我考慮了幾個方案:

  1. 主視窗加個「Settings」按鈕,點下去彈出一個對話框
  2. 在右側面板新增一個設定區塊
  3. 用分頁(Tab)來切換「路徑詳情」和「設定」

最後我選了第三個方案:Tab 切換。為什麼?因為它給了使用者最大的彈性。如果未來設定項目變多,Tab 的方式可以容納更多內容,而且不會讓畫面變得擁擠。現在的設定很簡單,只有一個下拉選單,但誰知道未來會不會加入主題顏色、快捷鍵之類的設定呢?

做這個決定的時候我想了一陣子,因為 Tab 的實作會比單純加個按鈕來得複雜一些。但我覺得為了未來的擴充性,這個投資是值得的。

挑戰二:Tab 切換的狀態管理

Tab 切換聽起來簡單,做起來卻有不少細節要考慮。最大的挑戰是:當使用者在路徑詳情和設定之間切換時,要怎麼保持狀態?

一開始我的設計是:當切換到 Settings 時,把目前選擇的路徑清空(設成 null)。這樣做在邏輯上很合理——既然你在看設定,就不需要顯示特定路徑的詳情了嘛。

結果問題來了。當使用者想從 Settings 切回 Path Details 時,因為沒有選中的路徑,畫面就顯示「請選擇一個路徑」的提示訊息。這意味著使用者得重新點一次路徑才能看到詳情,超級麻煩!

我意識到這個設計不夠直覺。使用者的心理預期應該是:「我剛才在看某個路徑的詳情,跑去設定看了一下,回來應該還是看到同一個路徑才對啊!」

所以我改了設計:切換到 Settings 時不清空路徑選擇。這樣一來,當使用者切回 Path Details 時,就能看到剛才選的路徑,體驗流暢多了。

這個小改動讓我學到一件事:技術上正確的實作,不一定是使用者體驗最好的實作。有時候保留一點「狀態」反而更符合直覺。

挑戰三:Command 綁定的陷阱

實作 Tab 切換時,我原本想偷懶,直接用既有的 SelectPathCommand 來處理「Path Details」Tab 的點擊。但問題來了:這個 Command 需要一個參數(要選擇哪個路徑),而在 Settings 模式下,這個參數會是 null。

結果就是:點了 Path Details Tab 沒反應。

Debug 半天才發現,原來是 Command 裡面有個判斷:「如果參數是 null 就直接返回」。這在一般選擇路徑時很合理,但在切換 Tab 時就變成了問題。

解決方法其實很簡單:為 Tab 切換新增專用的 Command(ShowPathDetailsCommand 和 ShowSettingsCommand),不要和路徑選擇的邏輯混在一起。這也是「單一職責原則」的體現——每個 Command 只做一件事,清楚明瞭。

這個經驗告訴我:不要為了省幾行程式碼就把不同的功能混在一起。短期看起來省事,長期維護起來反而更麻煩。

挑戰四:自動保存的時機

實作自動保存時,我遇到一個有趣的問題:要在什麼時候保存設定?

一開始我想說:「使用者改了設定之後,等個幾秒再存」,這樣可以避免頻繁寫入檔案。但後來我想想,設定項目其實不多,而且改動頻率也不高(誰會沒事一直改預設 CLI 命令?),所以就直接採用「即時保存」的策略。

只要 PropertyChanged 事件一觸發,馬上就存檔。這樣做的好處是:絕對不會漏掉任何變更。缺點是?嗯… 目前還真想不到有什麼缺點,畢竟寫入一個小小的 JSON 檔案幾乎感覺不到延遲。

下一步

Phase 1 的設定系統算是打下了一個基礎。現在使用者可以自訂預設的 CLI 命令了,但未來還有很多可以擴充的方向:

  • 可以加入主題設定(深色模式?)
  • 可以讓使用者自訂快捷鍵
  • 可以記住視窗大小和位置
  • 甚至可以讓使用者匯入/匯出設定

不過這些都是後話了。現在最重要的是:設定系統的架構已經建好了,未來要加新的設定項目會變得很簡單。這就是良好設計的價值——前期多花點心思,後期可以省下十倍的力氣。

說實話,這次開發最大的收穫不是寫了多少程式碼,而是在設計 UI 和使用者體驗時的思考過程。技術問題都有標準答案,但「怎樣讓使用者用得舒服」卻沒有正確答案,只有更好的答案。每一次在這方面的嘗試和調整,都是一種成長。

下一個 Phase 要做什麼呢?還沒想好,但肯定會很有趣!


返回 Fast CLI Tool 專案