经典三层架构

為什麼我要規範所有團隊用同樣的架構開發專案?

前陣子在上架構與框架設計的課程時候,提到幾件事情。我說...
  • 要設計出好的架構不難,但真正能夠實施(implement)在團隊中的卻很不容易。
  • 架構設計是一種取捨,沒有絕對完美的做法,有得,就有失,架構師除了要有足夠的技術能力,更重要的是,要有足夠的溝通能力。
  • 架構設計只有一件事情最重要,就是能夠實施(implement),無法實施的架構,再美也是枉然。(不能實施的因素有很多,除了設計的好壞,更多的時候是架構師是否能夠同理開發人員技術程度,以及能否在導入時突顯這個設計的優點)
  • 架構與框架的設計與導入,不僅僅是建構開發團隊的基礎,更是一種引導或限制,讓開發人員被框在某一個規範中,在有限制的狀況下自由發揮(我甚至補充,在軟體開發和專案管理的世界中,過度的自由是一種罪惡) 。

我無法在有限的課程時間中,解釋某些事情。因此,趁著有空且記憶猶新,我想來談談我們過去一兩年做的架構設計,以及為何我要求台灣和China幾個團隊中,所有的成員(PO/PM, SD/SM, Developers)都必須採用這樣的架構。

===================================

先講講背景...

最近這幾年,我們在Web開發上揚棄了從服務器端產生HTML的方式,而改採接近SPA(Single Page Application)的model來進行專案開發,也因此,整個ASP.NET MVC,嚴格說起來,我們只有用WebAPI,其他的部分都是透過我們自己開發的框架(Framework)來搭配與運行。

簡單的架構圖如下:

 
在這個架構底下,Framework 本身負責 Services Layer(中間橘色的那塊)、Client 端對服務器端 Server Components 的調用(呼叫)、以及 Cross-Cutting Components(左方豎著的那塊)。

採用此Framework 架構的開發人員,只focus 在底下2個部份的開發,而將其他部分交由這個Framework 處理,分別是:
  1. Server Components 開發
     
    Server Components 以.NET Assembly(.dll)的形式開發,開發人員可以建立標準 的.NET 4.5.x Class Library,透過引入 Framework Server Component Nuget Package 來建立 Visual Studio Project。開發後的.dll會被佈署到上圖中最底下藍色的那層Backend Application Service Layer中。
            
  2. Client 端 UI 開發
     
    Client 端 UI 有各種不同的形式,如果是網站可能是 HTML Pages,如果是 Windows Desktop application,則可採用 WPF 或 Windows Form 開發技術。如果是 Mobile Device,則可能是 Windows Store App, Windows Phone App, 或是 iOS/Android Apps…etc.。
     
    不論是何種形式的前端Project,均可透過引入相對應的 Nuget Package,取得 BackendServiceClient 這個共用 Component 來進行 Server Component 的調用,以及開發 Client 端所需要的各種 Helpers/Utilities。

透過這樣的開發方式,你會發現,這和你以前習慣的開發方式 -- 『開發人員直接打開Visual Studio 2013,用微軟內建的範本來寫程式…』會有著很大的不同。

首先,我們只讓開發人員寫兩個部分的Code,分別是:
  1. ServerComponent(.dll)
  2. Presentation(UI)
我們稱之為ServerComponent的部分,本質上就是Class Library,也就是.net的assembly(.dll),其中的具體內容就是一個一個的Method(我稱為ServerMethod)。

除此之外,其他的程式碼我們都已經透過framework所封裝,包含身分驗證、日誌(Log)的儲存、例外處理(exception Handling)、權限與安全性…等。都由Framework中的AOP機制來達成。

所以我們的開發人員在進行ServerComponent的撰寫時,毋須擔心或過度的處理cross-cutting concern部分的機制。撰寫程式碼時,只要繼承自我們提供的BaseClass,並專注在business logic的撰寫即可。cross-cutting concern部分的機制,有我們開發好的一整組Attributes可以用。(例如,只消在ServerMethod掛上WriteLog attribute,該Method即可具有log的功能,掛上Exception Handling attribute即可自動處理例外發生時的紀錄、retry、或alert...)

