新手程式設計師在做設計時,因為缺乏經驗,很容易寫出欠設計的程式碼,但有一些經驗的程式設計師,尤其是在剛學習過設計模式之後,很容易寫出過度設計的程式碼,而這種程式碼比新手程式設計師的程式碼更可怕,過度設計的程式碼不僅寫出來時的成本很高,後續維護的成本也高。因為相對於毫無設計的程式碼,過度設計的程式碼有比較高的理解成本。說這麼多,到底什麼是過度設計?
什麼是過度設計?
為了解釋清楚,我這裡用個類比,假如你想擰一顆螺絲,正常的解決方案是找一把螺絲刀,這很合理對吧。 但是有些人就想:“我就要一個不止能擰螺絲的工具,我想要一個可以幹各種事的工具!”,於是就花大價錢搞了把瑞士軍刀。在你解決“擰螺絲”問題的時候,重心早已從解決問題轉變為搞一個工具,這就是過度設計。
再舉個更技術的例子,假設你出去面試,面試官讓你寫一個程式,可以實現兩個數的加減乘除,方法出入參都給你提供好了 int calc(int x, int y, char op)
,普通程式設計師可能會寫出以下實現。
public int calc(int x, int y, int op) {
if (op == '+') {
return x + y;
} else if (op == '-') {
return x - y;
} else if (op == '*') {
return x * y;
} else {
return x / y;
}
}
而高階程式設計師會運用設計模式,寫出這樣的程式碼:
public interface Strategy {
int calc(int x, int y);
}
public class AddStrategy implements Strategy{
@Override
public int calc(int x, int y) {
return x + y;
}
}
public class MinusStrategy implements Strategy{
@Override
public int calc(int x, int y) {
return x - y;
}
}
/**
* 其他實現
*/
public class Main {
public int calc(int x, int y, int op) {
Strategy add = new AddStrategy();
Strategy minux = new MinusStrategy();
Strategy multi = new MultiStrategy();
Strategy div = new DivStrategy();
if (op == '+') {
return add.calc(x, y);
} else if (op == '-') {
return minux.calc(x, y);
} else if (op == '*') {
return multi.calc(x, y);
} else {
return div.calc(x, y);
}
}
}
策略模式好處在於將計算(calc)和具體的實現(strategy)拆分,後續如果修改具體實現,也不需要改動計算的邏輯,而且之後也可以加各種新的計算,比如求模、次冪……,擴充套件性明顯增強,很是牛x。 但光從程式碼量來看,複雜度也明顯增加。回到我們原始的需求上來看,如果我們只是需要實現兩個整數的加減乘除,這明顯過度設計了。
過度設計的壞處
個人總結過度設計有兩大壞處,首先就是前期的設計和開發的成本問題。過度設計的方案,首先設計的過程就需要投入額外的時間成本,其次越複雜的方案實現成本也就越高、耗時越長,如果是在快速迭代的業務中,這些可能都會決定到業務的生死。其次即便是程式碼正常上線後,其複雜度也會導致後期的維護成本高,比如當你想將這些程式碼交接給別人時,別人也需要付出額外的學習成本。
如果成本問題你都可以接受,接下來這個問題可能影響更大,那就是過度設計可能會影響到程式碼的靈活性,這點聽起來和做設計的目的有些矛盾,做設計不就是為了提升程式碼的靈活性和擴充套件性嗎!實際上很多過度設計的方案搞錯了擴充套件點,導致該靈活的地方不靈活,不該靈活的地方瞎靈活。在機器學習領域,有個術語叫做“過擬合”,指的是演算法模型在測試資料上表現完美,但在更廣泛的資料上表現非常差,模式缺少通用性。 過度設計也會出現類似的現象,就是缺少通用性,在面對稍有差異的需求上時可能就需要傷筋動骨級別的改造了。
如何避免過度設計
既然過度設計有著成本高和欠靈活的問題,那如何避免過度設計呢!我這裡總結了幾個方法,希望可以幫到大家。
充分理解問題本身
在設計的過程中,要確保充分理解了真正的問題是什麼,明確真正的需求是什麼,這樣才可以避免做出錯誤的設計。
保持簡單
過度設計毫無例外都是複雜的設計,很多時候未來有諸多的不確定性,如果過早的針對某個不確定的問題做出方案,很可能就白做了,等遇到真正問題的時候再去解決問題就行。
小步快跑
不要一開始就想著做出完美的方案,很多時候優秀的方案不是設計出來的,而是逐漸演變出來的,一點點最佳化已有的設計方案比一開始就設計出一個完美的方案容易得多。
徵求其他人的意見
如果你不確定自己的方案是不是過度設計了,可以諮詢下其他人的,尤其是比較資深的人,交叉驗證可以快速讓你確認問題。
總結
其實在業務的快速迭代之下,很難判定當前的設計是欠設計還是過度設計,你當前設計了一個簡單的方案,未來可能無法適應更復雜的業務需求,但如果你當前設計了一個複雜的方案,有可能會浪費時間……。 在面對類似這種不確定性的時候,我個人還是比較推崇大道至簡的哲學,當前用最簡單的方案,等需要複雜性擴充套件的時候再去重構程式碼。