前一天,我把 RoomRush 前面 27 天的內容重新整合,畫出了專案總地圖。
當我可以把資料來源、Room Database、DAO、Repository、ViewModel、使用者功能和管理者功能串起來之後,我開始看到一些以前不容易注意到的問題。
例如:
不過我並不是要馬上改程式碼,而是把目前逐檔案閱讀時發現的問題整理成「可判斷優先順序」的工程改善清單;有些問題牽涉安全性,有些牽涉資料生命週期,有些只是可讀性或維護成本。
所以今天我想做的不是「挑出程式碼寫得不好的地方」,而是把這些問題當成工程上的觀察,試著回答三個問題:
ManagerActivity 未看到進入時檢查 isLoggedIn。onOpen() 重新匯入 CSV 且insertAll(REPLACE) 可能覆蓋管理者修改。classroomType == "Normal" 推導。notifyDataSetChanged() 使用較粗略。這些問題的嚴重程度並不一樣,透過和 Hermes Agent 討論優先級時,它提議不用因為「看起來不漂亮」就先去修改。
要判斷一個問題要不要先修改,我會先立一個判斷準:
| 問題 | 影響 | 風險 |
|---|---|---|
| 管理者帳密硬編碼於 App 中 | App 反編譯後可能外洩管理者入口資訊 | 中 |
ManagerActivity 未看到進入時檢查 isLoggedIn |
某些情境可能繞過登入頁進入後台 | 低 |
| 問題 | 影響 | 風險 |
|---|---|---|
onOpen() 重新匯入 CSV 且 insertAll(REPLACE) 可能覆蓋管理者修改 |
管理者修改課表 / 教室類型後,可能被 CSV 原始資料覆蓋 | 中~高 |
| DB 重建時,管理者新增的資料可能遺失 | 管理者新增資料不一定長期可靠 | 中 |
| 問題 | 影響 | 風險 |
|---|---|---|
是否可飲食不是獨立欄位,由 classroomType == "Normal" 推導 |
無法表示例外規則,例如某間一般教室不可飲食 | 中 |
| 問題 | 影響 | 風險 |
|---|---|---|
| 大樓、星期、節次、時間表等有硬編碼 | 新增大樓或調整時間表時要改多處程式 | 低~中 |
| 教室類型轉換邏輯重複 | 新增類型時容易漏改某些頁面 | 低 |
| Adapter 和頁面導航耦合 | Adapter 和 Activity 導航耦合,測試與重用較不彈性 | 低~中 |
notifyDataSetChanged() 使用較粗略 |
資料量變大時效能與動畫較差 | 低 |
| 檔案 / class / layout 命名不一致 | 閱讀與維護時需要額外對照 | 中 |
| 可能存在遺留或重複 ViewModel | 增加閱讀成本,查詢邏輯可能分散 | 低~中 |
| 完整課表使用反射讀取欄位 | 欄位名錯誤編譯器不會先抓到,重構風險高 | 中 |
在目前的 RoomRush 裡,我認為最值得注意的問題之一,是 CSV 和管理者修改之間可能產生的衝突。
前面 Day 17 | 我發現一個危險問題:管理者修改可能被 CSV 蓋掉我已經追過這條流程:
管理者修改課表 / classroomType
↓
Room Database
↓
下一次開啟資料庫
↓
AppDatabase.onOpen()
↓
重新讀取 SF.csv / ES.csv
↓
insertAll(REPLACE)
↓
可能覆蓋原本的資料
這個問題和一般的程式碼整理不太一樣。
例如把一段重複的轉換邏輯抽成 helper,改錯了可能只影響某個功能,但 CSV 的問題碰到的是「資料到底以誰為準」。
如果 CSV 裡是原始資料,而管理者已經在 App 中修改過資料,那麼:
CSV
↓
Room Database
↑
管理者修改
兩邊其實都可能被視為資料來源。
因此真正需要先回答的問題不是:「我要不要把 onOpen() 刪掉?」,而是:「RoomRush 的資料來源到底應該是誰?」
如果 CSV 只負責第一次初始化,那麼可以考慮限制匯入時機,但如果未來 CSV 本身也需要更新,就不能單純把重新匯入功能刪掉,而需要重新設計資料同步策略。
所以這個問題雖然重要,我反而不會把它列為第一個修改項目,因為它需要先把資料生命週期想清楚,再動程式。
例如:
這些共同特徵是:不需要改資料結構,也不需要重新設計核心資料流。
例如:
這些 改動本身不一定很危險,但可能影響既有 UI 或資料流程。
改動難點:它們不是改一個 class 就結束,而是會牽涉多個部分。
例如 foodAllowed 如果真的要獨立出來,就不是:
classroomType
↓
foodAllowed
這麼簡單。
還會牽涉:
Entity
↓
Database Schema
↓
Migration
↓
CSV
↓
Repository
↓
ViewModel
↓
UI
所以這類改善就不適合在還沒有完整理解資料流的時候直接動。
如果真的開始改善,我也不能只確認 App 可以成功編譯,因為 RoomRush 是一條完整的資料流程,某一層改動可能影響後面的功能。
所以每次修改後,我至少會重新確認:
一般使用者
✓ 可以查詢空教室
✓ X / null 判斷正常
✓ 可以進入教室詳細資訊
管理者
✓ 可以登入
✓ 可以修改課表
✓ 可以修改 classroomType
✓ 可以新增教室
✓ 可以查看完整課表
✓ 登出後無法直接進入後台
對我來說,這也是「能跑」和「真的能放心修改」之間的差別。
前者只代表目前的功能沒有明顯壞掉;後者則需要知道自己改了什麼、可能影響什麼,以及怎麼確認其他功能沒有一起被改壞。
整理完 RoomRush 的主要流程後,我沒有直接把所有問題都視為「錯誤」,而是先把它們分成安全性、資料持久性、資料設計與可維護性四類。
這樣做的好處是,後續改善時可以先判斷哪一些改動風險低、價值高,哪一些雖然重要但需要更多測試。
我認為最需要注意的是 CSV 重新匯入資料的策略。因為管理者功能已經可以修改課表與教室類型,但 AppDatabase.onOpen() 又會重新匯入 CSV 並使用 REPLACE,這讓管理者修改過的資料可能被原始 CSV 覆蓋。這不是畫面層的小問題,而是資料生命週期設計上的問題。
另一方面,也有一些低風險改善可以先做,例如在 ManagerActivity 補登入狀態檢查、抽出教室類型轉換 helper、整理命名對照、盤點未使用的 ViewModel。
這些改善不一定會立刻讓功能變多,但會讓專案更安全、更容易讀,也更適合展示成作品集。
整理技術債後,我學到的不是「這個專案有哪些地方可以改」,而是開始學著用另一個角度看程式碼:問題有多嚴重?修改的成本是多少?改了之後會不會影響原本的功能?
下一篇是這個系列的最後一天,我會回顧從這系列開始到結束,自己有了哪些收穫和可能需要的改進,以及更重要的未來規劃;希望透過這系列,自己對於不論是開發一個 App 或是學習 Kotlin 都更有概念。