本文章是由機器翻譯。

.NET Framework

彈性存取層 + 相依性插入 = 產能

Ulrik Born

最艱巨的挑戰時管理和開發一個複雜的企業解決方案的原始程式碼,是確保基本代碼之一仍然一致、 直觀的和高度可測試正在同時保持和擴大了在大型軟體發展署內的多個小組。核心問題是開發人員通常有大量的規則和準則,遵循和一組實用程式庫,若要使用,往往會導致他們的解決方案變得更大、 更複雜。這是因為他們最終調整理想、 直觀的業務邏輯實現,使其遵守規則和適合固定的 Api。這更通常意味著更多的工作,對於開發人員來說,bug、 較少的標準化、 少重用,並降低整體生產力和品質。

我是為領先的線上投資銀行高級開發人員,已觀察到這些挑戰如何可以限制生產力。這篇文章是一個案例研究,提出了我們的開發團隊已經如何分析和克服的挑戰的創新使用的運行時代碼生成和依賴關係注入 (DI)。你可能不同意的一些我們的團隊設計的選擇,但我相信你會同意他們代表解決一些常見的建築挑戰的新鮮和有效的方式。

我公司擁有大內部軟體發展部 (工作在兩個大陸上的),不斷維護和擴展了我們巨大的 Microsoft.NET 框架代碼庫。我們的代碼庫重點是眾多任務關鍵型 Windows 服務,彌補在我們資料中心主辦的高性能、 低延遲的交易系統。我們有不少平臺團隊守護的代碼庫和運行時環境,再加上許多專案團隊,不斷 (和並行) 改善和擴展系統。

我上平臺團隊工作幾年,經驗豐富的缺點的不一致和過於複雜代碼庫期間多次審查和支援情況。兩年前,我們決定來解決這些問題,併發現了以下問題:

  • 我們有了太多的相同的基本問題解決方案。一個好的例子是我們大多數的 Windows 服務有自己獨特的方式與相結合的各種 Api 成一個簡單的服務適當支援日誌記錄、 跟蹤、 資料庫訪問等等。
  • 我們的業務邏輯實現了要麼簡單 — —­但不是單位可測試和太幼稚、 不遵守準則 — — 或由於大量水暖代碼過於複雜。一個常見的例子:簡單工作直接在.NETSQL ServerAPI 與瑣細的管道,支援自動重試次數,花更多線條的複雜代碼,所以比上的快取記憶體的實際業務邏輯的代碼。
  • 我們有實用程式庫支援大多數我們的建築原則和編碼準則,但是他們在幾個不同的樣式中實現並獨立地進化。結束時即使使用它們作為聽寫的指導方針時,每個功能解決方案已有巨大足跡的引用的程式集和往 API 更改曝光。這反過來讓這一複雜的任務本身投入在生產中的一項新功能,也使它難以更新實用程式庫。
  • 整體的一套準則和要應用的規則和實用程式,以使用只是那麼大僅自己們大多數經驗豐富的開發人員已經為新的開發人員理解一切,和進入壁壘的一個公平的機會是極高。這意味著大量的非標準代碼書面的要麼以後丟棄或到達生產以增加不一致。
  • 我們的核心 Windows 服務的幾個了中央"註冊點"所有專案團隊都必須觸摸相同的代碼的地方 — — 例如,大型 switch 語句調度命令或工作崗位。這使得非平凡代碼合併到我們主要分支。

Natrually,這些問題是既不是新的也不是唯一給我們,和一些既定的設計模式描述如何解決此類問題:

  • 門面模式隱藏訪問一個簡單的訪問層介面背後是複雜的資源的所有細節。這便於清潔和可測試業務邏輯實現在外部資源可以被輕鬆地嘲笑出來在測試中。
  • DI — — 或控制反轉 (IoC) 容器 — — 允許元件的鬆散耦合的因此易於擴展、 維護和結合起來。這種技術也容易地類比出選定的元件,從而提高可測試性。
  • 精心設計實用程式庫的 Api,不要強制消費代碼予以調整 ; 相反,他們支援直觀執行。

