1. 程式人生 > >記一次ORM的權衡和取捨

記一次ORM的權衡和取捨

面對ORM的選型,有些人是根據自己熟悉程度來評判,有些人是根據他人的推薦來抉擇,有些人覺得都差不多,隨便了。當自己要真正做選擇的時候,以上的這些依據都無法真正說服自己,因為不同的業務需求,不同的團隊構成都會造成選型的差異,而且特別大,這裡談一談自己的選型。

1.1需求背景介紹

  • 我所在的公司是做網際網路產品,對效能有著極致的要求;
  • 後臺人數也不算多,儘量人盡其用,技術水平呈梯度分佈;
  • 因為產品需要長期維護,所以對程式碼質量要求非常高,必須做評審和單元測試;
  • 對技術的可維護性,可擴充套件性要求很高,因為資源有限;
  • 因為資源有限,所以在生產力和效能之間需要做一個平衡;

1.2需求分析

難點

  我們知道沒有完美的技術,魚和熊掌無法兼得,所以我們必須擇優錄取,這裡的複雜度在於你要對所選擇的技術優缺點有一個360度的環評,最好能展示各自優缺點對比一覽圖,最後依據資料來證明你的選擇對的,是對團隊和業務負責的。

現狀

  不知道你有沒有呆過這樣的團隊:

  • 選什麼技術從不討論,大夥各自悶聲幹,等幹出來你才知道原來對方是用的IBatis.NET。
  • 你是後面入職的,你只能在前人的基礎上做維護,儘管你覺得這個技術不是最優的,但是你也無法瞭解當初為什麼做這樣的選擇。
  • 在入職後,沒有規範的技術培訓和規範,你一邊Google一邊編碼一邊罵娘。

  所以對需求的分析和選型在前期特別的重要,沒有對比的選擇,感覺活得有點不明不白,你無法說服自己,更無法說服團隊和領導。

分析

  根據網際網路業務特點和團隊結構,我們的選擇有幾個重要的關鍵詞:

  • 高效能
  • 易使用
  • 可擴充套件

  高效能就不用說了,網際網路產品,毫秒必爭!

  易用性和易維護相似,希望能在後續運維過程中不要給團隊造成維護的困難,同時也遵循簡單原則,高階的東西都有簡單的特點。

  可擴充套件面對的是產品的變更,很難想象高效能,易使用但是擴充套件性很差的產品,這種瑕疵會造成程式碼的臃腫和腐朽。

  所以,這個權衡的標準就出來了,效能、易用、擴充套件。

1.3備選方案

  這裡的備選方案由於精力和時間的關係,根據經驗和評論只羅列EF Core、Dapper、SmartSql三種,另外一個原因是這三種設計理念完全是不一樣的,差異性很大。另外有些人也會偏愛NHibernate Core(和EF雷同,不做考慮)或者SqlSuger等,不在本文討論範圍。

備選方案1:EF Core

優點

  • 強型別帶來維護的安全感,一旦資料庫有修改或者欄位變更,編譯帶來的BUG提示,可用極大提升維護效率。
  • EF Core的Code first和自動遷移功能,對面向DDD的設計十分友好,對DB遷移的高效帶來的體驗也非常棒。
  • 領域優先的設計理念,在和業務人員溝通的過程中,優勢也相對明顯。
  • 喜歡寫SQL的同學,不要忘記EF本身相容原生指令碼,包括儲存過程,不過不是優先的選擇。
  • 支援多種資料庫。

缺點

  • 入門容易,精通比較難,其知識體系有點複雜,學習曲線會比較陡峭!
  • 生成的SQL需要除錯和跟蹤,面對多表聯合查詢,效能就不用說了。
  • 需要藉助效能檢測工具比如MiniProfiler來進行效能分析和監控。
  • “我想好了Sql怎麼寫,然後再來寫Linq,完了可能還要再檢視一下Linq輸出的Sql是什麼樣的“。這是非常糟糕的體驗。

適用場景

  在效能和生產力之間可以做很好的平衡,比如企業管理系統、個人站點或者外包專案等。

  對EF Core來說如果用的好,效能是完全可以做到非常高的,雖然不是極致的效果,但是在開發效率和效能之間可以做一個很好的平衡。

備選方案2:Dapper

  Dapper是.NET的一款輕量級ORM工具(GitHub),也可稱為簡單物件對映器。在速度方面擁有微型ORM之王的稱號。它是半自動的,也就是說實體類和SQL語句都要自己寫,但它提供自動物件對映。是通過對IDbConnection介面的擴充套件來操作資料庫的。

