iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0
佛心分享-IT 人職涯歷練

從 UI/UX 麻瓜到工程魔法師|從讀懂程式開始系列 第 25 篇

Day 25|套件明明可以硬改,為什麼最後反而選擇換一種元件?

  • 分享至 

  • xImage
  •  

上一篇講到:

不要急著重做 Component,也許只是還沒看懂它原本提供的參數。

但今天剛好要講另一面。

有時候我們已經確認:

這個 Component 有很多參數
也真的可以繼續硬改
甚至最後可能做得到

但做著做著會開始出現另一個問題:

為了讓它符合需求,我是不是已經寫太多「對抗元件本身設計」的邏輯了?

這時候真正該問的,可能已經不是:

「還能不能做?」

而是:

「還值不值得繼續這樣做?」


一個很典型的情境:Date Range

假設需求是:

開始日期
+
結束日期

最直覺可能會想到:

<DateRangePicker />

因為它本來就是拿來選一段日期範圍。

使用者通常可以:

選 Start Date
↓
選 End Date
↓
中間顯示一段 Range

這個 Component 很適合:

一般的日期範圍選擇

但需求如果開始加入一些特殊規則:

End Date 可以是 Indefinite

某些情況只允許改 Start Date

某些情況只允許改 End Date

兩個日期可能有不同 disabled 規則

其中一個欄位可能沒有日期

事情就開始不一樣了。


原本的 Component 有自己的互動模型

RangePicker 的核心概念通常是:

Start
↓
End
↓
形成一個 Range

也就是:

這兩個日期本來就是「一組」。

所以元件本身會幫我們處理很多事情:

開始日期
結束日期
範圍預覽
disabled date
panel interaction
range highlight

這些原本都是優點。

但如果需求開始變成:

Start 跟 End 要有不同生命週期

那原本「綁在一起」的優點,

反而可能變成限制。


一開始很容易繼續加判斷

例如想做到:

Start 可以選
End 不可以選

可能開始找:

disabled
disabledDate
onCalendarChange
onChange
open
value

然後加:

條件 A
條件 B
條件 C

第一個情境修好了。

但測第二個流程:

又壞了。

再補:

條件 D

然後第三個操作方式:

又出現新的問題。

最後很容易變成:

需求本身其實不複雜

但為了維持 RangePicker
↓
程式越來越複雜

這時候我會開始問:是不是選錯抽象了?

這是我後來覺得很重要的一句話。

有時候不是:

我還不夠會用這個 Component。

而是:

這個 Component 的設計模型,本來就和現在的需求不完全一致。

例如需求實際上比較像:

Start Date
→ 一個獨立欄位

End Date
→ 另一個獨立欄位

Indefinite
→ 控制 End Date 是否存在

那真正的資料模型其實是:

Start Date
+
End Date
+
Indefinite

而不一定是:

一個 Range

如果是這樣,兩個 DatePicker 反而可能更自然

例如:

<DatePicker
  name="startDate"
/>

<DatePicker
  name="endDate"
/>

概念變成:

Start Date
↓
自己控制

End Date
↓
自己控制

需要限制:

End 不能早於 Start

就針對 End Date 寫。

需要:

Indefinite = true

就直接:

停用 / 清除 End Date

資料責任變得比較清楚。


這不是因為「兩個 DatePicker 比 RangePicker 高級」

完全不是。

如果需求就是:

請選 2026/01/01 ~ 2026/01/31

RangePicker 反而非常合理。

因為:

UI 模型
=
資料模型
=
使用者心智模型

都是:

一段日期範圍

真正要判斷的是:

現在的需求還是不是一個真正的 Range?


當元件開始需要很多「例外」,就是一個訊號

我現在會特別注意這些跡象:

為了某個需求一直 override 預設行為

很多 if 都在處理元件特殊狀態

需要阻止原本 Component 很自然的互動

修一個流程又破另一個流程

測試情境一直增加

程式開始比需求本身還難理解

這時候我會停一下。

問:

我是不是正在跟 Component 打架?


「做得到」和「值得做」是兩個問題

例如:

方案 A
繼續使用 RangePicker

技術上可能:

可以做到

但需要:

大量 disabled 判斷
額外 state
控制 panel
處理 preview
處理特殊選取順序
大量 edge case

另一個方案:

方案 B
拆成兩個 DatePicker

可能只需要:

Start Date 規則
End Date 規則
Indefinite 規則

兩個方案都能完成需求。

但:

完成需求

不是唯一評估標準。

還要考慮:

複雜度
可讀性
測試成本
未來維護
使用者體驗
跟既有頁面的一致性

我現在會開始算「複雜度成本」

以前選方案可能只看:

哪個最快做出來?

但現在會多看:

今天寫完容易嗎?

三個月後還看得懂嗎?

需求再改一次會不會爆炸?

下一個工程師敢不敢碰?

要測多少種操作流程?

這些其實都是成本。

只是它們不一定會直接出現在工時表裡。


UI Component 本身也代表一種約束

