從面向方面看軟件設計

0 評論 5569 瀏覽 3 收藏 15 分鐘

編輯導語:面向方面編程也就是AOP,它使開發人員可以更好地將本不該彼此糾纏在一起的任務(例如數學運算和異常處理)分離開來;本文作者從面向方面看軟件設計,我們一起來了解一下。

產品小王今天接到了一個新的需求——客戶希望把登錄驗證時間從12小時調整到24小時。

產品小王接到需求時,心想這不就是把服務器中的數字從12改成24嗎?簡單得很,所以為了展現自己的專業性,他一口答應市場部的同事說今天就可以實現你這個需求;心里還想著用一點小手段就讓市場部同事欠自己一個人情,以后找市場部辦事方便多了。

于是產品小王便找到研發老王說:能不能幫忙把登錄驗證時間改成24小時啊,我已經答應市場部了今天實現,沒問題吧。

研發老王一聽就說這個做不了,你趕緊和研發部同事說下,別耽誤人家事了。

小王一聽,急了,急忙問到為什么啊,不就是改個數字嗎?

老王說,可不僅僅是改個數字,我們當時在實現系統的時候,為了快速實現安全的相關功能,所以安全模塊是貫穿很多模塊的;如果要改這個數字,首先要看在各個模塊中關于安全模塊的相關代碼,然后再查看修改代碼產生的影響,最后還要測試數字修改后代碼是否能正常運行。

小王心想:為什么改個數字要這么復雜啊?

其實這個問題在軟件工程中很早就出現了,軟件工程中也早就有一個很好的解決辦法——面向方面編程(AOSE:Aspect-Oriented Software Engineering),這篇文章就詳細展開說明什么是面向方面編程。

一、面向及面向方面

一般情況下,在軟件實現過程中,單個需求需要多個組件實現,而每個組件也可能同時服務于多個需求。

換句話說就是一個組件可以服務多個需求,一個組件中也包含實現多個系統需求的代碼;正如在下面這張圖片中,安全需求組件和恢復需求組件同時服務于客戶需求,賬戶需求和管理需求,組件之間相互搭配,進而實現系統功能的。

軟件系統結構

在圖中可以看到,在這個簡單的系統中有三個核心功能組件,分別是客戶需求,賬戶需求和管理需求;同時為了保持這三個核心功能組件能穩定運行,增加了安全需求和恢復需求組件。

在面向方面編程中,核心關注點(Concerns)指系統要實現的主要功能,比如上述圖片中的客戶需求、賬戶需求、管理需求;而把服務于核心關注點實現的功能稱為橫切關注點(CrossCutting Concerns),比如上述圖片中的中的安全需求和恢復需求。

傳統的代碼實現過程中,核心關注點的實現總是包含額外的代碼來實現橫切關注點,這就會導致代碼混亂和分散;雖然這種程序的實現方式能夠提高效率,但是這種結構會導致的橫切關注點的組件修改成本,復用成本都非常高。

原因是需要找出橫切關注點與核心關注點組件間如何相互配合,并評估修改后對核心關注點組件的影響,修改完成后,還要全部驗證核心關注點的組件。

說到這里,已經說明清楚面向方面編程的起因,接下來將說明什么是方面以及什么是面向方面編程。

方面指的就實現一個功能的程序,與其他程序不同的是,方面更偏向于描述程序間組成方法——一個可執行的方面根據自身的描述去組合對象,方法和其他方面創建處理的,同時規定了程序在什么地方運行。

方面的主要內容包括切入點、程序和連接點:切入點說明約定方面在什么時間開始執行程序;連接點指定系統在執行完程序后繼續執行的程序,包括進行方法調用、初始化變量或者更新域,定義引用的事件集合等,如下圖所示。

面向方面編程實例

面向方面編程正是基于方面的概念而誕生的,是一種專門實現橫向關注點組件的編程思想。

二、分離關注點

面向方面編程的核心內容是分離關注點,是思考和構建軟件系統的重要方法。

在面向方面編程中將關注點劃分為各自獨立的關注點,要求程序中的每個方面(類、方法、過程等)只為實現一個目的,進而降低修改和復用方面的成本,甚至不用思考關注點之間的相互影響。

當用關注點來表示一個需求或者一組需求的時候,我們可以很容易在實現組件中跟蹤需求;如果需求發生改變,研發人員可以快速定位到需要需改的代碼,并且不需要考慮方面之間的相互影響,快速實現需求改變。

三、實現面向方面編程

在面向方面編程中,關注點是從系統需求中導出的,利用分離關注點的概念作為考慮需求和設計系統的基礎;這個是進行軟件設計的原則,下文中展開的軟件設計的步驟也是基于此進行描述。

1. 明確軟件需求

和大部分的軟件設計一樣,在進行軟件設計時要最先明確軟件需求,也就是明確軟件的主要功能是什么;只有抓住了主要功能,才能保證我們在軟件設計過程中不會偏離方向。

2. 核心系統設計

明確軟件需求后,我們就可以通過軟件需求推導出核心關注點和橫切關注點。

3. 方面識別和設計

通過視點識別方面是一種最常用的方法。如下圖所示,每個視點代表一種用戶的一組關注點,而每組關注點又可以分為核心關注點系統和橫切關注點。

