怎樣的設計算得上好設計?
spring
就如一百我的眼中有一百個哈姆雷特同樣,這個問題多半也不會有標準答案。況且,脫離了具體和細節的業務需求,設計、架構之類的討論也只剩套路了。
緩存
不過,前兩天想了想這個問題,仍是記錄一下吧。性能優化
最基礎的一點,確定是功能正確。若是一個設計方案,各類高上大的框架飛來飛去,結果卻不能保證功能是對的,那麼這方案從根子上就是失敗的。多線程
我前兩天寫了一個小需求的設計,思路是把行計算改爲並行計算。並且我用了新的併發stream和ForkJoinPool,感受忽然高上大了起來。結果併發一開,連計算結果都錯了。哎,臊了一臉。架構
反過來的例子就不勝枚舉了。併發
在功能正確之上,是健壯性。包括冪等性、容錯性、可用性等。簡言之,出現非正常操做時,系統仍然可以處理。框架
前陣子一個同事設計了一個申請功能。他設計的邏輯是:在申請前,須要校驗狀態位state!=A;而申請後,這個狀態纔會被設置爲A。結果,當同一筆數據先後兩次發起調用時,第一次調用成功,第二次卻跑出了異常。這個設計在冪等性上就存在問題,也就是健壯性上存在問題。
socket
容錯性稍難點。Java中最基礎的作法是try-catch。可是try-catch也有難處。一是異常自身的層次很差;二是異常處理中須要考慮一些關聯問題,例如事務的回滾與否、JMS消息是否重試,等等。ide
可用性比較好理解,簡單說就是多點多活。多點多活能夠用多線程的思路來設計,可是這個多線程,容易併發、難於同步。工具
再往上,我認爲是擴展性。擴展性不單單是系統、技術上的問題。它須要設計師對業務有充分、深刻的理解。
例如,技術上,若是咱們要把某些功能收在包內,把類、方法的可見性設定爲friendly或者protected就行。可是業務上呢?哪些業務功能要收在這個模塊內、哪些業務功能能夠開放爲系統服務?這是須要業務、技術兩棲人才能想明白的。
不過,擴展性與這個有什麼關係呢?擴展性所考慮的,不少時候就是這類依賴性的開、閉問題。哪些東西能夠開放、哪些要關閉;這個功能能夠依賴哪些模塊、不能依賴哪些模塊,這就是依賴性的問題。
把功能作正確、作得不出錯,這還算是「需求翻譯機」的範疇。把功能作得有良好的擴展性,這才進入了系統設計的大門。
擴展性能夠解決開發效率的問題。更進一步呢?我認爲更進一步的設計須要考慮性能,這一系統運行效率的問題。系統畢竟是拿來用的。
我這兩天正在作一個性能優化的需求。這套功能在擴展性上來講算是很是不錯的了,前兩天剛剛經歷了一個大需求的考驗,三口兩口就吃下去了。可是它的設計幾乎是反性能的——例如同一個耗時操做在循環體內執行屢次,例如循環操做沒有併發,例如資源池不夠大,等等。這樣的設計,我最多給40分。
不過,良好的擴展性優點在此次優化中也顯現了出來。方案定好後,我很快就完成了此次優化——這實際上也是一種「擴展」,用性能更好的方案替代原有方案。
不過這也是有點僥倖。更多的性能優化是須要突破原有框架、模型的。久遠點的如socket,它打破了七層協議的界限,一個「人」處理了端口、ip、字節流等多個協議層的功能。但它也確實比http等乖寶寶的性能要好。又如我此次的優化中,也存在用緩存、ThreadLocal等方式來跨線程調用棧執行REST操做的地方。
除了性能以外,還有一個目標須要考慮:易用性。這點主要是針對技術工具、組件或者框架來講的。EJB之因此被淘汰掉,一個重要緣由就是太難上手、使用了。而Spring系列框架的生命力一直如此旺盛,與它的簡單易用也有很大關係——更別說它如今還推出了spring boot。
功能正確、健壯(冪等性、容錯性、可用性等)、擴展、性能、易用,這些就是我理解的一個好的設計的評價標準。