這點我以前比較少想到。

當選:

RangePicker

不只是拿了一個外觀。

也等於接受:

它的互動方式
它的 State 模型
它的事件設計
它對 Start / End 的關係假設

同樣地:

Select
AutoComplete
DatePicker
Table
Form

每個 Component 都不只是長相。

它背後都有一套:

它認為這個問題應該怎麼被操作。


所以 Component 選擇其實也是資料模型選擇

例如:

RangePicker

比較接近:

[startDate, endDate]

也就是:

兩個值組成一個範圍。

而兩個獨立 DatePicker:

startDate
endDate

比較接近:

兩個互相關聯,但仍然獨立的欄位。

如果需求還有:

indefinite = true

那第二種模型可能更自然:

startDate
endDate
indefinite

而不是硬把:

indefinite

塞進 RangePicker 的原始互動模型裡。


我覺得這是 UI/UX 背景很有幫助的地方

做 UI 時,我們會問:

使用者到底在完成什麼任務?

到了前端,

其實也可以拿同一個問題判斷 Component。

例如:

使用者是在「選一段 Range」?

還是:

使用者是在「設定開始日期,並決定是否有結束日期」?

兩句話很像。

但它們其實代表不同的互動模型。

如果第二種才是真正需求,

那拆成:

Start Date
End Date
Indefinite

可能比 RangePicker 更符合使用者心智模型。


工程師不是一定要把現有方案救到底

有時候已經投入一段時間,

會很容易產生:

我都做到這裡了,再補一個判斷應該就好了。

然後:

再補一個
↓
再補一個
↓
再補一個

最後變成一個很難維護的區塊。

這其實有點像:

沉沒成本

已經花掉的時間,

不應該成為:

繼續使用錯誤方案的唯一理由。

如果重新評估後發現:

換模型比較簡單

那重整方向不代表前面白做。

因為前面的嘗試至少讓我們確認:

這個 Component 的限制在哪裡。


但也不能一遇到困難就換 Component

另一個極端也不好。

如果:

只是還沒讀文件
只是少一個 Prop
只是某個 API 不熟

就直接換掉,

又會回到上一篇的問題:

沒有理解現有工具,就重新發明。

所以我現在會用兩階段判斷。


第一階段:先確認工具能力

看文件
↓
看 Props
↓
搜尋 Existing Pattern
↓
確認 Component 原本支援什麼

如果有簡單設定可以完成:

沿用。

第二階段:確認需求是否仍符合元件模型

如果已經確認:

不是少一個 Prop

而是:

需求本身和 Component 的互動模型衝突

那才開始比較:

繼續客製
vs
換更適合的 Component

我現在會這樣做方案比較

例如:

需求:
Start Date
End Date
Indefinite

方案 A:RangePicker

優點
→ 原本就是日期區間
→ UI 緊湊
→ 一般 Range 操作方便

成本
→ Start / End 綁得比較緊
→ 特殊 disabled 流程較複雜
→ Indefinite 需要額外處理

方案 B:兩個 DatePicker

優點
→ Start / End 分開控制
→ 驗證規則比較直覺
→ Indefinite 比較好處理

成本
→ 要自己維護兩者關係
→ 例如 End 不能早於 Start
→ UI 需要自己安排

這樣討論就不再是:

哪個比較厲害?

而是:

哪個的成本比較符合現在的需求?


這也是我開始學到的「工程 Trade-off」

很多問題其實沒有:

唯一正確答案

而是:

方案 A
有 A 的優缺點

方案 B
有 B 的優缺點

最後依照:

需求
維護成本
風險
一致性
時間

做選擇。

這就是:

Trade-off

取捨。


我現在不會只問「能不能做到」

看到需求,

我會開始問三層:

第一層
能不能做?

第二層
用現在這個 Component 做,複雜度是多少?

第三層
有沒有更符合需求模型的做法?

這三個問題,

比單純:

找一段能跑的 Code

更接近真實開發。


今天真正想記的是

上一篇:

不要太快重做,先確認原本工具能不能做到。

今天則是另一半:

確認過之後,也不要因為「技術上做得到」,就硬把原本 Component 留到底。

因為好的方案不只是:

現在能跑

還應該考慮:

未來好不好懂
好不好測
好不好改
是不是符合真正的資料模型

所以我現在遇到元件問題,

會先問:

我是在使用這個 Component,
還是在對抗這個 Component?

如果越寫越像後者,

那可能就是重新思考工具選擇的時候了。

下一篇可以進到另一個非常容易讓人第一次看到時滿頭問號的工程問題:

Route 為什麼有順序?/:id 怎麼可能把別的網址吃掉?


上一篇
Day 24|不要急著重做 Component,也許你只是還沒看懂它原本提供的參數
下一篇
Day 26|/:id 怎麼把別人的網址吃掉了?Static Route 和 Dynamic Route 到底差在哪?
系列文
從 UI/UX 麻瓜到工程魔法師|從讀懂程式開始 共 26 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言