而前端UI(Presentation Layer)調用服務器端ServerComponent的部分,也是透過我們所建立的Services Layer與前端API。且不管前端用哪一種開發方式,是Web/Desktop/Mobile甚至是iOS或Android,都以同樣的一個Helper(BackendServiceClient)來調用服務器端ServerComnponent中的Server Method(via ExecuteCommand),也就是說,不論是開發哪一種前端,前端對於後端Business Logic調用的寫法幾乎完全相同。

前端開發人員需要發揮的就是UI的處理與特性,後端開發人員需要撰寫與掌握的就是Business Logic。

簡單總結一下,透過這樣的架構:
  1. 後端開發人員需要會的技能是 C#, OOP, ORM(EF), 以及domain know-how
  2. Web前端開發人員需要會的技能是 HTML/JavaScript(or some js framework)
  3. Windows desktop開發人員需要會的技能是 XAML/C#
總的來說,我們盡可能地壓低開發人員所需要的skill set,這樣的目的是確保開發成本降低,並且讓交接與維護更為容易。

我要坦白說一句,這對於開發人員來說不一定100%是好事(但放心,我們並沒有苦待開發人員,我們有架構設計與RD單位,讓具有RD個性、特質、與能力的開發人員,反而更能夠有另一條更有挑戰也更有趣的升遷管道),但這對於專案管理來說,卻是一個很大的利基。當每一個案子都用這樣的方式和架構來開發時,你會發現每一個專案的程式碼寫法與架構都完全相同,在交接或維護時,立刻可以看到優點,管理效率提升到PM會偷笑的程度。

如果依照過去的作法,每一個案子(或產品)都由該案子的Architect來從頭設計架構,你會發現長期下來這根本是一個災難。

首先,先不管坊間framework的變化程度(你想想從ASP.NET WebForm到ASP.NET MVC才幾年? 再想想AngularJS從1.x到2.0的改變...),也不管架構師本身的素養和能力。當每一個案子的特性不同,架構師往往會很『盡責』的去設計出貼近這個案子的開發架構,並且『順手』就把最近學到的新技術給硬生生地塞進去。

你會發現很有趣的事情,在過度自由的開發環境中, 同一個架構師(或同一個團隊),所經手的三個案子,可能會有五種不同的設計。每一次都有新的『改進』,而每一次『改進』,就意味著某些過去的作法被推翻與拋棄,然後架構師又會持續在新的案子中加入了新的元素(或技術、或pattern),企圖讓校能更好,讓開發更方便,或是讓XX更OO、讓ZZ更YY....總之架構師或SD會告訴你...加入這個...加入那個...各種好處不在話下。

如果案子不用維護,那當然沒有任何問題。但你有碰過不用維護的案子嗎? 是了,少到幾乎沒有,所以開發完成之後,往往才是災難的開始。

特定的開發技術,特定的前端框架,這對於開發來說都是機會,但也都是風險,對於維護來說則都是成本。即便用了某些框架,可以很快的完成某些功能,但,以後呢? 如果開發過程中碰到規格變更呢? 這些隱含的成本往往PM和開發團隊都不太關心,但這卻是日後無法結案或無法維護的主因。

也因此,最近這幾年,我們力求統一開發架構,讓每一個專案(甚至產品)的開發,都用完全一樣的Framework(我們自己開發的Framework),當有新的技術或是更好的作法,我們會邀請前線的開發人員,反饋給架構設計單位,並且每季定期釋出框架(framework)更新。由於開發工具的進步,現在我們將框架透過nuget package來導入,更新時開發人員只需要update package即可自動更新。

正如同我前面所說的,架構和框架設計是一種取捨,這樣做讓開發團隊自由發揮的空間減少,卻讓後續維護與交接的成本有效的降低。然而取捨,是一種需要智慧的決定。

有機會,我會再談談在企業和團隊中導入開發框架時,所會碰到的阻礙和因應方案。


-------分割线,下面是aop的参考--------------------------------------------------------------------------------------------------

示例下载。

AOP全名为Aspect-Oriented Programming,有关于AOP的许多名词术语都过于抽象,单从字面上并不容易理解其名词意义,这边将以之前介绍代理机制的范例来逐一对照以介绍AOP的术语与观念:

  • Cross-cutting concern

