系統設計時要避免的 3 個誤區
2024年12月16日
系統設計幾乎是現代後端與全端工程師,在工作與面試中高頻率會要面對的議題;然而,在剛接觸系統設計時,很容易踩到一些坑,讓最終的設計品質不如預期。
對此,在這篇文章中,我們會討論一些在工作上或面試中,做系統設計時常見的誤區。推薦讀者們可以把這篇提到的點,當做一個檢核清單,在工作上或準備面試時,可以拿來檢核,確保沒有不小心踩到類似的坑。
沒有確認解決對的問題
由於工程師的職責是要解決問題,最終需要端出解決方案,很多時候會不小心就一頭熱於「解決」上,而沒有先去確認解決的問題,是不是對的問題。
試想下面兩種情境,讀者們覺得哪一個帶來的效益比較高呢?
- 有絕妙的解法,但是解決錯的問題
- 解法可能還不是最佳解,但是解決對的問題
相信多數人會認為是第二種狀況效益會高。因為第一種狀況,即使解決方法本身很絕妙,但解錯問題,導致的結果是原本的問題完全沒有被解決到。這就像在面試中,提出一個很精妙的演算法,但是因為解錯問題,原本的問題的測試案例全都沒有通過;又或者在現實工作中,打造出一個看似很厲害的產品,結果沒有幫使用者解決問題,無法創造價值,導致沒有人買單 (詳細見先前我們寫過的 技術上很困難,但對使用者沒價值的事 一文)。
假如要避免自己踩了這種坑,一個有效的方法,是問自己是否「聽到問題後,總會想要直接跳下去解問題?」,如果是的話,很可能就會踩到這種坑。
舉個具體的例子來說,假如要設計短影音系統,假如沒有多去釐清問題,可能一開始就會想到現有短影音平台的優勢是演算法,所以需要有一個更強大的演算法,因此需要有有各種方法搜集使用者偏好,藉此調教演算法。
然而,很可能工作上的產品經理或面試中的面試官,不是想討論傳統短影音系統的設計 (例如 BeReal 就提出完全不同類型的短影音概念,不已演算法為主心,且相當受到歡迎),這時如果直接跳到想演算法為中心的設計,就會變成解錯問題。
先發散再收斂
假如你發現自己總會想要直接剃下去解問題,該如何有效改掉這個習慣呢? 一個推薦的方法是有意識提醒自己「先發散再收斂」,在沒有發散之前,不要下任何定論。
所謂的發散,是去探索問題,具體來說:
- 在工作上,一定要多對產品經理提問,了解產品的願景與方向、想帶給使用者的價值等等
- 在面試中,要先花時間跟面試官提問,至少面試開頭前五分鐘,應該都要專注於問問題
在探索問題時,推薦要探索目前有的限制。在軟體工程領域,很多時候加上限制後,解法會完全不同。如過前期沒有先探索限制,很可能導致想完解法後,才發現不符合實踐狀況,導致必須要重新設計
除此之外,在發散的過程中,要有效辨別極端狀況 (edge cases)。畢竟如果只想到正常情況 (happy path),其他人也想得到,這樣就沒辦法體現資深的價值。如果對這個要點感興趣,推薦讀先前我們寫過的《考量極端案例 (edge case) 是工程師的基本功》一文。
花太多時間在不重要的細節上
在一個系統中,通常會有很多細節可以討論,然而在實際工作中,大家能一起開會的時間有限,不該把時間浪費在不是核心的細節上。當講太多不是最重要的細節,會讓討論變得冗長且失焦。而在系統設計面試中時間更短 (通常是在 45 到 60 分鐘左右),如果不拉出重點來講,而僅是談一些細碎的面向,非常可能無法通過。
舉例來說,如果今天是要設計一個社群媒體系統,這種系統比起其他系統,最常見的問題是,會在極短時間湧入極大量的流量,這是許多其他系統不會有的問題。所以如果在討論社群媒體系統時,沒有去討論如何處理尖峰時段的吞吐量問題,在面試中可能會被認為沒有抓到重點,進而無法通過。
同樣地,如果是在討論金流相關系統,在金流系統中最會被擔心的問題,是重複收費或者餘額不足卻能成功支付,畢竟如果出現這類問題的話,估計沒有人敢再用該金流系統。而要解決這問題,在分散式的狀況下,如何確保不同節點之間能維持一致性 (consistency)。同樣地,如果在面試時被問到這種系統,卻沒有去討論一致性問題,很可能就會被認為不知道如何抓重點。
要辨別核心,可以看一些不同的重要面向:
- 一致性要求:上面提到的金流系統外,常見的搶票系統也需要確保同個位置不會被多個人同時買到
- 讀寫比例:寫多於讀或讀多於寫的系統,要關注的面向會很不一樣
- 流量:社群網站類型的系統,很可能會在某個事件高峰 (例如 Talor Swift 演唱會) 而有大量的流量灌入
- 效能:交易類的系統,幾要有幾毫秒的延遲,就可能導致錯失交易機會
前一個段落提到的「確保解決對的問題」之所以重要,是因為這樣能確保在設計時,能夠把時間花在該花的細節上。
假如今天要設計一個庫存管理系統,在了解需求後,會理解到因為庫存管理多半是 2B 的系統,所以用的人不多,但是對庫存精確度的掌握需要很高。在這種情況下,如果沒花時間討論一致性,而是花時間討論流量優化,將會浪費寶貴的時間,務必要避免。
解法不符合系統的脈絡
在系統設計時,符合系統脈絡非常重要。很多時候,符合脈絡的設計,是好過於「遵守最佳實踐」的設計。這是因為真實世界的系統,要考慮的面向很多,而理論上的最佳實踐,可能僅在某些條件下適用。因此,推薦不要針對某些問題,在對於脈絡了解不夠清楚的狀況下,就直接選某個看似最佳實踐的方式。
舉例來說,「因為快取能協助加速與減少運算,於是在任何地方都加上快取」就是個很典型的不考慮脈絡的陳述。因為技術的選擇背後往往有取捨,沒有考量脈絡,直接強加,很可能會有預期外的負面效益。
以快取來說,當選擇快取意味著會有資料不一致的狀況,同時代表多一個快取元件要維護,增加系統的複雜度。在某些狀況下,快取的效益能讓這些負面的點被接受,但不是所有狀況都是。
就常見的電商系統來說,商品資訊可能是適合快取的對象,因為讀取量大,快取能幫上很大忙,同時更新頻率不高,相對不擔心一致性的問題。
但是庫存管理的部分,可能就不太適合快取,因為庫存的變動頻繁,且要追求準確,特別是在聖誕促銷等檔期時,庫存變動又會更快,要避免消費者買到已經沒貨的東西這種狀況,就要盡可能減少不一致,這時加上快取可能就不是個好選擇。
閱讀更多
如果你對「系統設計要避免的誤區」這主題感興趣,我們在 E+ 有更深入的討論。有興趣的讀者,歡迎加入 E+ 成長計畫。
本文為 E+ 成長計畫的深度內容,截取段落開放免費閱讀。歡迎加入 E+ 成長計畫閱讀完整版本 (點此了解 E+ 的詳細介紹)。