哪種人是軟體設計中的稀缺型人才?
簡介: 阿里妹導讀:好的系統架構離不開好的介面設計,因此,真正懂介面設計的人往往是軟體設計隊伍中的稀缺型人才。為什麼在介面制定標準中說:一流的企業做標準,二流的企業做品牌,三流的企業做產品?依賴倒置到底是什麼意思?什麼時候使用介面才算合理?今天,阿里匠人——張建飛將為你詳細解讀。
介面有什麼好處(Why)
在我看來,介面在軟體設計中主要有兩大好處:
1. 制定標準
標準規範的制定離不開介面,制定標準的目的就是為了讓定義和實現分離,而介面作為完全的抽象,是標準制定的不二之選。
這個世界的運轉離不開分工協作,而分工協作的前提就是標準化。試想一下,你家的電腦能允許你把顯示卡從NVIDIA換成七彩虹;你家的燈泡壞了,你可以隨便找一個超市買一個新的就可以換上;你把資料從Oracle換成了MySQL,但是你基於JDBC寫的程式碼都不用動。等等這些事情的背後都是因為介面,以及基於介面定製的標準化在起作用。
在Java的世界裡,有一個很NB的社群叫JCP( Java Community Process),就是專門通過JSR(Java Specification Request)來制定標準的。正是有了JSR-315(Java Servlet),我們服務端的程式碼才能在Tomcat和Jetty之間自由切換。
最後,我想用一句話來總結一下標準的重要性,那就是:“一流的企業做標準,二流的企業做品牌,三流的企業做產品。
2. 提供抽象
除了標準之外,介面還有一個特徵就是抽象。正是這樣的抽象,得以讓介面的呼叫者和實現者可以完全的解耦。
解耦的好處是呼叫者不需要依賴具體的實現,這樣也就不用關心實現的細節。這樣,不管是實現細節的改動,還是替換新的實現,對於呼叫者來說都是透明的。
這種擴充套件性和靈活性,是軟體設計中,最美妙的設計藝術之一。一旦你品嚐過這種“依賴介面”的設計來帶的美好,就不大會再願意回到“依賴實現”的簡單粗暴。平時我們說的“面向介面程式設計原則”和“依賴倒置原則”說的都是這種設計。
另外,一旦你融會貫通的掌握了這個強大的技巧——面向抽象、面向介面,你會發現,雖然面向實現和麵向介面在程式碼層面的差異不大,但是其背後所隱含的設計思想和設計理念的差異,不亞於我籃球水平和詹姆斯籃球水平之間的差異!
//面向介面
Animal dog = new Dog();
//面向實現
Dog dog = new Dog();
作為一名資深職場老兵,我牆裂建議各位在做系統設計、模組設計、甚至物件設計的時候。要多考慮考慮更高層次的抽象——也就是介面,而不是一上來就陷入到實現的細節中去。要清楚的意識到介面設計是我們系統設計中的主要工作內容。而這種可以跳出細節內容,站在更高抽象層次上,來看整個系統的模組設計、模組劃分、模組互動的人,正是我們軟體設計隊伍中,非常稀缺的人才。有時候,我們也管這些人叫架構師。
什麼時候要用介面(When)
有擴充套件性需求的時候
可擴充套件設計,主要是利用了物件導向的多型特性,所以這裡的介面是一個廣義的概念,如果用程式語言的術語來說,它既可以是Interface,也可能是Abstract Class。
這種擴充套件性的訴求在軟體工作中可以說無處不在,小到一個工具類。例如,我現在系統中需要一個開關的功能,開關的配置目前是用資料庫做配置的,但是後續可能會遷移到Diamond配置中心,或者SwitchCenter上去。
簡單做法就是,我直接用資料庫的配置去實現開關功能,如下圖所示:
但是這樣做的問題很明顯,當需要切換新的配置實現的話,就不得不扒開原來的應用程式碼做修改了。更恰當的做法應該是提供一個Switch的介面,讓不同的實現去實現這個介面,從而在切換配置實現的時候,應用程式碼不再需要更改了。
如果說,上面的重構只是使用策略模式對程式碼進行了區域性優化,做了當然更好,不做的話,影響也還好,可以將就著過。
那麼接下來我要給大家介紹的場景,就不僅僅是“要不要”的問題,而是“不得不”的問題了。
例如,老闆給你佈置了一個任務,實現一個類似於eclipse可以可插拔(Pluggable)的產品,此時,使用介面就不僅僅是一個選擇問題了,而是你不得不使用的架構方法了。因為,可插拔的本質就是,你制定一個標準介面(API),然後有不同的實現者去做外掛的實現,最後再由PluginManager把這個外掛機制串起來而已。
下圖是我當時給ICBU設計的一個企業協同雲的Pluggable架構,其本質上,也就是基於介面的一種標準和擴充套件的設計。
需要解耦的時候
上面介紹的關於Switch的例子,從表面上來看,是擴充套件性的訴求。但不可擴充套件的本質原因正是因為耦合性。當我們通過Switch Interface來解開耦合之後,擴充套件性的訴求也就迎刃而解了。
發現這種耦合性,對系統的可維護性至關重要。有一些耦合比較明顯(比如Switch的例子)。但更多的耦合是隱式的,並沒有那麼明顯,而且在很長一段時間,它也不是什麼問題,但是,一旦它變成一個問題,將是一個非常頭痛的問題。
一個真實的典型案例,就是java的logger,早些年,大家使用commons-logging、log4j並沒有什麼問題。然而,此處一個隱患正在生長——那就是對logger實現的強耦合。
當logback出來之後,事情開始變得複雜,當我們想替換一個新的logger vendor的時候,為了儘量減少程式碼改動,不得不上各種Bridge(橋接),到最後日誌程式碼變成了誰也看不懂的程式碼迷宮。下圖就是我費了九頭二虎之力,才梳理清楚的一個老業務系統的日誌框架依賴情況。
試想一下,假如一開始我們就能遇見到這種緊耦合帶來的問題。在應用和日誌框架之間加入一層抽象解耦。後續的那麼多橋接,那麼多的向後相容都是可以省掉的麻煩。而我們所要做的事情,實際上也很簡單——就是加一個介面做解耦而已(如下圖所示):
要給外界提供API的時候
上文已經介紹過JCP和JSR了,大家有空可以去閱讀一些JSR的文件。不管是做的比較成功的JSR-221(JDBC規範)、JSR-315(Servlet規範),還是比較失敗的JSR-94(規則引擎規範)等等。其本質上都是在定義標準、和制定API。其規範的內容都是抽象的,其對外發布的形式都是介面,它不提供實現,最多會指導實現。
還有就是我們通常使用的各種開放平臺的SDK,或者分散式服務中RPC的二方庫,其包含的主要成分也是介面,其實現不在本地,而是在遠端服務提供方。
類似於這種API的情況,都是在倒逼開發者要把介面想清楚。我想,這也算微服務架構一個漂亮的“副作用”吧。當原來單體應用裡的各種耦合的業務模組,一旦被服務化之後,就自然而然的變成“面向介面”的了。
通過依賴倒置來實現面向介面(How)
關於依賴倒置,我以前寫過不少文章,來闡述它的重要性。實際上,我上面給出的關於擴充套件需求的Switch案例,關於解耦的logger案例。其背後用來解決問題的方法論都是依賴倒置。
如上圖所示,依賴倒置原則主要規定了兩件事情:
- 高層模組不應該依賴底層模組,兩者都應該依賴抽象(如上面的圖2所示)
- 抽象不應該依賴細節,細節應該依賴抽象。
我們回頭看一下,不管是Switch的設計,還是抽象Logger的設計,是不是都在遵循上面的兩條定義內容呢。
實際上,DIP(依賴倒置原則)不光在物件設計,模組設計的時候有用。在架構設計的時候也非常有用,比如,我在做COLA 1.0的時候,和大多數應用架構分層設計一樣,默許了Domain層可以依賴Infrastructure層。
這種看起來“無傷大雅”的設計,實際上還是存在不小的隱患,也違背了我當初想把業務複雜度和技術複雜度分開的初心,當業務變得更加複雜的時候,這種“偷懶”行為很可能會導致Domain層墮落成大泥球(Big mud ball)。因此,在COLA 2.0的時候,我決定用DIP來反轉Domain層和Infrastructure層的關係,最終形成如下的結構:
這樣做的好處是Domain層會變得更加純粹,其好處體現在以下三點:
1、解耦: Domain層完全擺脫了對技術細節(以及技術細節帶來的複雜度)的依賴,只需要安心處理業務邏輯就好了。
2、並行開發: 只要在Domain和Infrastructure約定好介面,可以有兩個同學並行編寫Domain和Infrastructure的程式碼。
3、可測試性: 沒有任何依賴的Domain裡面都是POJO的類,單元測試將會變得非常方便,也非常適合TDD的開發。
什麼時候不需要介面
"勁酒雖好,可不要貪杯哦!"
和許多其它軟體原則一樣,面向介面很好,但也不應該是不分背景、不分場合胡亂使用的殺手鐗和尚方寶劍。因為過多的使用介面,過多的引入間接層也會帶來一些不必要的複雜度。
比如,我就看過有些應用的內部模組設計的過於“靈活”,給什麼DAO、Convertor都加上一層Interface,但實際情況是,應用中對DAO、Convertor的實現進行替換的可能性極低。類似於這樣的,裝模作樣,裝腔作勢的Interface就屬於可有可無的雞骨頭(比雞肋還低一個檔次)。
就像《Effective Java》的作者Joshua Bloch所說:
“同大多數學科一樣,學習程式設計的藝術首先要學會基本的規則,然後才能知道什麼時候可以打破這些規則。”
相關文章
- 未來3到5年內,哪個方向機器學習人才最稀缺?機器學習
- 軟體設計是怎樣煉成的(3)——軟體系統不是木桶型的
- 23種軟體設計模式設計模式
- 軟體設計雜談(二)--軟體設計與設計人員的個人素質 (轉)
- 軟體設計是怎樣煉成的(4)——軟體設計的“大道理”
- 熱門行業 + 人才稀缺,風口上的 RPA?行業
- 不值錢的軟體人才
- 面對物件是一種軟體設計思想,和具體的實現無關物件
- Adobe創意軟體和認證體系,賦能創新、創意型設計人才數字化轉型
- 軟體設計的沉靜|ONES 技術人
- TRIZ在軟體設計中的思考
- 軟體有兩種型別的值型別
- 天使投資人是如何正摧毀年輕易受騙的程式設計人才程式設計
- 在遊戲中設計動物是怎樣一種體驗?遊戲
- 【slam】ubuntu中各種型別軟體包的安裝方法SLAMUbuntu型別
- Mathias Verraes:軟體設計中,越小越好,粒度越細越好往往是一種壞建議
- 軟體設計是怎樣煉成的(1)——什麼是優秀的設計?
- 有兩種方式構建軟體設計
- 專家 vs 多面手:你是哪種型別的開發者?型別
- 軟體設計中的可用性 (轉)
- 軟體設計的目標是建立適合人類思維的片塊 - KentBeck
- 你在用哪種程式設計字型?程式設計
- 軟體測試用例設計中的結構設計
- 軟體效能的設計(三)資料型別對軟體效能的影響 (轉)資料型別
- 人生和遊戲設計的稀缺性迴圈遊戲設計
- 【軟體工程】軟體設計之總體設計軟體工程
- 介面設計是一個人迭代的過程,其核心活動包括哪幾種
- 成功軟體開發者的9種程式設計習慣 (轉)程式設計
- 頂級程式設計人員推薦軟體程式設計
- [軟體人生]什麼是程式設計師程式設計師
- 軟體設計的目標是建立適合人類思維的切片分塊 - KentBeck
- 上海:軟體行業急缺複合型IT專業人才(轉)行業
- 從傳統職場人到複合型人才,你只差一套風變程式設計的課程式設計
- 五種型別的程式設計師型別程式設計師
- 程式設計師的五種型別程式設計師型別
- 程式設計師的四種型別程式設計師型別
- 5種型別的程式設計師型別程式設計師
- 成功軟體開發者的9種程式設計習慣 7 (轉)程式設計