最近武漢肺炎襲捲全球,台灣因「超前部署」而躲掉許多其他國家遭遇到的危機。防疫應該「超前部署」,那麼軟體開發是否也應該「超前部署」呢?
緣起
所有進行軟體/系統開發的人一定會面臨一個問題,那就是當你拿到客戶需求時,你到底要不要如質如實地做,還是應該替客戶預先想到一些未來可能面臨的問題?
這不是會寫在教科書裡的問題,也沒有標準答案。如果你拿這個問題去問不同背景的資深工程師,你問幾個人就會得到幾個答案。
我個人並不是一開始就寫程式的;雖然我是資工本科系,但我的職場生涯一開始是擔任產品經理(Product Manager)的職位,後來又做過技術客服(Technical Support)和 QA 的工作,然後才回頭去寫程式。所以我有一個職業病,就是習慣去評估一個系統的後續客訴及產品生命週期等雜事。
但是我的主管並不是每個都認同我的想法。尤其是以業務導向的那種主管,總覺得趕快做一做趕快收錢就好,所以客戶要什麼就給他什麼,「不要多問」! 我在這種主管的手下做過一小段時間,也的確照著他的要求去做了。結果如何呢?當然是慘不忍睹。因為許多主管根本就是沒肩膀的混蛋,既要你完全遵從命令,當發生問題時,卻責怪你說「為什麼當初沒想到」!?
我換了很多工作,也換了很多老闆,總算看清楚了人性。講白了,人性本是如此,而且每個人不一樣。如果無法隨遇而安,就換個工作吧! 而且嚴格地講,難道我自己都沒有錯嗎? 應該也是有的。不過,這種問題無關技術,在這裡就不多發牢騷了。
面向
(A) 如果你工作的環境是有嚴格分工的團隊,事情可能會輕鬆一點。或許你拿到的需求甚至已經切分到 Module 了,你只需要負責 implement 就好。
(B) 如果你既然要做需求訪談、又要做開發、又要管資料庫、又要做測試(你就是那一條龍), 那麼你要負的責任就大了。在這種情況下,「為什麼當初沒想到」就真的是你的問題了。
從 A 到 B 的廣大模糊地帶,大概就是所有開發者所處的環境。但是不管你處於哪一種環境中,我們面對的問題其實是一樣的,只是分擔問題的比例不同而已。怎麼說呢?
我們必須從使用者的角度來看事情。或許我們必須事先搞清楚你的使用者是誰、是哪種人。客戶有百百款,有一種極端是「如果需求沒有就默默吞了」;另一種極端則是「需求沒有,但為什麼你當初沒有幫我想到?」。從這種極端到那種極端的各種客戶我都遇到過。
我們先不要討論誰是奧客,我也不打算在這裡討論什麼奧客的應對技巧什麼的。我只是單純地想把我的經驗拿出來給大家參考而已。
首先,客戶永遠是對的。這是大原則。但這並不表示客戶真的永遠是對的;我的意思是應該盡量尊重客戶的要求,即使很難溝通。
其次,醜媳婦也要見公婆;當系統到了測試階段,就是「真正的需求」正式開始談的時候了。相信我,大部份的客戶都是等到系統做出來以後才開始想需求。不管你的開發環境是從 A 到 B 的中間哪一種,都難免遇到這樣的情形。
所以,我們不妨把時間拉回到你剛剛開始設計系統的時候。
千金難買早知道
我曾經遇到過幾個極端的情形。以下舉例說明:
案例一
客戶跟我說他的用戶都使用身分證驗證身分,還指明說他要使用身分證字號當作 PK。我當時還很驚訝地問他怎麼知道 "PK" 這個專有名詞。但主管當場要我別多問,照辦就好。
系統上線幾個月之後,他的問題來了。首先,他遇到一個外國用戶;他沒有身分證字號,而他很堅持要註冊。
再過幾個月,又有問題了。他遇到身分證字號重複的用戶。這種問題非常罕見,但是他們偏偏遇到了。
請問一下,如果把時間拉回一開始的時候,我應該依照他的要求,把身分證字號當作 PK 嗎? 我後來才知道那位客戶其實只懂得遠古時期的 dBase,就自以為很懂資料庫了。
案例二
我們的用戶管理系統設計為一名用戶歸屬於一個理專,所以資料庫就設計為一個 Member 表格關聯一個 Representative 表格。多年後,資料量已經膨脹到無法即時計算的程度;我們只能勉強在最近兩年的資料中做運算。但問題來了,由於用戶可以變換理專(每個月底執行一次轉換),以致於若以前述方式關聯到的用戶,計算出來的業績就難免會歸入目前的理專;但實際上應該歸入之前的理專才對。
當我們發現這個問題時,資料量已經很大了,但我們還能補救。但隨著資料量愈來愈大,前述的補救措施逐漸變得不可行。最後,我們只能把整個資料庫重新拆解,變成另一個專門用來計算歷史業績的資料庫,而且只能逐月批次作業。當然也有其它解決,就是把歷史紀錄預先通通算出來等著。
案例三
隨著我們的用戶愈來愈多、交易紀錄愈來愈龐大,原來的資料庫即使做過無數次擴增,仍然因架構問題而效能低落。其中最主要的原因在於,由於用戶的資料統統集中於一個資料庫裡,所有運算都會交互影響,形成既是 CPU bound 又是 IO bound 的情形。
因為部份用戶的交易次數過於頻繁,而每次交易都會需要重算餘額,而餘額的計算方式是從頭算到尾,光是這項作業就會耗費許多工夫。當有幾個此類用戶同時上線交易時,系統就幾乎停擺。更糟糕的是,當我們內部在做業績統計或維護作業時,也會同時影響到用戶的交易。
超前部署的必要性
前面兩個例子都不能算是 bug。真的要算的話,也應該叫做「呆」。
但與其在那裡相互指責「你怎麼沒有早想到」,還不如花力氣去想如何一勞永逸地解決或避免這種問題。以下是我的建議:
- 從經驗中學習
- 多花點功夫在需求訪談上面
- 預留資料庫的修改彈性
- 程式中不應該有太多寫死的變數
- 一開始就採用多語言框架
以第三點來講,在案例二中,我們其實只要新建一個表把用戶的每個月業績及當時所屬理專的紀錄重建起來,未來就可以直接使用這個表來做計算即可。這個還算容易,而且不影響整體架構。
但是這種對案例三就不適用了。那是整體架構的問題,真的是一開始就應該思考周詳的。
換句話說,當客戶告訴你「線上用戶不會很多啦,有幾百個就不錯了」時,我們真的不能相信。或者,如果 PM 精明一點,最好記得在訪談紀錄中明確載明像「同時間可服務的 Session 數以最多 1,000 為準」之類的文字以自保,並且一定要客戶親筆簽名,絕不能含糊帶過。
但是終極的解決方式非得修改系統才行。這種麻煩事有時比整個重寫還要麻煩,在此就不再著墨了。
重點是,當你要著手下一個系統時,能不能記取教訓?
像案例三這樣的問題,應該從一開始就設計成分散式的資料庫。不要把雞蛋通通放在同一個籃子裡;否則當雞蛋太多時,上面的蛋會把下面的蛋壓破,所以我們應該多準備幾個籃子。意思是說,當我們在計算餘額時,資料庫就不能和進行交易的資料庫是同一個,否則交易受到影響的事就會發生。諸如此類。
同理,大型用戶的交易是否也應該和小型用戶切開?查詢作業是否應該跟交易作業分開?坦白說這些判斷都不應該由客戶來告訴你,而應該是由你來告訴客戶。如果你已經事先告知風險而對方不理會,責任是對方的。可是如果你根本沒有及早想到,責任就是你自己的。