OOBootcamp 回顧與總結

OOBootcamp,全稱是Object-oriented Bootcamp,就是面向對象訓練營的意思,在12月份和1月份,我們整個項目組一些senior一些的同事一起接受了OOBootcamp的培訓,有這個培訓呢,還多虧了訓杰找駿總爭取到了這個機會,Tech leader做得好,關心組員的技術成長,哈哈。講師是袁慎建老師,intellij 的快捷鍵玩的出神入化,技術實力沒得說,又會說話還又會寫文章,關鍵是人還長得特別帥,這就讓人有點嫉妒了,附上他的簡書地址,歡迎大家前去騷擾. ??

前些天這次OOBootcamp圓滿結束,完結撒花??。領到了一張小獎狀


image.png

當然還有一些附帶的訓戰計劃,是需要在實際項目中去落實所學到的知識。所以之后還會有一些在實際項目中實踐這次學到的知識之后的感悟,好,廢話不多說了,下面就來回顧總結一下這次的OOBootcamp.

這次OOBootcamp, 主要分了三大塊的內容,一個是SOLID原則, Simple Design原則,貧血充血模型,二是TDD, 三是重構,主要用了Parking Lot 這個編程實例來給我們做練習,學以致用,先用例子實現一遍,再之后在真實項目中再操練一遍,幾板斧下來,保準你映像深刻,又有自己的體悟。

SOLID 原則 (面向對象的基石)

SOLID原則,我自己就不多現丑了,附上一篇袁老師的博文,供大家參考,雖然主要講的是里氏替換原則,但是其他原則附帶也有講,網上一搜索也是一大把。我下面就講一下我在OOBootcamp結束后對SOLID原則的理解,就不會講很多細節了。

先復制一波袁老師的一段文字??
SOLID由五大原則構成:

  1. Single Responsibility Principle【單一職責原則】
  2. Open Close Principle【開閉原則】
  3. Liskov Substitution Principle【里氏替換原則】
  4. Interface Segregation Principle【接口隔離原則】
  5. Dependency Inversion Principle【依賴倒置原則】
    并且請記住一句話,所有的原則其實都是為開閉原則服務的

注:袁老師說,你們知道了這幾個原則后,就把它忘掉,不過,我可能還沒到這種無招勝有招的境界,所以需要詳細記錄一下??

1. 單一職責原則

我理解的單一職責原則很簡單, 就是一個類,或者一個方法,它就只做一件事情,當然這句話說了等于沒說,你可能會說我知道單一職責是什么意思,但還是不會啊。對,我也不會,沒人敢說他會。因為單一職責的難點就在于這個一件事,到底是怎么個一件事,或者說怎么分。大到組裝一臺車,小到造一個螺絲釘,它都是一件事。怎么分?

其實這是一個很難的問題,這個問題是沒有一個標準的答案的,它跟你的業務相關,跟你具體的實踐相關。不是一個精準的度量而是一個感官度量。唯有以面向對象的方式多多練習,才能找到那個感覺。以我的感受來說,當你覺得你找出的那一件事情,分無可分,不存在二義性,那么我認為這就是單一職責的一件事。

2. 開閉原則

開閉原則的定義是對擴展開放,對修改關閉。這個真的咋一看云里霧里,要理解這個原則,我覺得我們首先得把這句話的作用域縮小一點,就針對java 面向對象來說,其實應該說的是,擴展功能可以增加新的類,但應該盡量避免修改已有的類。其實還是有點不好理解哈,也不知道怎么做,我覺得這時候可以去看下設計模式,全部的設計模式都遵循了開閉原則,簡直是最好的開閉原則示范。

3. 里氏替換原則

墻裂推薦袁老師的這篇博文 讓里氏替換原則為你效力,寫得很好,簡直寫到我心坎里去了。

我這里就只說說里氏替換原則的定義,任何基類可以出現的地方,子類一定可以出現,如果你覆寫了父類的方法,那么其實你是違背里氏替換原則的。至于為什么,都在袁老師的博文里,歡迎大家去圍觀,哈哈。

