AOP在大規模軟體開發專案中應用的嘗試與思考

azz發表於2007-08-23
AOP在大規模軟體開發專案中應用的嘗試與思考[@more@]  本文的寫作源於一個真實的大型軟體開發專案,我們努力嘗試在這個專案中推廣應用AOP。在此我們將對曾經面臨過的一些實際問題與困難進行分析,試圖引發關於面向方面軟體開發(AOSD)的一些更深層次的思考。本文的作者將站在開發者的角度做出客觀的判斷,既不是AOP的狂熱鼓吹者,同樣也不是AOP反對陣營的一員。因此可以視作來自Java開發者對AOP技術應用的客觀分析和建設性意見。

  關於AOP

  關於AOP的概念,筆者在這裡不再贅述。誰最先創造了AOP,業界一直有些爭議,但普遍接受的說法大概是最先由Gregor J Kiczales在ECOOP'97提出來的,隨後Gregor又申請了AOP的專利[US06467086]。很多人可能不太服氣,因為他們或多或少早已有了類似的想法,只不過沒有想到給他起個新名字罷了。無論是OOP,MOP,還是AOP,其本質的想法都是試圖在更貼近現實世界的層次上實現軟體開發的模組化。從這個角度看,AOP的想法不過是新瓶裝舊酒罷了。其實AOP作為新生事物的出現,並不是一種技術上的飛躍,而是軟體模組化發展到某一個階段的一個階段性產物。人的思維通常都有一些慣性,在我們飽嘗了OOP的艱辛後,有一種新的概念跳出來分析總結了OOP的某些缺點,而且以看起來合理的方式做出改進,難免會給大家一種耳目一新的感覺。但不可否認的是,到目前為止,AOP角色所扮演的應用角色更多的只是對OOP的一種補充,因此作為一種重要的"OP"存在似乎有些名過其實,看起來更像是一種高階的設計模式。然而,在很多人的眼中AOP的分量甚至不亞於OOP,甚至AOP被視作未來軟體開發的一個趨勢。筆者一直思考一個問題,AOP出現的七八年時間在IT界並不算很短了,有趣的現象是AOP始終保持了小火慢燉的熱度,一直沒有像大家所期望的那樣大紅大紫起來。

  那麼AOP究竟在多大程度上可以幫助我們解決實際的問題呢?讓我們嘗試在一個真實的軟體開發專案中應用AOP。對AOP所推崇的各個典型應用方向加以研究,例如,日誌(Log),事務(Transaction), 安全性(Security), 執行緒池等等。必須說明,我們這裡提到的場景,是有一定規模的軟體產品開發,我們最終完成的是百兆數量級的軟體產品,因此我們研究的範圍既不是程式設計師的個人行為,也不是小範圍的示例。讓我們一起來看一看有什麼有趣的發現。

  AOP的實踐

  我們試驗應用AOP的方向很多,這裡僅以最具代表性的Log為例。大多數人瞭解AOP,都是從經典的Log 關注點的剝離開始的。因此這是每一個AOP的愛好者都耳熟能詳的案例。按道理,應該是無可爭辯的。很不幸,在我們的研究過程中還是碰到了很棘手的問題。

  讓我們來看一看一個經典的AOP 做日誌的例子。

  我們假定,按照AOP的思想,主邏輯的開發人員在寫程式碼的時候不應該考慮邊緣邏輯。因此,上述的日誌程式碼實際對主邏輯的開發者不可見。假定我們以主流的Log4J為記日誌的實現方式,以AspectJ作為Aspect的實現方式。需要重申,本文的寫作目的並不是針對某一種AOP的實現平臺,選用AspectJ主要因為從語法的角度而言,AspectJ是目前所有AOP實現中覆蓋範圍最廣的一種實現。

  這樣一個記日誌的橫切關注點描述,是最經典的AOP應用,它本身是沒有任何問題的。通常我們會怎樣用它呢?在繼承了這個抽象Aspect的子Aspect實現中指定切入點的位置①,並在這個位置上將實現的邏輯填入通知(Advice)②。

  在一個小規模的應用開發環境中這樣做是不會有問題的,首先,記日誌的切入點不多,無論是採用一對一的位置直接描述,還是利用統一的編碼規範來約束都是可行的方案;其次,通知中的邏輯不會很複雜。整體的軟體開發流程不會有什麼變化的需要,通常的做法是由專門的Aspect開發人員統一編寫Aspect,而由大家共享記Log的Aspect。但是不鼓勵每一個開發人員都寫自己的Aspect,這樣就不是橫(cross-cut),變成過篩子了(cross-point),軟體開發變成一盤散沙,失去控制,AOP帶來的好處喪失殆盡。

  那麼,在我們的專案中,情況怎樣呢?上述看似簡單的兩個點都存在問題:

  (1) 具我們統計,在我們開發的軟體上一個版本的軟體程式碼中,總共有7萬句記Log的呼叫。如果我們不做任何相關的總結工作,直接一對一的對切入點進行描述,那麼在位置①上的切入點描述就有7萬條之多;姑且不算工作量,即使這樣做了,將來帶來的程式碼維護將是天文數字的成本,此路不通。

  那麼我們只能寄希望能夠提煉出這7萬句日誌呼叫的公共模式,我們在這裡用到的是一種最佳化過的Log元件,介面與LOG4J類似,考慮到LOG4J的廣泛應用,我們下面將以LOG4J為參照。Log Level類中預定義了五個級別,DEBUG, INFO, WARN, ERROR,FATAL,根據統計,Fatal型別的呼叫最少,根據Fatal的級別定義,我們或許可以花一定時間整理程式碼,提煉出捕捉Fatal點的規則。然後次之,WARN和ERROR大約佔7%左右,這一部分就不好辦了,WARN/ERROR型別的LOG並沒有嚴格的界定,程式碼的分佈點也難尋規律,一定要找到規律,要付出相當大的代價。最後,DEBUG, INFO佔據了很大的比例30%-50%,顧名思義,這一部分的程式碼出現的隨機性很大,無論怎樣努力都不可能找到有意義的公共規律。此路還是不通。

  有一種說法也許可以解釋這種想象:如果切入點難於描述的時候,很大原因是因為關注點的定義不準確。此說法有一定道理,以"日誌"作為一個方面來切入粒度似乎太大了。那麼,唯一的辦法是將"日誌"關注點進一步拆解。一直拆解到可以接受的程度。但是,我們的問題似乎還沒有解決,如果我們的專案足夠小,那麼這樣的拆解總是有一定的限度的,這種做法或許可行。但很不幸,我們的專案很大,要經過相當多的分解才能最終找到日誌的規律性。我們還是可能需要成百上千條語句來指定切入點的位置,最終的結果將很難維護,這樣的做法對於一個不斷演化中的專案而言是脆弱乃至於不可接受的。況且,像Debug這樣的Log級別,無論你怎樣拆解,都不可能找到完美的規律。通常,任何一個系統中的Log都會保持邏輯的一致性,如果經過了這樣的層層分解,Log作為一個邏輯主體的完整性被完全破壞了。這是一種為了AOP而AOP的做法,非但工作量沒有減輕,還帶來了無窮的後患。

  好了,只剩最後一招了,為了用AOP, 我們犧牲掉Log的某些特性,預先定義好編碼的規則和日誌原則,強制推行。當然,如果想要全面覆蓋所有的日誌點,這樣的日誌原則只能定得非常粗。從AOP的角度來講,技術上是可行的,但粗放的日誌規則會帶來Log的資訊量瘋長,對於我們的軟體專案來說,還是不可接受,因為日誌失去了它的精確性,會對系統的維護產生較大影響,而且大量日誌資訊的增長對系統整體執行效能的衝擊是顯而易見的。

  (2) 在圖1 的第二個要點上我們也同樣面臨問題,也許從圖上的例子你可能還看不出來,因為在所有的介紹AOP的文件材料中介紹Log的例子都很簡單。但是現實生活中的Log很不留情面。很多時候程式對Log的呼叫都有其特殊的原因,它們的Advice需要分別編寫。例如在例子產品中我們經常需要把一個變數傳給"日誌"方面, 而且,經常要傳入一個區域性變數。至少現在,所有的AOP實現都還不支援對區域性變數的捕捉,在可見的將來也不會有這種實現。好吧,只好重構程式碼,如果您想傳引數,必須要遵守我們預先定義的編碼命名規則。但是,這樣給程式設計人員帶來的限制會很大,你很難說服開發人員手捧厚厚的編碼規範,小心翼翼的寫程式。

  綜合上述兩個致命缺陷,我們試圖推行Log Aspect的工作已經遇到了相當的阻力。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10901326/viewspace-965481/,如需轉載,請註明出處,否則將追究法律責任。

相關文章