Skip to content

程式碼優化與重構的衡量思路

進行優化與否的判斷

為甚麼要進行程式碼優化與重構

  1. 既有的程式碼產生了Bug,或是為了要擴展新功能
  2. 讓同仁或是我自己在開發可以有更好的方式進行開發
  3. 單純覺得效能跟可讀性可以再更好

甚麼時候不要進行程式碼優化與重構

  1. 如果舊的程式碼已經達到預期的效果,並且沒有產生Bug
  2. 既有的邏輯或是型別已經在多個地方被使用,造成相依性太強,無法梳理出究竟會影響到哪裡、會不會產生不可預期的錯誤或是問題

舉例說明

這是根據實際上遇到的問題需求提出的相似解法。

1. 從Array.find 改用 new Map().get()

typescript
import { ref } from "vue";

const items = ref<Item[]>([]);

const findItem = (id: string) => {
  return items.value.find((item) => item.id === id);
};
typescript
import { ref, computed } from "vue";

const items = ref<Item[]>([]);

const itemById = computed(
  () => new Map(items.value.map((item) => [item.id, item])),
);

const getItemName = (id: string): string => {
  const item = itemById.value.get(id);
  if (item === undefined) return "";
  return item;
};

這邊的寫法對照的是同一個需求(依 id 從列表拿出資料),但刻意拆成兩種結構,方便說明我怎麼決定要不要換寫法。

實務上 很多畫面與流程都會載入不小的列表:依客戶規模,常見可能是從數十筆到數千筆資料不等。

第一種保留 ref 裝列表,需要時再 find:實作最短、一眼能懂,資料量小、或查找次數少時,維護成本通常最低。

第二種把 items 仍放在 ref,查詢用的索引改由 computedMapitems 一變,Map 跟著重算一次;之後多次 .get(id) 近似常數時間,能 大幅減少重複查找所花的時間。代價是 多保留一份以 id 為鍵的索引結構,記憶體負擔會比單純陣列略高;但在「筆數多、查找又密集」的情境下,通常仍值得用少量記憶體換流暢度。空值則在函式裡用 if 明確處理成 "",避免上層模板或呼叫端到處寫 optional chaining,顯示路徑也比較一致。

決定要不要換寫法,取決於客戶實際資料量、操作時的查找頻率,以及你是否願意用多一點記憶體與一次性的 Map 建置,換後續大量查找的成本。若情境已經落在「千筆級列表+表單/服務內高頻查 id」,我會傾向第二種;若列表短、查找也少,第一種就夠用,也符合前面說的「舊程式已達預期就不必硬優化」。

請注意!

當 items.value頻繁變化(例如即時更新、WebSocket 推送、表單編輯後 refresh 等)時,每次 items 一變就會重建整個 Map。 在千筆資料下,重建 Map 的成本(O(n))如果太頻繁,可能反而抵消掉 .get() 帶來的優勢,甚至造成短暫卡頓。

2. 減少 API 請求次數

做法一POST 成功後再打一支列表 GET,把 ref 整包換成最新資料。

typescript
const items = ref<Item[]>([]);

const submitCreate = async (payload: CreatePayload) => {
  await api.createItem(payload);
  //   這裡簡略不做錯誤處理
  items.value = await api.fetchItems();
};

做法二POST 成功後,API 回傳新建資料,直接 pushitems,不再打列表 GET

typescript
const items = ref<Item[]>([]);

const submitCreate = async (payload: CreatePayload) => {
  const created = await api.createItem(payload);
  //   這裡簡略不做錯誤處理
  items.value.push(created);
};

這樣做是為了 少打一次 API(省掉成功後那支列表 GET)。因為列表資料一多,整包重拉會比較慢、也較耗流量;既然 POST 已經回傳新建好的那一筆,直接併進 ref 就夠更新畫面,不必再多打一輪。同時也可以降低使用者的等待時間。

小結

以上兩點是我實作與重構時 印象比較深 的例子。若之後還想到其他情境,會再補上後續說明。