在DynamicProxyDemo项目的例子中,记录的动作原先被横切(Cross-cutting)入至HelloSpeaker本身所负责的业务流程之中,另外类似于记录这类的动作,如安全(Security)检查、事务(Transaction)等系统层面的服务(Service),在一些应用程序之中常被见到安插至各个对象的处理流程之中,这些动作在AOP的术语中被称之为Cross-cutting concerns。
 

以图片说明可强调出Cross-cutting concerns的意涵,例如原来的业务流程是很单纯的:



现在为了要加入记录(Logging)与安全(Security)检查等服务,对象的程序代码中若被硬生生的写入相关的Logging、Security程序片段,则可使用以下图解表示出Cross-cutting与Cross-cutting concerns的概念:



Cross-cutting concerns若直接撰写在负责某业务的对象之流程中,会使得维护程序的成本增高,例如若您今天要将对象中的记录功能修改或是移除该服务,则必须修改所有撰写曾记录服务的程序代码,然后重新编译,另一方面,Cross-cutting concerns混杂于业务逻辑之中,使得业务对象本身的逻辑或程序的撰写更为复杂。

  •   Aspect

将散落于各个业务对象之中的Cross-cutting concerns收集起来,设计各个独立可重用的对象,这些对象称之为Aspect,例如在DynamicProxyDemo项目中将登录的动作设计为一个LogHandler类别,LogHandler类别在AOP的术语就是Aspect的一个具体实例,在AOP中着重于Aspect的辨认,将之从业务流程中独立出来,在需要该服务的时候,缝合(Weave)至应用程序之上,不需要服务的时候,也可以马上从应用程序中脱离,应用程序中的可重用组件不用作任何的修改,例如在DynamicProxyDemo项目中的HelloSpeaker所代表的角色就是应用程序中可重用的组件,在它需要记录服务时并不用修改本身的程序代码。

另一方面,对于应用程序中可重用的组件来说,以AOP的设计方式,它不用知道处理提供服务的对象之存在,具体的说,与服务相关的API不会出现在可重用的应用程序组件之中,因而可提高这些组件的重用性,您可以将这些组件应用至其它的应用程序之中,而不会因为目前加入了某些服务而与目前的应用程序框架发生耦合。

  • Advice

Aspect的具体实作称之为Advice,以记录的动作而言,Advice中会包括真正的记录程序代码是如何实作的,像是DynamicProxyDemo项目中的LogHandler类别就是Advice的一个具体实例,Advice中包括了Cross-cutting concerns的行为或所要提供的服务。 

  • Joinpoint

Aspect在应用程序执行时加入业务流程的点或时机称之为Joinpoint,具体来说,就是Advice在应用程序中被呼叫执行的时机,这个时机可能是某个方法被呼叫之前或之后(或两者都有),或是某个例外发生的时候。

  • Pointcut

Pointcut是一个定义,藉由这个定义您可以指定某个Aspect在哪些Joinpoint时被应用至应用程序之上。具体的说,您可以在某个定义档中撰写Pointcut,当中说明了哪些Aspect要应用至应用程序中的哪些Joinpoint。 

  • Target

一个Advice被应用的对象或目标对象,例如DynamicProxyDemo项目中的HelloSpeaker就是LogHandler这个Advice的Target。

  • Introduction

对于一个现存的类别,Introduction可以为其增加行为,而不用修改该类别的程序,具体的说,您可以为某个已撰写、编译完成的类别,在执行时期动态加入一些方法或行为,而不用修改或新增任何一行程序代码。

  • Proxy

《Expert One-on-One J2EE Development WIthout EJB》一书中,Rod Johnson、Juergen Hoeller在第八章中有提到,AOP的实作有五个主要的策略: Dynamic Proxies、Dynamic Byte Code Generation、Java Code Generation、Use of a Custon Class Loader、Language Extensions。

在之前静态代理与动态代理中,已经使用实际的程序范例介绍过代理机制的实现,Spring的AOP主要是透过动态代理来完成。

  • Weave

Advice被应用至对象之上的过程称之为缝合(Weave),在AOP中缝合的方式有几个时间点:编译时期(Compile time)、类别加载时期(Classload time)、执行时期(Runtime)。
 

结合DynamicProxyDemo的实例,将以上介绍过的AOP相关名词具体的使用图片来加以表示,有助于您对每一个名词的理解与认识:



0


关于aop ,请参考http://blog.csdn.net/caterpillar_here/article/details/753473

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值