優點

  • 輕量,只有一個檔案
  • 效能高,Dapper的速度接近與IDataReader,取列表的資料超過了DataTable。
  • 支援多種資料庫。Dapper可以在所有Ado.net Providers下工作,包括sqlite, sqlce, firebird, oracle, MySQL, PostgreSQL and SQL Server
  • 使用Dapper可以自動進行物件對映,通過Emit反射IDataReader的序列佇列,來快速的得到和產生物件

缺點

  • 程式碼裡邊充斥著 SQL 和各種判斷分支,這些將會使程式碼維護難以閱讀和維護,更談不上Linq的優雅。
  • 和EF相比,手寫SQL 當修改表結構不易發現bug。
  • 習慣了EF後再來使用Dapper,會很難適應那種沒有了強型別的安全感。

適用場景

  對效能有著極限的追求,同時能寫一手很好的SQL(對資料庫能達到DBA的水準更好),懷念SQL的感覺,習慣SQL的體驗的同學。

  在可維護這塊有做單元測試,很好的規避後期維護的困難。

備選方案3:SmartSql

  為什麼這邊沒有選擇NHibernate-Core?是因為這傢伙和EF Core太像了,在人氣上來看,完全沒有必要去做選型,當然如果你的團隊有NHibernate情節,對NH玩得風生水起例外。

  為什麼是SmartSql而不是MyBatis?主要是Mybatis在跨平臺上找到不到開源方案,幾乎沒有更新,更不用說跨平臺了。而且SmartSql的設計理念就是借鑑的Mybatis,同時又增加了不少強大的功能,比如支援快取、CQRS等乾貨,看官宣SmartSql就一句話:

MyBatis .NET Core+ Cache(Memory | Redis) + R/W Splitting +Dynamic Repository + Diagnostics 

優點

  • 因為SQL自擼,所以效能和Dapper不相上下,非常的高。
  • SmartSql 借鑑了 MyBatis 的思想,使用 XML 來管理 SQL ,並且提供了若干個篩選器標籤來消除程式碼層面的各種 if/else 的判斷分支。
  • SmartSql將管理你的 SQL ,並且通過篩選標籤來維護本來你在程式碼層面的各種條件判斷,使你的程式碼更加優美,你再也不用看到到處充斥的SQL了,對程式碼優雅有著極限追求的人會有點受不了。
  • 支援多種資料庫

缺點

  • 易排查:排查性和維護性對新人來說,個人感覺不是十分友好,寫SQL會考驗你的細心。
  • 使用 XML 來管理 SQL個人覺得是優點也是缺點,因為程式碼優雅了,但是有些人並不是很感冒這種方式,特別是在XML裡面的if/else的邏輯判斷,不親切。
  • 穩定性有待提升,雖然官宣對Dapper有很好的提升,但是從人氣來看,成熟度需要進一步觀察。

適用場景

  喜歡Dapper的效能,但是不喜歡到處充斥的SQL指令碼,追求極致優雅,同時又對SmartSql的特性和效率特別欣賞。但是從人氣和成熟度來看,如果對原始碼沒有很好的掌控能力,碰到坑就不好搞了。

1.4備選方案評估和選擇

  在評估和最終選型的時候,建議做360度環評,架構人員、開發人員、運維人員、測試人員不妨都請過來參與一下。

  架構人員首先給出自己的備選方案,然後舉行備選方案評估會議,再根據會議結論修改備選方案文件。

  有些團隊主管或者叫技術經理一人就包辦了需求分析、方案選型等工作,雖然這種方式效率很高,但是對團隊開發的推進和向上彙報其實是很不利的。首先團隊會覺得你大包大攬,黑箱操作;領導會覺得你做事沒有章法和原則,萬一你離職了,你留下的後遺症和黑鍋需要你來背,也許你會覺得我都離職了,關我上面事!

  我覺得你的技術牌子首先就砸了,你的影響力和同事的相處能力也消減了,你的分享能力和做事風格也就丟分了,這些無形的資產會在將來某一個時刻帶你帶來晦氣。

結論:Dapper+擴充套件

  根據人氣、效能和易用性,我選擇了Dapper。EF Core的效能和精通的門檻是我拋棄它的原因,而SmartSql儘管設計理念是我的最愛,但他的人氣和坑是我擔心的點。因為無法魚和熊掌兼得,所以只能根據自己的情況進行取捨,但是你無法開懷,因為你要包容Dapper帶給你的不足,而這些不足,我個人選擇單元測試來彌補;同時對Dapper的進一步封裝和優化也是接下來很重要的工作:比如AOP攔截代替到處都在的Transaction等等,正式的工作才剛剛開始……