4. 接口隔離原則

接口隔離原則的定義是 客戶端不應該依賴它不需要的接口;類間的依賴關系應該建立在最小的接口上
這個原則,看定義就很好理解了,其實我認為它是對單一職責的一種補充,因為如果你單一職責做的非常好,那么你其實會很少碰到違背接口隔離的情況的,反之,如果真的出現了,那么一定是你單一職責做的還是不夠好。

5. 依賴倒置原則

這個原則的定義 是程序要依賴于抽象接口,不要依賴于具體實現。簡單的說就是要求對抽象進行編程,不要對實現進行編程,這樣就降低了耦合

這個其實也是有點繞的,面向抽象編程怎么就降低了耦合呢?其實我覺得還是很好理解的,比如你吃一個蘋果,如果寫實現,你寫一個蘋果類就完事兒了,但是如果面向抽象你需要定義一個蘋果接口,然后我吃這個接口就好,不關心是什么蘋果,然后再寫蘋果的實現,但是后面還有需求,說要吃一個美國的蘋果,因為美國蘋果又大又圓,面向實現的做法是,我改一下我的那個蘋果類改成美國蘋果就完了,面向抽象的做法是,我在寫一個類,美國蘋果類實現蘋果接口,其實對比兩種方式,你就能知道誰好誰壞。

Simple Design(簡單設計)

簡單設計原則 我還是推薦大家去讀袁老師的文章 簡單設計落地三板斧 其中鏈接了 簡單設計的價值觀簡單設計原則,哈哈,都是他寫的,十分高產。

簡單設計原則在我看來核心就是 保持簡單。對于程序開發來說,就是保持程序簡單,不要去過度設計,我們寫程序的時候常常會不由自主的為未來去考慮,比如一個好的程序員,他會有這樣個習慣,他不會單單只完成自己手上的工作,他會去思考未來會有什么需求進來,于是這些思考會常常體現在代碼上,形成過度設計。而如果你認同敏捷價值觀,那么這其實并不是一個好的習慣,因為你思考的需求,其實有時候并不會實際產生,于是代碼憑空復雜了很多,并且有一部分還是無用代碼。

Simple Design 就是需要你去認同這樣的價值觀 保持程序簡單,不要過度設計,你的程序實現應該是剛剛好滿足你現有的需求的。

那么怎么去落地Simple Design呢?請看袁老師講的Simple Design落地三板斧。TDD, 重構,clean code, 哈哈
培訓的時候映像比較深的是這樣一幅圖


img

這個是說的在實踐簡單設計過程中,當面臨沖突時,我們如何取舍,最重要的是通過所有測試,其次是消除重復和解釋意圖,優先級最低的是減少元素,當有沖突時,優先級越高的我們越應該關注。

貧血充血模型

期間由訓杰給我們分享了貧血和充血模型,現在一般Java 項目多數都會采用spring全家桶,而spring所推崇的mvc結構是一種典型的貧血模型,于是迅杰給我們分享了貧血模型和充血模型的區別(好處和壞處),以及充血模型的架構應該是怎么樣的

不了解貧血模型和充血模型的, 可以看看這篇文章 貧血模型與充血模型的對比

以下是摘抄自上面那篇文章

貧血模型的好處是:
1、每個貧血對象職責單一,所以模塊解藕程度很高,有利于錯誤的隔離。
2、非常重要的是,這種模型非常適合于軟件外包和大規模軟件團隊的協作。每個編程個體只需要負責單一職責的小對象模塊編寫,不會互相影響。