我們已經知道這些模式多年,也應用他們都以各種形式在整個我們的代碼庫。但是幾個基本問題大大限制了這些模式的成功。第一,門面模式並不消除對很多管道代碼的需要 — — 它只是將其移動到另一個類,通常只是手段更工作為開發人員。第二,除非 DI 容器會自動探索它的元件在運行時 (例如,通過屬性),它仍將需要一個中央註冊,並將只是現實中引入附加層執行。而且,最後,它是成本高昂而且極難設計和實施在同一時間是直觀的、 靈活的和有用的 Api。

為什麼我們創建了自我調整訪問圖層

集思廣議會議次數後, 我們來到了一個單一的靈活且功能強大的解決方案與所有的這些問題。基本思想是以隱藏所有 Api 都歸因於的訪問層介面背後並生成一個執行引擎,可以在運行時中遵循所有的規則和準則的方式實現這種介面。我們要求這項技術自我調整訪問層 (AAL),因為每個解決方案定義的訪問層介面,它需要高度靈活的方式。我們結合開源,屬性驅動 Autofac DI 容器的 AAL 執行引擎,實現靈活的 Windows 服務框架,使清潔、 直觀和可測試實現成為最簡單的選項。圖 1 闡釋了如何的大小、 足跡和解決方案的複雜性大大減少當 AAL 用於解耦核心邏輯實現從周圍的庫和 Api。藍框代表一個單一的解決方案,(在左側) 與 AAL 執行的足跡和無 (右側)。


圖 1 自我調整訪問層 (描述上左) 大大降低解決方案的複雜程度和足跡

AAL 技術的一個關鍵特徵是它給我們一個共同的中心位置,不會污染的業務邏輯代碼執行我們的最佳做法和準則。在這方面,AAL 是類似于面向方面程式設計 (AOP)、 各種攔截功能和代理技術。主要的區別是 AAL 隱藏底層的 Api 來從消費的業務邏輯代碼,而其他技術仍然公開他們,從而大大增加解決方案足跡。

為了說明這個想法,我將討論一些業務邏輯和標準的 Windows 事件日誌之間的簡單訪問層。考慮在資料庫中註冊傳入訂單訂購登記服務。如果資料庫調用失敗,則該服務必須寫入事件日誌錯誤。

在經典的方法中,這可能涉及對.NET EventLog.WriteEntry 方法的調用,可能看起來像中的代碼圖 2。這種方法不是最優,原因有二。第一,它不是非常適合的單元測試,該測試會檢查運行單元測試來驗證與正確的文本條目實際寫入電腦上的事件日誌。和第二、 四行的瑣細的水管系統的代碼會"污染"的業務邏輯的一個核心部分。

圖 2 經典事件日誌訪問

public OrderConfirmation RegisterOrder(Order order)
{ 
  try 
  {  
    // Call database to register order and return confirmation 
  } 
  catch (Exception ex) 
  {   
    string msg = string.Format("Order {0} not registered due to error: {1}",     
      order.OrderId,     
      ex.Message);   
    _eventLog.WriteEntry(msg, 1000, EventLogEntryType.Error); 
  }
}

這兩個問題被針對引入 AAL 的業務邏輯和底層的 EventLog 類之間的介面。這種一層下面的代碼所示:

