👓看不懂的程式怎麼變好讀?用真實範例帶你重整 Vue 3 + ASP.NET Core + EF Core 專案

 新手常問:「程式能跑就好,為什麼還要『重整(Refactor)』?」

答案:因為專案會長大、會交接、會改需求——今天看得懂,三個月後也要看得懂。這篇用實際專案片段(Vue 3 前端、ASP.NET Core API、EF Core 實體與資料處理服務)一步一步把「可讀性」與「維護性」講清楚,讓不懂程式的人也能看懂工程師在做什麼


#1 為什麼「可讀性」與「維護性」這麼重要?

  • 可讀性:像寫給未來的自己/同事看的說明書。越好讀,改錯率越低。

  • 維護性:遇到新需求、異常或交接時,能快速定位與修改。

  • 直接影響成本:好讀好修=少踩雷、快交付。


#2 這個專案是什麼?(技術地圖)

  • 前端:Vue 3(Composition API)、Pinia(全域狀態)、SheetJS(XLSX 匯出 Excel)

  • 後端:ASP.NET Core Web API(C#)

  • 資料層:EF Core(連 Oracle)、Entities(資料表對應模型)

  • 商業邏輯層:ApsDataProcessor(把零散資料整合成前端要的格式)

你可以把它想成:
前端是櫃檯、API是點餐系統、EF Core/DB是廚房、Processor是總鋪師——把食材變成客人要的菜。


#3 前端:如何把頁面寫得好懂(以 PageThree.vue / PageFour.vue 為例)

3-1 格式化與命名

  • 狀態區、API 區、工具函式、生命週期分區清楚(加醒目分隔線註解)。

  • 命名用名詞 + 動詞fetchPlanVersionsexportExcelinitUniqueFilters1

3-2 每個函式都有註解(JSDoc)

/** * 依目前選取的版本,拉取「表一」資料並初始化篩選器。 * 失敗時重置資料避免殘留舊狀態。 */ async function fetchTableData1() { ... }

3-3 把「多用途」的工具抽出去

像把 A001~A210 這種動態欄位,或日期/數字格式化,統一由小工具處理(避免每頁重複寫)。

/** 將 yyyy-MM-ddThh:mm 轉成 yyyy/MM/dd */ function formatDate(val) { ... } /** 是不是數字(字串先去千分位逗號) */ function isNumeric(val) { ... }

3-4 匯出 Excel:用 SheetJS,但留給未來的自己一條活路

  • 表頭(headers)動態日期欄格式化邏輯獨立出來;

  • 每個欄位的格式(整數/小數)在程式裡就定義清楚。

function exportTable1() { // 1) 檢查資料 // 2) 組表頭:左固定欄+動態日期欄+右固定欄 // 3) 組資料列:依日期欄 a001, a002... // 4) 設定數字欄位格式(#,##0) // 5) 下載檔名含版本 }

3-5 UI/UX 小細節

  • Sticky 表頭/側欄:大表格也能追得上。

  • 下拉篩選(全選/全不選、一鍵清除),存回 Pinia,換版本自動重設。


#4 後端:DataController 寫法——好維護的 API 有哪些共通點?

  • 路由一致/api/data/GetAPSZRESULTEGetAPSZRESULTF,語意清楚。

  • 輸入驗證:必要參數空白就回 400(BadRequest)。

  • AsNoTracking:查詢用資料一律不追蹤,減少 EF 的負擔。

  • 錯誤處理:try-catch 回 500,訊息簡潔。

  • 投影(Select):只回前端需要的欄位,並在伺服器端統一把日期/數字格式化

對非工程師的一句話:API 就像菜單,每道菜(端點)都寫明材料(參數)和端出來的樣子(回傳欄位)。


#5 商業邏輯層:ApsDataProcessor(資料整形總鋪師)

5-1 單一職責:控制器瘦、服務層胖

  • Controller 只負責「接單出單」;

  • Processor 負責查資料、合併、格式化(日期 yyy-MM-dd、數字千分位)。

5-2 反射快取:A001 ~ A210 的「欄位複製器」

表中有 A001、A002…一直到 A210。不同版本日期數量不同,就用 CopyAColumns 來「只複製需要的數量」,其餘補 null
重點:這段被封裝成一個小函式,任何人要改只改這裡。

/// 將來源物件的 A001~AXXX 複製到目標;超出 validCount 的欄位設為 null。 /// toThousandString = true 時轉千分位(E 報表),false 則保留原型別(F 報表)。 private static void CopyAColumns( object src, PropertyInfo[] srcProps, object dst, PropertyInfo[] dstProps, int validCount, bool toThousandString) { ... }

5-3 小工具一律集中管理

  • FormatDate(DateTime?)yyyy-MM-dd

  • FormatNumber0(decimal?)#,##0

  • ExtractPrefix("NB_W2513_20250430.01")W2513

對非工程師的一句話:這些就像「醬料罐」,任何菜要加醬都從同一罐拿,味道才會一致。


#6 EF Core 實體(Models):欄位清楚、輔助屬性友善

  • 每個欄位都用 [Column("DB欄位名")] 明確對應。

  • 需要主鍵時加 [Key](複合主鍵則在 OnModelCreating 設)。

  • 若前端常需要漂亮字串(例如千分位或日期),可以加 [NotMapped] 輔助屬性,但商業邏輯仍放在服務層

我們也示範了在 APS_U_NINE 增加 Create(...) 工廠與 IsValid(...) 檢核,讓建立資料基本驗證更直覺。


#7 把「查資料+匯出 Excel」流程寫得好懂(一步驟地圖)

  1. 前端選版本 → 觸發 fetchTableDataX()

  2. API 收到版本 → Controller 驗證參數 → 呼叫 ApsDataProcessor

  3. Processor:查主檔+日期檔 → 整形成前端要的格式(含 A001~A210)

  4. 回前端:表格呈現、可篩選 → 點「匯出 Excel」

  5. SheetJS:組表頭、寫資料、設定欄位格式 → 下載 .xlsx


#8 常見 10 大地雷與修正

  1. 函式太長 → 拆小、每段加註解。

  2. 魔法字串/數字 → 用常數或列舉(e.g., MaxA = 210)。

  3. 重複程式碼 → 寫工具函式(formatDateCopyAColumns)。

  4. 沒錯誤處理try-catch+對前端友善訊息。

  5. 資料庫查太多欄Select 只拿需要的;AsNoTracking

  6. UI 沒提示 → Loading、無資料、篩選結果為空要清楚。

  7. 檔名/欄位格式混亂 → 統一命名規則與格式(yyyy-MM-dd、#,##0)。

  8. 函式沒有註解 → JSDoc / XML Doc 標準化。

  9. 狀態散落 → 用 Pinia 集中管理(如 globalApsVersion)。

  10. 路由不一致 → API 命名語意一致(GetXxxByYyy)。


#9 FAQ:非工程師也能懂的小辭典

  • Pinia:Vue 的全域資料儲存(像一個共享記事本)。

  • AsNoTracking:查資料時不做「變更追蹤」,更快、更省記憶體。

  • SheetJS:讓前端能把資料存成 Excel。

  • EF Core:C# 的 ORM,把資料表映射成類別操作。

  • Processor:服務層,專門把資料「整理成前端好用的樣子」。


#10 附錄:標準註解模板

C# 檔頭(類別)

/*************************************************************** * 檔案名稱: ClassName.cs * 功能說明: <一句話描述> * 主要特性: <條列重點> * 使用說明: <如何被呼叫/相依套件> * 注意事項: <容易踩雷/效能/安全> ***************************************************************/

C# 方法(XML Doc)

/// <summary>說明這個方法做什麼、為什麼需要它。</summary> /// <param name="apsVersion">必填,APS 版本號。</param> /// <returns>整形後的資料清單。</returns> /// <exception cref="ArgumentException">參數空白時拋出。</exception> public async Task<List<APSZRESULTE>> GenerateAPSZRESULTE(string apsVersion) { ... }

Vue / JS(JSDoc)

/** * 依選取的版本拉資料並初始化篩選器。 * @returns {Promise<void>} */ async function fetchTableData1() { ... }

結語

把程式寫「給人看」比「給電腦看」更重要。
這篇示範了前端(Vue 3 + Pinia + SheetJS)、後端(ASP.NET Core)、資料層(EF Core)如何用註解、命名、分層、工具抽取讓專案更可靠、更好交接。
下次你打開一支看不懂的程式,試試:先把區塊切清楚、加上目的說明、把重複邏輯抽出成函式——你會發現維護速度真的快很多 🚀


延伸關鍵字(SEO)
Vue 3 可讀性、Composition API 重構、Pinia 全域狀態、SheetJS 匯出 Excel、ASP.NET Core Web API 範例、EF Core Oracle、C# Clean Code、資料表對應 Entity、A001 A210 動態欄位、日期數字格式化、API 設計最佳實務、程式碼可維護性指南

留言

這個網誌中的熱門文章

🛠【ASP.NET Core + Oracle】解決 ORA-00904 "FALSE": 無效的 ID 錯誤與資料欄位動態插入顯示問題

🛠【實戰排除教學】從 VS Code 的 _logger 錯誤,到 PowerShell 找不到 npm/serve,再到 Oracle ORA-03135 連線中斷——一次搞懂!

🔎如何在 Oracle PL/SQL 儲存過程中為文字欄位加入換行符號(CHR(10))——以 Updlcmremark 為例