貧血模型的壞處是:
1、由于對象狀態和行為分離,所以一個完整的業務邏輯的描述不能夠在一個類當中完成,而是一組互相協作的類共同完成的。因此可復用的顆粒度比較 小,代碼量膨脹的很厲害,最重要的是業務邏輯的描述能力比較差,一個稍微復雜的業務邏輯,就需要太多類和太多代碼去表達(針對我們假定的這個簡單的工時管 理系統的業務邏輯實現,ruby使用了50行代碼,但Java至少要上千行代碼)。
2、對象協作依賴于外部容器的組裝,因此裸寫代碼是不可能的了,必須借助于外部的IoC容器。

對于Ruby來說,更加適合充血模型。因為ruby語言的表達能力非常強大,現在用ruby做企業應用的DSL是一個很熱門的領域,DSL說白了就是用來描述某個行業業務邏輯的專用語言。

充血模型的好處是:
1、對象自洽程度很高,表達能力很強,因此非常適合于復雜的企業業務邏輯的實現,以及可復用程度比較高。
2、不必依賴外部容器的組裝,所以RoR沒有IoC的概念。

充血模型的壞處是:
1、對象高度自洽的結果是不利于大規模團隊分工協作。一個編程個體至少要完成一個完整業務邏輯的功能。對于單個完整業務邏輯,無法再細分下去了。
2、隨著業務邏輯的變動,領域模型可能會處于比較頻繁的變動狀態中,領域模型不夠穩定也會帶來web層代碼頻繁變動。

TDD

上面的理論講完了之后,就是實踐了,用TDD 這個工具來實現一個比較經典的題目ParkingLot Management,在回顧TDD之前我要先回顧一下Tasking 思維管理工具

Tasking

Tasking 是一種思維管理工具, 它要求你對于一個比較復雜的問題,列出它的每一個完整子路徑,這樣進行Task分解之后,復雜的問題就變成了一個個簡單的容易實現的子問題了

Tasking 的經典格式是 Given When Then 格式,一個典型停車小弟的需求Tasking分解的例子是

Given: 我管理一個停車場,停車場有空位
When: 用戶委托我停一輛車
Then: 停車成功

可以看到,Tasking要求你分解出的Task要盡量的簡單并且可測試

一個錯誤的例子是

Given: 我管理N個停車場,停車場N個空位
When: 用戶委托我停N輛車
Then: 停車成功

這個Task其實是很難去測試的,N是多少?測試里面你難道要窮舉嗎?怎么窮舉?

TDD

TDD 測試驅動開發,是極限編程列出的12個團隊實踐之一,是其中重要的組成部分,TDD的具體理論和一些實踐,在網上都有,我這里只講我練寫TDD的感受,首先 TDD 是一個工具,是工具就有適用場景的,也就是說,不是所有的軟件開發過程都適合使用TDD,其次它是由三個單詞組成

  1. Task Driven Development
  2. Test Driven Development
  3. Test Driven Design

三個詞中都出現了Driven,所以,TDD的核心其實是那三個D, 而且從2,3兩個詞可以看出,TDD是必須Test First的

其實在課程開始之前,我對TDD的理解很粗淺,僅僅限于先寫測試后寫實現(當然,其實這樣理解也沒什么毛病),在實踐中也幾乎沒有去實踐,我們總是習慣于先寫實現,寫完之后再回過頭來補測試. 其實有時候就會有一種想法,覺得測試是一個可有可無的東西,你寫了更好,沒寫程序也不會出啥大的問題。就像是客戶要求我們測試覆蓋率90%以上,寫測試就是為了完成客戶的需求。

但是,TDD要求你重視測試,測試是一等公民, 你得先寫測試再去寫實現,你的測試得能表現你的業務,讓別人一看你的測試,就知道你的業務是啥,這就倒了過來,變成了實現是小兒子,哈哈

因為在TDD看來,好的能完整表現業務的測試,至少不會讓你漏了邊邊角角,而且這樣寫下來,理想情況下,測試的覆蓋率應該是百分之一百的. 你會對你寫的代碼無比有信心,因為在需求范圍內,你可以宣稱你寫的代碼是百分之百的滿足需求。