[EventLogContract("OrderService")]
public interface IOrderServiceEventLog{
    [EventEntryContract(1000, EventLogEntryType.Error,
        "Order {0} not reg due to error: {1}"]
    void OrderRegistrationFailed(int orderId, string message);
}

圖層是由化介面 IOrderServiceEventLog,通過實施動態類由執行引擎在運行時定義的。介面本身具有 [EventLogContract] 的屬性以允許執行引擎承認它是一個事件日誌的訪問層。單個參數是為目標的事件日誌的名稱。有對名稱的介面或方法上它的數目沒有限制。每個方法必須返回的 void (有向事件日誌寫入資訊時是沒有意義的傳回值),並且有 [EventEntryContract] 屬性。該屬性將所有固定元資料輸入 (id、 嚴重性和格式) 作為參數,這不再需要在業務邏輯中。

介面使用訪問層、 業務邏輯從圖 2 成為了很多更小和更清晰:

public OrderConfirmation RegisterOrder(Order order)
{
    try  
    {
        // Call database to register order and return confirmation
    }
    catch (Exception ex)  
    {
        _logLayer.OrderRegistrationFailed(order.Id, ex.Message);   
    }
}

示例 RegisterOrder 方法現在是簡單、 高度可讀和可更多測試,因為驗證不再要求檢查事件日誌而是只小類比實現訪問層介面的類。另一個優點是可以通過整個訂單服務映射事件日誌已滿的互動和從而提供一個簡單的然而什麼事件日誌條目的完整概述系統寫入 IOrderServiceEventLog 介面。

(附註:簡短的一邊,作為最近語義日誌記錄應用程式塊 [板] 對新.NET 4.5 EventSource 類擁抱將中繼資料從代碼移動到屬性和公開自訂的、 強型別的測井方法,而不是通用的幾種方法同樣的想法。若要使用板,開發人員必須實現從 EventSource 類派生的自訂類和使用此類整個代碼庫。我相信我們的方法是作為板一樣強大但便於使用,因為它只需要開發人員定義的介面和類的實現不。EventSource 類的一個關鍵特徵是它支援通過接收器可組態集的結構化的事件日誌記錄。我們的訪問層實現當前不支援結構化的日誌記錄但可以輕鬆地擴展為這樣做,因為它有訪問通過訪問層方法的參數的結構化資訊。)

我還沒尚未考慮 RegisterOrder 方法的真正主體,即對一些SQL Server資料庫的調用預存程序來堅持的順序進行進一步處理。如果我的團隊使用.NET SqlClient API 來實現這個,它將至少 10 行的瑣細的代碼來創建 SqlConnection 實例和 SqlCommand 實例,填充帶從順序屬性參數的命令、 執行命令和讀回的結果集。如果我們要滿足額外的要求,如在資料庫鎖死或超時的情況下自動重試,我們可以輕鬆地結束 15 到 20 行代碼只是為了讓一個相當簡單的調用。所有這一切需要和只是因為調用的目標發生了是一個存儲的過程,而不是進程在.NET 方法。從業務邏輯的觀點看,是絕對沒有理由為什麼我們核心執行應該如此混亂和複雜,只是因為加工十字架從一個系統到另一個。

通過引入類似的事件日誌訪問層自我調整資料庫訪問層,我們可以實現簡單、 可測試身體:

public OrderConfirmation RegisterOrder(Order order)
{
  try
  {
    return _ordersDbLayer.RegisterOrder(order);
  }
  catch (Exception ex)
  {
    _logLayer.OrderRegistrationFailed(order.Id, ex.Message);
   }
}

到目前為止,我已經說明了想法、 靈活性和 AAL 的力量。我們已經開發了,發現有用的訪問層更詳細攻略,我們現在就隨。我會從開始上述資料庫訪問層。

資料庫訪問層資料庫訪問是大多數企業系統中,包括我們的核心部分。我們正在關鍵的調解人的嚴重線上交易的金融工具,必須滿足一些嚴格的性能和安全要求由我們的客戶和金融當局,要求,因此被迫仔細地保障我們的資料庫。我們一般通過這樣做只做資料庫訪問通過預存程序中,如讓我們應用細細微性安全規則和審查所有資料庫的查詢性能和伺服器負載之前他們打我們的生產系統。

我們已經仔細評估是否預存程序的物件關係映射 (ORM) 工具如Entity Framework可以説明我們實現更簡單和更可測試代碼,而無需移動遠離。我們的結論是Entity Framework是一個極具吸引力的解決方案,但它很大程度依賴于能夠撰寫並在運行時執行複雜的 SQL 語句。它可以將映射的存儲的過程,但限於映射唯一的存儲的過程,它失去了大部分的它的好處。為此原因,我們決定實施我們自己的資料庫訪問框架作為自我調整資料庫訪問層。

我們的執行支援存儲的程序呼叫,選擇意見和有效的大規模插入通過SQL Server批量複製功能了。它可以映射到存儲的過程參數輸入的資料直接從資料傳輸物件 (DTO) 類的屬性和同樣可以將結果集的列映射到類的屬性。做.NET 代碼中的資料庫訪問時,這有助於明確和直接的語法。

下面的代碼演示一個簡單的層,適合的示例命令註冊服務:

[DatabaseContract("Orders")]
public interface IOrdersDatabase{
  [StoredProcedureContract("dbo.RegisterOrder",
    Returns=ReturnOption.SingleRow)]
   OrderConfirmation RegisterOrder(Order order);
 }

此代碼映射單個存儲的過程和結果單排在結果集中到 OrderConfirmation 實例初始化從結果集列。從給定的命令實例的屬性設置映射的預存程序的參數。此映射行為定義在 [StoredProcedure­合同] 屬性,因而不再需要在業務邏輯執行,使這一清晰和可讀。

因為我們認為它是簡單而有效的方式向我們的開發人員提供標準的功能,而不限制他們的自由,以最自然和最直觀的方式實現他們的業務邏輯的我們已經在資料庫訪問層實施一些相當高級的功能。

支援的功能之一是對大容量插入行通過 SQL 批量複製功能的無縫支援。我們的支援使我們開發人員可以定義一個簡單的方法,採用的表示要作為輸入插入的行的 DTO 類的可枚舉集合。訪問層處理所有的細節,從而減輕 15 到 20 的代碼的行複雜,以資料庫為中心的業務邏輯。這種大容量複製支援是一個完美的例子,概念上很簡單操作的 — — 以行插入到表中的有效方式 — — 通常最終被相當複雜,簡單地實施因為基礎.NET 框架 SqlBulkCopy 類發生工作 IDataReader,而不是直接在我們 DTO 類上。

資料庫訪問層是我們實施的第一個,它已從一開始一個巨大的成功。我們的經驗是我們編寫更少、 更簡單行代碼與它和我們的解決方案自然成為高度單位可測試。基於這些積極的成果,我們很快意識到我們可以受益于我們的業務邏輯代碼和其他幾個外部資源之間引入 AAL。

服務訪問層我們交易系統的實施是高度面向服務、 和魯棒間服務通信對於我們至關重要。我們的標準協定是 Windows 通信基礎 (WCF),我們有很多的重點是使 WCF 調用的代碼。

大部分的這些實現按照相同的總體格局。第一,終結點的位址是解決 (我們通常運行我們的服務或者在主動-主動或主動-被動設置)。然後 ChannelFactory.NET 類用於創建對其所需的方法調用一個通道類實現。如果此方法成功,通道是關閉和釋放,但如果它失敗,異常也要進行檢查。在某些情況下,重試的方法上同一個終結點,而在其他情況下它是更好地做自動容錯移轉和重試的其他可用的終結點之一是有意義的。在此之上,我們常常想要隔離很短的時間,以不重載它與連接嘗試和失敗的方法調用失敗終結點。

它很不瑣碎,寫這種模式,正確執行,它可以很容易地 10 到 15 行代碼。並再次,這種複雜性介紹了只是因為我們需要調用的業務邏輯發生承載在另一項服務,並不在進程。我們已經實現了自我調整服務訪問層,消除這種複雜性,使之盡可能簡單和安全地調用遠端方法,因為它是調用進程的方法。

與相同的資料庫訪問層的原則和工作流。開發人員將寫入化的介面映射只有她需要調用的方法和我們執行引擎創建的最佳實踐行為作為指定在屬性中的使用實現介面的運行時類型。

下面的代碼顯示映射單個方法小服務訪問層:

[ServiceAccessLayer(typeof(IStatisticsSvc), 
  "net.tcp", "STATISTICS_SVC"]
public interface ISalesStatistics{
  [ServiceOperationContract("GetTopSellingItems")]
  Product[] GetTopProducts(int productCategory);
}

介面屬性標識基礎純 [ServiceContract] 歸因於介面 (用於對 ChannelFactory 的內部調用)、 要使用的協定和服務調用的 id。後者用作鍵進入我們的服務定位器,在調用時解決實際的端點位址。訪問層將在預設情況下使用預設 WCF 綁定為給定的協定,但這可以通過在 [ServiceAccessLayer] 屬性上設置的附加屬性自訂。

ServiceOperationContract 的單個參數是操作的動詞,用於標識基本的 WCF 服務合同中的映射的方法。其他的可選參數的屬性指定是否應快取服務調用結果和是否始終是安全的自動容錯移轉操作即使 WCF 終結點的第一個調用失敗後目標服務上已執行的代碼。

其他訪問層我們也建立了類似 AAL 用於追蹤檔案、 效能計數器和我們消息匯流排。他們都基於前面的示例中所示的同一原則 — — 即,要允許的業務邏輯來表達其資源訪問的可能的最簡單的方式由移動到的所有中繼資料屬性。

依賴關係注入一體化

與圖層的訪問,我們的開發人員不再需要執行大量的瑣碎水暖代碼,但仍必須有一種方法來調用,AAL 執行引擎,以獲得執行的運行時類型的實例,每當該映射的外部資源已被稱為。執行引擎可以直接調用,但那樣會違背我們的保持清潔和可測試業務邏輯的原則。

我們已經通過註冊我們的執行引擎作為一個動態註冊來源與 Autofac 這樣每當 Autofac 不能解決與靜態註冊的任何依賴項時,就會調用來處理這個問題。在這種情況下,Autofac 會問,執行引擎是否它可以解決給定的類型和 id 的組合。引擎將檢查類型,並提供該類型的實例,如果該類型是歸因於的訪問層介面。

這個地方,我們已經建立了在業務邏輯實現簡單地可以聲明其訪問層介面的類型和環境把他們當作參數 (例如,在類的建構函式),然後 DI 容器將能夠解決這些參數通過援引在幕後執行引擎的信任。此類實現自然會在介面上的工作,並且很容易測試,它只需幾個 mock 類來實現這些介面。

實作

所有我們訪問層是使用相同的技術來實現的。總的想法是在普通的 C# 代碼中的抽象基類中實現的所有功能,然後僅使用發出以生成薄類從基類派生並實現該介面。發出的方法體的每個介面簡單地將轉發到一般的 Execute 方法在基類中執行。

這一般方法的簽名是:

object Execute(Attribute, MethodInfo, object[], TAttributeData)

第一個參數是從中調用 Execute 方法的訪問層介面方法的方法屬性。它通常包含的所有中繼資料 (例如,存儲的過程的名稱、 重試規範等等) 所需的 Execute 方法,以提供正確的運行時行為。

第二個參數是介面方法的反射的 MethodInfo 實例。它包含有關該實現的方法的完整資訊 — — 包括的類型和方法參數的名稱 — — 和 Execute 方法用於解釋第三個參數。它包含所有參數的值到當前介面方法調用。Execute 方法通常轉發這些值到基礎資源的 API,例如,作為存儲的過程的參數。

第四個參數是自訂類型,擁有固定的資料,用於在每次調用該方法,使其盡可能高效。固定的資料被初始化一次 (由抽象基類中的方法) 時,引擎實現的運行時類。我們資料庫訪問層使用此功能來檢查只有一次的存儲的過程和準備準備好使用的 SqlCommand 範本時調用該方法。

傳遞到 Execute 方法的特性和 MethodInfo 參數也只有一次反映並重複使用在每個方法調用,又儘量減少每個調用的系統開銷。

執行的傳回值用作實現的介面方法的傳回值。

這種結構相當簡單,已變得靈活和強大。我們已經在通過一個抽象的、 共同的基類 AccessLayerBase 該類的所有我們訪問層中重用它。它實現了所有所需的邏輯化的介面和磁碟機發出一個新的運行時類的過程進行檢查。每個接入層類別都有自己專門的抽象基類從 AccessLayerBase 派生。它擁有的實際執行情況訪問外部資源,例如,使存儲的程序呼叫根據我們所有的最佳實踐。圖 3 顯示為示例資料庫訪問層介面執行類層次結構。藍色部分是 AAL 的框架 ; 紅色部分是歸因於的介面定義的業務邏輯功能解決方案 ; 綠色部分中,排放的 AAL 執行引擎的運行時類。


圖 3 訪問層實施綱要

圖 3 也說明了我們如何讓基類實現一組公共介面 (從 IAccessLayer 派生) 以公開關鍵行為資訊。這不打算用於由業務邏輯實現,但而是通過基礎設施的邏輯 — — 例如,要跟蹤每當一個存儲的程序呼叫將失敗。

這些訪問層介面也是在業務或技術要求要求對後面的訪問層基礎資源的訪問不完全支援 AAL 的方式做的幾個特殊情況下很有用的。有了這些介面,我們的開發人員可以使用 AAL 但攔截和調整底層操作以滿足特殊的要求。一個很好的例子是 IDatabaseAccessLayer.ExecutingCommand 事件。這引發右前 SqlCommand 執行的使我們能夠通過改變事物如超時值或參數來自訂它。

報告和檢查

歸因於 AAL 介面的一個業務邏輯解決方案,還使我們能夠反映在已編譯的二進位檔案生成時間和提取數量的有用的報告。我們的團隊已納入這我們的Team Foundation伺服器 (TFS) 生成這樣每個生成的輸出現在包括幾個內容豐富的小 XML 檔。

報告生成時間資料庫訪問層報告完整清單的所有存儲的過程、 視圖和大容量插入正在訪問。我們使用此來簡化點評並檢查所有所需的資料庫物件正確部署和配置之前我們釋放的業務邏輯。

同樣,我們的事件日誌的訪問層報告一項服務可以生成的事件日誌條目的完整的清單。我們的生成後步驟採取此資訊,並把它變成我們 Microsoft 系統中心操作管理器生產環境監測的管理包。這是聰明的因為它確保運營經理始終是最新的正確的資訊,關於如何最佳處理生產問題。

自動化 Microsoft 安裝程式套裝程式我們已經應用相同的反射技術,收穫寶貴的投入到我們為我們的 Windows 服務生成作為我們 TFS 的最後一步生成的 Microsoft 安裝程式 (MSI) 套裝程式。這些套件的一個關鍵點是要安裝和配置事件日誌和效能計數器以確保它們匹配正在部署的業務邏輯。生成從二進位檔案中提取事件日誌名稱和效能計數器定義和自動生成 MSI 套裝軟體,安裝這些名稱和定義。

運行時檢查使用報告從我們生產環境的最常見錯誤之一是一項服務曾試圖調用的存儲的過程,並不存在或存在了與生產資料庫上的錯誤簽名。這些類型的錯誤發生了因為我們錯過了部署的所有所需的資料庫物件,當我們生產部署 Windows 服務。這裡的關鍵問題並不缺少部署本身,因為那可以修復很容易,但更多的事實該錯誤不是發生在部署但通常後來當存儲的過程是第一次調用期間上班時間。我們使用了基於反射的所有訪問的資料庫物件清單來解決這一問題,讓我們的 Windows 服務在服務啟動過程中驗證的存在性和有效性的所有物件。該服務只需運行通過物件的清單,然後查詢資料庫,為每一個要檢查它將能夠訪問該物件時所需。這種方式,我們已經所有此類錯誤從上班時間到部署時間,當它是很多更安全和更容易地解決這些問題。

下面列出了這些附加的用法來說明 AAL 的一個主要好處。與有關服務行為很容易可通過反射幾乎完成的資訊,一個全新的智慧化報告、 建築、 自動化和監測開闢了。我們的團隊收穫了到目前為止,這些好處的一小部分,但我們看到更多有趣的應用未來數。

生產力和品質

AAL、 設計和實施在過去兩年,已證明是非常強大的調解人的提高開發人員生產率和增加的解決方案品質為我們公司的開發團隊。我們已經降低我們的成本,準備從周小時到新的 Windows 服務和現有的服務從天延長到幾分鐘。這已改進我們的靈活性,從而做為我們發展我們的客戶產品更便宜。

實現絕大多數的我們的業務解決方案時,我們訪問層是適當的。但是,我們有幾個特殊情況下他們不適合 — — 通常是在高度可配置的方案,例如,當從配置表中讀取並在編譯時不知道要調用的預存程序的名稱。我們的團隊有故意選擇不支援這種情況下,為了避免將引入附加的框架複雜性。相反,我們允許我們在這種孤立的情況下使用普通的.NET Api 的開發人員。

AAL 解決辦法本身並不大,在幾個月內會在兩年期間已經制定。因此,我們的初始投資不是很高,已達到盈虧平衡狀態,通過大量的已保存的發展和支援小時。

當然,有一個廣泛應用和高度靈活的平臺的挑戰是它可以成為一個單點故障。我們減輕了這個由擁有完整的單元測試覆蓋率的 AAL 解決方案和推出它的新版本中受管轄的服務的服務方式。你也可以認為 AAL 辦法本身我們的系統中引入額外的複雜性,並迫使我們開發人員學習新的抽象層。但我們認為這超過補償提高整體生產力和品質。

我們知道的另一個問題是我們必須把重點放在整體設計和體系結構並不只是簡單地把 Windows 服務的一切都因為這種做法已變得如此便宜和容易。有時候 IIS 承載 Windows 進程啟動服務 (WAS) 或協力廠商解決方案提供一個更好的總體解決方案,即使它將添加到我們的生產環境的多樣性。

Ulrik Born 資訊技術從丹麥技術大學碩士學位和一直以來在過去的 15 年作為開發商和建築師在 Windows 平臺上。他是領先開發者,盛寶銀行、 基於互聯網的投資銀行。

衷心感谢以下技术专家对本文的审阅:古德永松約拿斯 (盛寶銀行)、James麥卡弗裡 (Microsoft) 格裡梅爾 (Microsoft) 和費爾南多 · Simonazzi (Microsoft)
約拿斯 · 古德永松、 副總裁和企業的建築師,是首席技術官辦公室負責盛寶銀行,包括戰略、 原則和準則的四個建築領域的總體 IT 體系結構的一部分

博士。James麥卡弗裡為微軟在華盛頓州雷德蒙德,校園的工作。他曾經參與過多項 Microsoft 產品的研發,包括 Internet Explorer 和 MSN Search。他是作者的".NET 測試自動化食譜"(Apress,2006 年),並可以在達成 jammc@microsoft.com

博士。格裡戈裡 Melnik 是微軟模式的首席專案經理 & 實踐團隊。這些天他開車的微軟企業庫、 統一、 CQRS 的旅程和 NUI 模式專案。他還設計為它促進效率。在此之前,他是一個足夠長的時間前的研究員和軟體工程師還記得在 Fortran 程式設計的樂趣。格裡戈裡講話世界各地關於主題的代碼重用、 雲計算、 敏捷方法和軟體測試。他還擔任 IEEE 軟體諮詢委員會。在他博客 HTTP://blogs.msdn.com/agile

費爾南多 · Simonazzi 是一個軟體發展商和建築師有超過 15 年的專業經驗。他已經貢獻者微軟模式 & 包括企業圖書館、 統一,CQRS 的旅程和棱鏡的幾個版本的做法的專案。費爾南多是副研究員 Clarius 諮詢。