AOP在大規模軟件開發項目中的應用(圖)


AOP在大規模軟件開發項目中的應用()

 

  本文的寫作源於一個真實的大型軟件開發項目,我們努力嘗試在這個項目中推廣應用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的工作已經遇到了相當的阻力。
  
  問題分析
  
  原本看起來一件簡單的事情,現在變得很復雜了,最初的熱情變成了愛恨交織與困惑,一定是哪里出了問題。
  
  在大型的軟件開發項目里AOP的切入點應該怎樣控制?這牽涉到開發的流程,版本控制,編碼規則等等。似乎AOP本身並沒有給出明確的答復。當我們談OOP的時候,涉及到的更多的是類,繼承,多態,而更深層次的方法學被隱藏在OOA與OOD中。類似的,我們在提到AOP的時候,表面上似乎就是Aspect,pointcut,advice,… 然而隱藏在代碼后面的面向方面的精華卻被忽略了。因此,我們主張,在我們學習應用AOP的時候,不要過分沉迷於代碼,應當合理的在分析、設計上投入更多的精力。這是我們從上述的失敗經歷中得到的第一個教訓。才能的。 我們不能把AOP想象成為萬靈丹,服用之后立刻生效。相反,在實際項目中應用AOP需要多方面的考慮,這樣才可能對由AOP產生的問題胸有成竹。
  
  從某種意義上講,代碼級別上的面向方面, 無論是面向Java的語言擴展還是XML,實現起來並沒有太大的不同。但是面向方面的技術也應該體現在不同的抽象層面上,如果在大規模的開發中應用,AOA(面向方面的分析),AOD(面向方面的分析設計)是必不可少的,因此,AOSD(面向方面的軟件開發)更貼切的描述了面向方面實際上是一個完整的實施過程。關於在更高層面上的AOSD,很多人正在做有益的嘗試,例如IBM 支持的基於Eclipse的CME項目,首先要解決的是怎樣在軟件開發的初始階段,定義合理的關注點,至於后面的實現是否基於純粹AOP的工具,並不是重要的問題。脫離分析、設計階段的關注點分析,直接在代碼中使用AOP,只在小規模的應用中可行,一旦面向大規模應用,許多問題就會接踵而來。
  
  除此之外,面向方面的開發過程還必須解決很多的具體問題,諸如:
  
  怎樣在切入點的公共模式與切入點的特征描述之間權衡?這是一個怎樣合理的控制AOP的粒度的問題,前面我們已經提到過,橫切關注點的粒度其實是很難決定的。在高層次上定義的橫切關注點, 在底層實現的時候還可能會碰到問題。對具體的AOP實現,可能單純從代碼的角度來看,粒度划分得越細越簡單越好。但這樣一來,方面的代碼與核心代碼就會綁定很死,不好維護。而且方面的代碼不優雅,看起來好像單純把一塊代碼摘出來另放一個地方,刻意隱藏的痕跡很重,很難看出AOP的好處。但粒度如果太粗,AOP的代碼就必須依賴公共模式的總結,這樣的公共模式首先需要花功夫來定義,力求完美,因為規則的不斷變化會帶來很多問題,所以應盡量避免出現規則的頻繁變動。而且,規則是大家都要遵守的,這樣會帶來更多的編碼限制。當然,對於具體的項目,編碼規則的多少是具體的問題,但如何能做到適度,並不是一個簡單的問題。
  
  很現實的一個問題,如果在大型開發項目有多個橫切關注點的時候,這些關注點之間應該如何打交道。在我們的實際項目中,就遇到這樣一個難題,日志關注點在很多情況下是與其他橫切關注點糾纏在一起的。其中的難題是橫切關注點的剝離先后順序問題。在一個版本延續性的開放項目中,由於需要重構,這個問題更為突出。某些情況下,橫切關注點之間如果存在雙向的相互依賴,就必須要修改邏輯,屏蔽這種可能性,否則,以目前的AOP的實現方式,很難處理,AOP的代碼會很難看,主邏輯的代碼重構會紛繁瑣碎,而且極難維護。
  
  在一個大型的軟件開發項目中,軟件的生命周期應該都處於可管理的狀態。如果AOP大規模介入,很多問題都變得很敏感,尤其是QA。按照AOP的想法,關注點是互相隔離開的,因此,實質上AOP造成軟件模塊間的耦合性變得松散了。軟件開發過程的松耦合必然帶來測試的復雜性。如果系統中的關注點控制在小范圍,那么這種負擔可以在小范圍的開發單位內部消化掉,但一旦關注點涉及到全局,這種變動就會蔓延,帶來的測試和QA的額外工作會迅速增長。並有可能會沖擊到現有的測試與QA流程。
  
  大型軟件產品的售后服務,通常都會在必要的時候觸及源代碼,以IBM為例,第三級的服務支持人員,將在源程序上跟蹤糾錯。很不幸,這些人必須盡快學會AOP,否則他們將無所適從,因為他們可能根本不知道整個應用邏輯是怎樣編織在一起的。軟件的維護與服務的成本可能會因此提高,並依賴特定的工具。
  
  AOSD發展方向的探討
  
  首先,這里我們再次強調AOSD,而不是單純的AOP。面向方面的發展空間,應該不僅僅局限於代碼層面。究竟面向方面是否會在未來很大程度上影響的軟件開發模式,目前的形勢並不明了。面向方面的分析與設計,應該對面向方面技術的未來起到主導作用。以現在面向代碼層的AOP的用法,坦率地講,只是一種小范圍的設計模式,並不值得投入太大的熱情。很多熱門的松散耦合的開發模型,比如SOA,SCA等等,看起來更現實,更合理,他們都有類似的理念,但具有比面向方面有更好的柔性。
  
  面向方面的分析與設計必須能夠解決下面的問題:
  
  首先,面向方面的方法學需要完善:
  
  1) 怎樣從具體需求中定位橫切關注點;這樣的定義一定不是來自於簡單的基於名字的原則,例如,Log在所有的軟件項目中都是橫切關注點嗎?如果我們軟件開發的對象是類似IBM WebSphere 這樣的J2EE應用服務器,那么事務 (Transaction)還是橫切關注點嗎?
  2) 怎樣合理的控制方面的粒度?從設計階段的橫切關注點到實現階段的方面,怎樣平滑的過渡?我們經常碰到的問題是,在實現階段,方面之間仍然有相互依賴性的問題,怎樣才能在分析設計階段就盡量避免這些問題?
  3) 關注點的模型表達方式,我們通過怎樣的標准形式來表達關注點,關注點之間的關系,以及橫切關注點與主邏輯之間的關系?
  4) 這樣的橫切關注點分析是可以重復、可驗證的嗎?有沒有可行的通用的方法學來幫助我們使得橫切關注點的識別與規范成為可控的過程?
  
  其次,面向方面的軟件工程是無法回避的重要問題,通過上面的問題分析,相信大家都已經認識到AOP對現有軟件過程各個階段的沖擊,因此有必要去規范適用於AOP的新的軟件開發過程。首先,面向方面的開發必須遵循迭代的模式。但現有的軟件工程方法都不足以讓我們有足夠的信心在當方面多到一定的程度時,軟件的開發仍然是可控的。為什么面對以前的OO,基於組件的方式,甚至更新的SOA的開發,我們都不會如此的不安?主要是因為在這些模式下,我們都能夠比較簡單的看到完整產品的雛形,而方面一旦多到某種程度,軟件的整體性就不能直觀的被感知到。因此,面向方面對開發流程的沖擊是不可避免的。特別是疊代的開發方式,如何對每個開發循環有效控制也是很有學問的。
  
  最后,面向方面的開發工具是大規模應用AOP的技術保障,現有的開發工具都不能保證面向方面的軟件開發的效率與完整性。我們需要一種能夠更好的集成方面開發的工具。AJDT能夠提供一些幫助,但是還遠遠不夠。一個理想的AOP開發工具應該支持:
  
  1) 軟件產品的完整視圖,能夠以可視並且形象的方式組合橫切關注點和核心關注點
  2) 能將AOP技術集成到系統的分析設計階段
  3) 基於方面組合的測試與Debug工具,能夠靈活的根據不同的關注點組合進行測試和Debug
  4) 更加靈活和方便的關注點定義方式,對大多數Java開發者屏蔽復雜的Aspect語法
  
  總結
  
  本文通過我們在大規模項目中應用AOP的實際經驗,總結了碰到的問題和取得的進展。通過我們的實踐與分析,我們認為在AOP有較大發展之前,以現在的狀態,AOP更適合在小規模軟件開發項目中應用。而AOP的更大規模應用不僅需要代碼級AOP強有力的支持,更依賴於面向方面的分析設計技術與相應軟件工程領域的進展。
  
  最后,在看到了問題之余,我們也看到了AOP技術仍然處於一個不斷發展的階段。關於AOP的文章不斷涌現,AOP工具的功能在不斷加強,而開發人員對AOP的接受程度也在逐步提高。樂觀的看,也許在不久的將來,AOP就能獲得理論和實踐上的長足進步,從而解決本文中提到的問題。讓我們拭目以待。
  
  參考資料
  
  AspectJ是目前使用最廣泛也是功能最強大的AOP代碼級別的實現。我們可以從http://www.eclipse.org/aspectj 獲得它。
  AJDT是基於Eclipse的AspectJ的集成開發環境,它包含了最新版本的AspectJ。可以從http://www.eclipse.org/ajdt 獲得它。
  Http://aosd.net 上有很多AOP相關的資料和論文。另外,您也可以通過這個網站參加每年一次的AOSD會議。
  Developerworks上的AOP@Work系列能夠幫助我們深入了解AOP的現狀
  CME是一個有趣的工具,它對AOP在整個軟件工程生命周期中的運用提供了支持。特別有趣的是它能夠幫助開發人員發現和提取Crosscutting Concern。可以從http://www.eclipse.org/cme獲得它。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM