爲何我再也不用 .NET 框架

.NET平臺很棒。真的很棒。直到它再也不那麼棒。我爲何再也不用.NET?簡單來講,它限制了咱們選擇的能力(對我來講很重要),轉移了咱們的注意力,使得咱們向內認知它的安全性,替代了幫助咱們認知外面廣闊世界的全部可能性。php

[繫好安全帶:這個文章的長度幾乎成了一本書…]html

優勢

首先讓我開始說說.NET作得對的許多事吧,儘管這其中的大多數並不來自.NET自己,但倒是由.NET社區而來。java

C#

C#使人驚歎。我認爲它是一個使人驚歎的編程語言。從強大的C語言背景而來,我完全地喜歡其語法,流和這門語言的所帶來的感受。固然有我可能改變的事,但整體來講它是一門紮實的語言。而且基於開發人員使用的編程語言如此鉅額的百分比和Windows操做系統的優越性,它是一門衆所周知的語言。nginx

ReSharper

我也很喜歡Resharper。在JetBrains工做的開發者們都是奇蹟般的人。若是沒有ReSharper和一些相關的工具,我可能並不會如此喜歡C#。git

BDD and MSpec

我也很喜歡簡稱爲機器規格(mspec)的BDD風格的框架。它是一個使人驚歎的測試框架,真正支持在測試中使用正確的語言測試自己。在使用mspec以前,個人測試真是一團糟而且很礙個人事。github

另外,當咱們建立GoConvey—基於Golang的BDD測試框架的時候,Mspec對於個人組織來講是一個巨大的靈感和激勵。web

多語言運行時

我認爲多語言的CLR(公共語言運行時)的觀念真得使得JVM的世界思考着。我不知道任何非Java的JVM語言在CLR以前,但隨着「公共語言運行時」的到來,個人理解是這使得使用JVM的人們向前進而且最終創造瞭如Scala和Clojure這樣偉大的JVM編程語言。若是我錯了請糾正我。再者,CLR使得Sun公司的人們坐下來並關注它,由於Java有一點陳舊而且隨着Java 8的到來,僅僅如今纔在多個方面追趕着。競爭是一件很是好的事。數據庫

NuGet

另外一個顯著的例子是NuGet。這個包在Windows中做爲一個總體特別是在Windows的開發中,它的管理軼事是糟透的。NuGet解決了不少問題,他們也經過從Python和Ruby借用了不少東西去作了不少正確的事。有改進的餘地嗎?固然。但比起其餘一些選擇在這兒或那兒的包升級來講,我尚未感到使用NuGet有這許多痛楚。編程

Mono

對於Mono的開發者們,我不能不說太棒了。他們所創造的太驚奇了。沒有任何官方支持和不顧潛在的懸在他們頭上的法律問題,他們向前推動並創造了一個竟然能替代官方運行時的實現。我已經有一些運行在產品中應用程序,在Mono下運行了幾乎一年而沒有任何問題。它的產品準備好了嗎?這可能取決於你的應用程序(見下文「Mono」)。windows

CQRS 和事件溯源

能夠認爲,關於.NET最好事之一是,它是CQRS的誕生地並有相關的技術:事件溯源。就算這樣,CQRS+ES自己並無什麼很新的東西。正如Greg Young將會告訴你的,這是由一堆40年曆史原料爲咱們從新打包並改名的。對於大型代碼庫我有些很是嚴重的問題,當我5年前使用CQRS+ES的時候,它徹底釋放了個人域。CQRS+ES如今是命名模式的而且其成長是顯而易見的。這多是由於.NET已經可以和其餘的開發平臺交互共享的緣由。除了這個以外,大多數的創新是從外部來的。

 

缺點

優勢先放在一邊,讓咱們看看什麼出錯了和我爲何再也不用.NET框架。關於我最近開發平臺的遷移,最能激勵個人事是我能夠利用許多最好的部分而丟下很差的部分(以下文所說)。

Windows

正如前文所述,當面對基於網絡的服務器軟件時,Windows並非一個好的選手。在我看來,Windows的另外一個真正的大問題是傳統的Windows開發者是一般僅僅擅長於Windows,當他們離開安樂窩以後就會很快迷失,這對於Linux開發者來講卻不是問題。計算遠不止是Windows。開發者僅僅能操做單一的操做系統的一個問題是它不可避省得致使Windows的激增。換句話說,Windows生了Windows。沒辦法打破這個循環。

另外一方面,*NIX的開發者一般熟悉多操做系統(Linux,Unix,OSX,Windows等等),一個操做系統的內部工做原理,不一樣的分佈(基於Debian和基於Fedora),窗口管理器,桌面管理器,文件系統,包管理,編譯,從新編譯,從新打包,命令行「fu」等等。

個人一個心病是文件系統。NTFS並非系統惟一的文件系統,對於任何給予的任務它幾乎都不是最好的選擇。ZFS,BTRFS,ReiserFs,ext*等等,有一些很酷的特性。我也很喜歡爲了各類高速/透明的磁盤操做,能從BASH建立迴路設備或者建立RAM設備。這在Windows中不會發生—若是沒有第三方軟件的話。

在AWS雲服務中,啓動一個Windows機器要花掉足足10多分鐘。我大約15-20秒就能啓動一個簡單的Linux機器。當涉及到雲計算規模,它可以迅速擴展是很重要的,由於當擴展很重要時,10-15分鐘就像是永恆的。

Visual Studio

在我這另外一根刺,當屬Visual Studio。我須要一個大大超出預期的 IDE 去作任何開發,這個想法困擾着我。它只是如Windows同樣龐大的資源豬。我有一個內核i7 3770K 3.5GHZ的臺式機,以16GB的內存和最大4512GB的固態硬盤去編譯。它差很少刷爆了Windows體驗指數,但Windows+VS仍然很慢。(是的,ReSharper使得它更慢了,可是ReSharper對這來講是值得的。)

如今我在MacBook Pro上開發,它比起個人強大的臺式機來講只有更少的CPU馬力,但運行明顯更快,在一個短小的學習曲線以後,UX(用戶體驗)變得無限美好了。事實上,我甚至再也不用鼠標了—個人雙手一直在鍵盤或觸控板上,我能夠用手勢操做個人電腦並讓它迴應—不像在Windows。

關於VS很酷的一個事是調試器。它的查看和使用,使人難以置信得方便。每隔一段時間會在監視窗口報告錯誤的值,致使花費更多時間去調試。同時,這也是很大的負面,由於CLR默認的,多線程的世界使得我一開始就須要一個調試器。沒有調試器是一個解脫的體驗,由於它迫使你以另外一種方式編程。

VS一樣也有建立「csproj」和「sln」文件的壞毛病。我恨這些。固然,C#必須知道編譯什麼和什麼時候編譯。我理解這點。在Golang中,引用在代碼中使用了很重要的語句。若是它不是.NET中用到的工程文件,我可能使用簡單的文本編輯器編碼C#,而且對這門語言更流暢。使用git rebase操做時,這些文件也有致使合併衝突。

別讓我開始說換行符的差別。我不能相信直到今天咱們還在處理這樣的事。若是VS解決方案文件以Linux行結束符結束,經過雙擊它並不能載入該解決方案,由於VS解決方案文件分析器讀不出它來。

源代碼管理

幸運的是,我早就跳出了微軟陣營的源代碼管理(版本控制系統VSS)。我早在2000年初,在VSS無數次丟失了個人提交以後,就使用了Subversion(譯者注:Subversion是開源的版本控制系統)。以後git(譯者注:git是開源的版本控制系統,內容管理系統等)出現了,我又迷上了它。不幸的是,沒有Windows的接口—對我來講是典型的遭遇。最終有人建立了一個接口,我就用了那個而且沒有回頭。Git是一把很是鋒利的刀,但當你正確運用它的時候,它是一個強大而高效的工具。我曾經在一個小工程中用過TFS(譯者注:Team Foundation Server,工做流協做引擎),它是一個怪物—和全部來自Redmond(譯者注:美國微軟總部)的產品同樣。它感染了個人項目文件而且污染了個人源代碼目錄。真可惡。不,仍是謝謝你。給了我任意一天用命令行git…或者多是SourceTree,若是你須要從GUI獲得一點關愛。

Mono

是的,這是第二次說起Mono。正如Mono自己如此驚豔同樣。在.NET的世界,它仍然二等公民。不管何時我嘗試在Mono上運行任何重要的東西,我一般都在和漏洞做鬥爭。幸運的是,對下載代碼,查找問題,發送請求和在Linux上編譯代碼我沒有感到不舒服。可是這件事我都記不清作了多少遍了。

是的,CLR是個巨大的怪物,而且對一個非官方的應用在不一樣的操做系統都有相同的行爲,簡直是個相似於分開紅海的奇蹟。但事實是,我不得不花費如此多的時間來填補漏洞以使個人代碼可以正確運行,實在是很難爲其辯護。

Mono的特定區域也慢。也許它不是在慢在過載,但對我來講Web服務器是關鍵所在。而且它很是慢,最後,慢到了最底下—即便是微不足道的東西。我想好消息是它只能從這兒獲得更好的。我也應該說起Mono的開發者可能忘了Linux,比起我可能知道的還多,因此我不能太挑剔。

IIS

也許IIS在嘗試着爲太多的應用程序作太多的事情。它從做爲一個web服務器變爲像J2EE應用程序容器同樣的應用程序宿主。它也站在慢速這一邊。我猜若是我須要更高的性能,我應該編寫我本身的web服務器,但我真的很想只關注我應用程序的代碼。可能利用Windows事件服務器將是好的,但nginx(譯者注:一個高性能的HTTP和反向代理服務器,也是一個IMAP/POP3/SMTP代理服務器)和其餘服務器只是不喜歡在Windows中生產。

虛擬的以JVM爲基礎的實現,例如Netty(譯者注:JBOSS提供的一個java開源框架),很容易處理每秒650K+/的請求量。IIS在運行一個簡單的CLR應用程序「Hello,World!」,處理大約每秒50K的請求量時就會壅塞。(有趣的題外話,參考基準開發者經過TCP套接字建立了一個簡單的C#的web服務器,它能處理大約每秒120K的請求量。)

狹隘的心理

前些年有個運動叫作ALT.NET。該運動是所有是關於尋找咱們自身以外的更廣闊的開發社區以做爲一個總體,並匯聚不一樣的部分。有趣的是,那是StructureMap、Autofac、NuGet、ASP.NET MVC和許多其它工具的靈感來源。在傳統的.NET的圈子裏,這個運動受到了不少的不屑和鄙視。我把這看做是,做爲一個總體的社區廣泛的狹隘心理和怠惰的一個極大的例證。(的確,它們中的一些可能會消失,進而以包括Redis,MongoBD還有其它的不一樣的技術而出現。)

有這麼多很棒的方案在那裏。假定微軟已註定是惟一正確之路的想法是荒謬的。若是是這樣的話,咱們就都還在使用Visual Studio的設計工具去拖放按鈕和連接元素到一個WebForm的界面上,咱們會設定了該按鈕而且依賴ViewState以幫助咱們與可怕的HTTP所帶來的恐懼隔開。我從個人一個部署的代碼庫中最後一個WebForm中擺脫的那一天,是個光榮的值得慶賀的日子。

誰又曾想過「網絡控制」是個好主意?很顯然我考慮過由於我喝了Kool-Aid(譯者注:卡夫公司出品的飲料,這裏意指明知是註定的或有危險的仍然去作,有負面涵義)而且徹底接受它。它狠咬了我。見過2MB的ViewState嗎?

[注:當我寫這篇文章的時候,原來的標題,「爲何我再也不用.NET」,意味着整個.NET生態系統。標題感受有點短因而我更新爲「爲何我再也不用.NET框架」。我想.NET做爲一個生態系統,包括了全部的工具,工程,平臺,組織還有不少開發者。這就是爲何有些更普遍的.NET社區的元素在個人這篇文章中受到抨擊緣由。]

性能殺手

C,Java和C#中典型的多線程範例都強烈推薦使用鎖和互斥。對於鎖來講有個隱藏的開銷:它們慢得難以忍受。使用Disruptor(JVM中的無鎖的環形緩存[譯者注:實際上就是擁有一個序號指向下一個可用元素的數組]),你能夠很容易得每秒處理20M以上的事件。在.NET中使用規定的「最佳實踐」等任何超過每秒十幾回的傳輸,都被認爲是體面又好的性能表現,在這一點上來講你僅僅須要更大/更好/更多的硬件設備。事實上,我見過第三方客戶端庫(Rabbit,Couch,Mongo等等)中鎖語句遍及整個代碼。即便在個人代碼中沒有任何的併發,默認的和首選的方法都用了鎖。

無鎖的、事件驅動的方法容許你大幅下降硬件和資金支出。大部分應用程序能夠輕易地運行在兩臺機器上,第二臺機器僅僅在冗餘和失效備援時是必須的,以防由於硬件相關的問題致使第一臺機器不可用的時候起做用。

這個問題的另外一個方面是調用網絡和磁盤子系統的傳統方式:同步,阻塞代碼。若是你須要多個併發的HTTP請求,你須要更多的線程。大多數人不知道的是,爲維持線程多出的1-2MB和上下文切換線程的需求,使得CPU內核消耗全部的時間顛簸在上下文切換上而不是作真正的工做。因此如今咱們獲得了在一個應用程序中數百或數千的線程,佔用了RAM,並形成CPU停滯不前。還有個更好的方式。

Netty/NIO (JVM),Erlang,Node,Gevent (Python)和Go都支持使用事件驅動的子系統操做(選擇/epoll[譯者注:Linux內核中的一種可擴展IO事件處理機制]/kqueue[譯者注:FreeBSD的可擴展的事件通知接口])。這就意味着當等待數據包被tx/rx跨網絡的時候,CPU能夠自由地去作其它,重要的工做。由於JVM的成熟,Netty能夠認爲是作這項工做最快的,但我喜歡Go用Goroutines操做這個的方式—它簡單,優雅,很容易推理,沒有像意大利麪條同樣的回調。

SQL Server

做爲一名.NET開發者,當你開始一個新的工程時,有一些事是你一般會去作的:

  • 建立一個新的solution
  • 將其部署到Team Foundation Server(譯者注:Microsoft 應用程序生命週期管理 (ALM) 解決方案的核心協做平臺)
  • IIS中創建相應的網站入口
  • 建立一個新的SQL Server數據庫
  • 在solution中關聯Entity Framework(一般是2010年以後建立的工程)
  • 開始設計你的數據庫和ActiveRecord實體

在大多數狀況下這不是編寫代碼的正確方式。固然它可能在某些狀況下有效,可是做爲一個「默認的架構」它並非你想要的。爲何在咱們甚至還沒理解問題領域以前已經作了任何技術上的選擇?這簡直是本末倒置了。

微軟的生態系統鼓勵每一個人使用SQL Server。在Visual Studio中和SQL Service進行交互或者使用SQL Management Studio(和它的前身,SQL查詢分析器)是如此使人難以置信的容易。這種以數據庫爲中心的重點,是欽定的或惟一正確的方式的一部分。它使你更加迷戀微軟。廠商鎖定始終對廠商來講是好的。

爲何咱們要如此開發?爲何咱們不更多地考慮應用程序的行爲而不是它如何存儲的?如今我全部的項目都使用基於JSON的鍵/值存儲。有了這種功能,我能夠選擇任何我想要的存儲引擎,包括SQL Server,Oracle,PostgreSQL,MySQL,Cassandra, CouchDB, CouchBase, Dynamo, SimpleDB, S3, Riak, BerkeleyDB, Firebird, Hypertable, RavenDB, Redis, Tokyo Cabinet/Tyrant, Azure Blobs,文件系統中的明文JSON文件等等等等。忽然之間,咱們可以開始根據其優勢而不是僅僅對其熟悉來選擇存儲引擎了。

題外話:在AWS RDS的雲上運行過SQL Server嗎?別這麼作。固然它會工做,可是一些例如複製這樣最簡單的事是不存在的。文章充斥着對SQL Server不能在AWS RDS上工做的引用。

結論

也許我在軟件開發中學到的兩件最重要的教訓是:

  • 邊界和封裝的重要性(以多種形式)
  • 付出代價以獲得正確的模型和抽象

許多年前我恨「模型」這個詞。每一個人都會把它處處扔,它是一個如此過載的術語,很難理解它的含義和它爲何這麼重要。就這點來講,我僅僅會說模型是對你想要封裝的現實的一個有限的表示。也許最簡單的例子就是地球儀的墨卡託投影了。這很確切得說明了一件事:導航。若是你在其餘的事情上使用它,它並不毫無價值。若是你不專一於付出代價去使模型正確,去封裝商業現實,那麼沒有任何技術可以拯救你。

我對.NET最大的抱怨是,「惟一正確的方式」引導你遠離理想的模型並把你推向關注實現細節和技術缺陷的方向。這樣的關注致使技術實施滲血而且感染模型,最終致使它腐爛變質,由於它不能適應不斷變化的商業需求。當這發生的時候,開發者掙扎着並蹬踢着,如同吸毒者同樣,他們從一個新技術轉向另外一個,以指望下一個強大的技術可以治癒他們的病痛。

技術自己並非靈丹妙藥,相反地,它是關於取捨和選擇。只有正確地理解了商業行爲並把它們封裝進結構良好的,易於理解的模型中,以幫助保持技術堆棧在屬於它的地方—做爲一個實現細節。

這就是我爲何再也不用.NET 框架,由於它不斷地重申本身(的主張),不斷地想要比它的自己更多的:一個實現細節。

轉自:http://blog.jobbole.com/72987/

相關文章
相關標籤/搜索