通過視點識別關注點,能很好地保證我們在分析時不重復、不遺漏,盡可能找到所有的關注點。

面向方面的設計和編程

面向方面的設計是利用方面進行系統設計的過程,通過方面來實現那些在需求工程中所找出來的橫切關注點,同時將方面與系統的其他組件組合在一起。

4. 沖突分析和解決

在將方面和系統的其他組件結合在一起時,要分析并解決可能存在的沖突,保證不發生組合的二義性;在不保證二義性的情況下,要找到每個方面與系統合適的切入點;只有找到了合適的切入點,方面運行才會符合設計者的需求。

需要特別注意的是,由于方面都是基于對系統一定的預期而獨立設計的,當多個方面一起作用與一個系統,一個方面對系統的影響會導致其他方面運行失敗。

5. 名字設計

面向設計的最后一步是方面及切入點的名字設計,由于面向方面特殊的軟件執行順序,所以在設計面向方面程序時要特別注意方面和切入點的名字設計,避免方面通過切入點執行程序時調用錯誤。

6. 總結

面向方面編程的流程圖如下:

面向方面的設計過程的流程圖

四、測試

由于面向方面編程代碼的特殊結構,測試是具有一定困難的,主要的原因是方面的程序與主體代碼是緊湊的,而不是松散的;就算測試后在一處能正常工作,在其他環境下也未必能正常工作。

下面展開說明可能的測試方法和遇到的困難:

1. 閱讀代碼測試

面向方面編程的代碼之間通過切入點進行連接,導致代碼無法直接閱讀;雖然可以借助一些代碼閱讀工具可以使代碼“變平”,從而降低代碼的閱讀難度,但是面向方面編程的程序語言本身是動態的,而非靜態的;所以借助工具閱讀代碼的只是解決了表面問題,無法解決實際問題。

2. 白盒測試

與白盒類似的還有結構化測試,這兩種測試方法的共同點是設計能提供一定程度覆蓋的測試方法;比如保證軟件的每個執行路徑都執行過一遍,每個程序語句都執行過一次。

遇到的問題和閱讀代碼測試類似,由于面向編程軟件通過切入點連接,導致面向方面的程序不是結構化程序;在某些運行環境下,一些方面可能被執行,一些方面不執行;而在另一種運行環境下,方面的執行情況又是另一種情況,方面之間又相互影響;所以產生了龐大的測試地圖,大大增加了測試難度。

很多現實世界中的系統都會涉及敏感操作,為了減少敏感操作帶來的損失,系統需要在敏感操作之前驗證用戶身份,并進行相關的記錄操作,比如生成日志、發出通知等。

那么這種功能的實現邏輯是什么呢?這篇文章將以財務系統的數據查看功能為例子說明面向方面編程如何實現用戶認證。

財務系統中有很多敏感數據及敏感操作權限,這些數據及操作只能被有相關權限的員工看到及使用。

但是在很多情況下,僅僅靠權限控制無法達到理想效果,比如財務人員打開了相關頁面并短暫離開座位去完成其他工作,這個時候該頁面上的數據和操作沒有任何保護措施。

為了對敏感數據及操作有更好的保護效果,產品往往會在相關領域增加賬號驗證——要查看敏感數據或者進行敏感操作需要先驗證賬號密碼;如果密碼不匹配,將直接退出系統并記錄相關操作信息;如果賬號密碼正確,則繼續操作并記錄相關操作信息。

這種功能的實現邏輯大概有以下兩種:

  • 修改每個敏感數據及操作的組件,讓組件去調用賬號密碼驗證并生成操作信息;
  • 修改系統代碼,使得每次進行敏感操作的時候都調用賬號密碼認證,在認證完成后記錄相關信息;

以上兩種實現邏輯都不是非常合理的,原因如下:

  • 第一種邏輯的問題是會導致驗證操作和記錄操作綁定在一起,不但造成代碼冗余而且會固化代碼,降低代碼的靈活性;
  • 第二種邏輯的問題是將代碼分散操作,會導致后續修改需求時無法快速定位對應的代碼,同時也會固化代碼,降低代碼的靈活性;

其實不難看出,賬號密碼驗證及操作是屬于橫切關注點,可以使用面向方面編程實現,具體如下:

  • 切入點:查看敏感數據或者進行敏感操作;
  • 切入點程序:進行賬號密碼驗證操作;
  • 連接點程序:記錄操作的相關信息等;

代碼結構如下圖所示:

敏感操作的面向方面編程結構圖

從上例中可以看到,面向方面編程的優點是代碼冗余少且靈活;但是在一定程度上增加了代碼的復雜度,可能會出現無法預知的問題。

面向方面編程并沒有大范圍使用,從這個意義上來說,面向方面編程對編寫代碼的意義不大,面向方面編程更多的意義在于系統架構;通過面向方面思想設計的架構能有更強的靈活性和更少的冗余,這也是個人了解完面向方面后的最大感受。

 

作者:寶寶心里苦??;公眾號:寶寶心里苦啊

本文由 @寶寶心里苦啊 原創發布于人人都是產品經理,未經作者許可,禁止轉載。

題圖來自Unsplash,基于CC0協議。

更多精彩內容,請關注人人都是產品經理微信公眾號或下載App
評論
評論請登錄
  1. 目前還沒評論,等你發揮!