課程開始的時候,我們對TDD要求的 Test First是什么,是很明確的,就是先寫測試后寫實現,Task Driven Development 這個也是比較好理解的,但是后兩個確難到我們了,測試怎么去驅動開發,怎么去驅動你的設計,你的設計是測試驅動出來的嗎?以至于我們花了兩節課的時間去討論這些問題。下面我附上,我們討論的結論

  1. 我們寫測試之前,腦海里是有提前設計的,沒有提前設計,你測試都寫不了更不用說寫實現。
  2. 測試并不能驅動你的設計,只會讓你發現壞的設計(壞的設計測試很難寫)

下面是我們TDD的實踐步驟:

  1. 跟客戶確認當前階段需求,確認到什么程度呢?你覺得你能開始列Task了的時候,之后隨時保持與客戶的緊密溝通,需求有任何問題找客戶溝通

  2. 選擇視角(就是選擇看待問題的視角,比如是用戶視角還是停車場管理員視角),運用Tasking思維管理工具 列Task,Task是以業務場景為單位的,每一個Task都是要有交付價值,何為交付價值,就是客戶拿來能用的功能(能跑起來的程序), 代碼寫了一半,跑都跑不起來的,沒有任何價值. 先列簡單場景的Task 后列復雜場景的.

  3. 根據Task列表,從前到后一個一個的實現,由于我們是采取Pair的編程方式,所以是一個人寫測試,然后另一人寫實現,之后輪換
    提前設計注意點:

    1. 寫Task之前,是要有提前設計的
    2. 提前設計必須根據你當前已經做完和正要做的Task做提前設計,禁止根據全部的Task做提前設計
      寫測試的注意點:
    3. 測試必須能表現你當前Task的業務
    4. 抽象關系可以體現在測試里
      寫實現的注意點:
    5. 實現的代碼是基于你的提前設計的 (不要做重復的無用功)
    6. 實現的代碼要剛剛好滿足你的業務,何為剛剛好?就是刪除任意一行你的代碼,你的測試就會掛掉, 反之,就不是剛剛好
    7. 看到不爽的代碼就重構,什么是不爽的代碼?請看 clean code 這本書
  4. 全部Task完成之后就是向客戶交付產品了,由于我們的客戶是袁老師,所以給他review了代碼,保證所有的測試是綠的

TDD 這個東西,如果你單看字面,不去實踐,是無法領會它的精髓的,我覺得初學者如果要去實踐TDD, 可以不用去考慮它的后兩個單詞,只看Test First,先實踐一下Test First, 然后再慢慢去加上后兩個Driven,最終你會達到那種得心應手的境界,當然還可能是放棄,哈哈

據說如果熟練使用了TDD, 開發效率會比不使用TDD提升很多,這個我暫時也還沒體會到,看來是實踐的少了,之后會找機會多實踐TDD

重構

重構我就不多介紹了(要介紹也只能貼貼各種代碼示例),請大家移步 重構 這本書

我就只說說我的感受

  1. 當你看到不爽的點的時候,你就要重構你的代碼
  2. 不爽的點應該是違背團隊的代碼約定的,而不是違背你自己的小癖好
  3. 最好通讀一遍 clean code, 這樣你說別人代碼不好的時候也不至于詞窮(可以指著書本罵他??)
  4. 光看重構這本書,其實沒多大用處,你看過就會忘,你必須結合它來一場說寫就寫的實踐, clean code也一樣
  5. clean code, 重構這兩本書,請常備在桌面上,說不準啥時候就會用到,無論是指著書本罵人,還是適當的裝一下逼??

總結

OOBootcamp 培訓給我的進步還是很大的,以前我雖說是用著面向對象的語言,確寫著云里霧里,而這次培訓下來,結合理論和實踐,我深刻理解了面相對象的基本原則,簡單設計原則,以及Tasking TDD等做法,而且也使我對敏捷有了更深刻的認知,確實是猶如醍醐灌頂,受用無窮。我相信這些知識最終也能帶著我飛得更高。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容