.NET平台很棒。真的很好。直到它不再那么棒了。为什么我不再使用.NET?简单地说,它限制了我们选择的能力(对我来说很重要),转移了我们对内在安全性的注意力,并取代了所有帮助我们认识性之外更广阔世界的可能性。[系好安全带:这篇文章几乎是一本书的篇幅...]优点让我先说说.NET做对的许多事情,其中??大部分不是来自.NET本身,而是来自.NET社区。C#C#很棒。我认为这是一种了不起的编程语言。来自强大的C背景,我非常喜欢这种语言的语法、流程和感觉。当然有些东西我可以改变,但总的来说它是一种可靠的语言。并且基于开发者使用的编程语言如此巨大的比例以及Windows操作系统的优越性,它是一种众所周知的语言。ReSharper我也非常喜欢Resharper。在JetBrains工作的开发人员都是神奇的人。如果不是ReSharper和一些相关工具,我可能不会那么喜欢C#。BDD和MSpec我也非常喜欢BDD风格的框架,简称为MachineSpecification(mspec)。这是一个了不起的测试框架,真正支持在测试本身中使用正确的语言。在使用mspec之前,我的测试一团糟,妨碍了我。此外,当我们创建GoConvey(一个基于Golang的BDD测试框架)时,Mspec对我的组织来说是一个巨大的灵感和动力。多语言运行时我认为多语言CLR(公共语言运行时)的想法确实让JVM世界思考。我不知道在CLR之前有任何非JavaJVM语言,但随着“公共语言运行时”的出现,我的理解是这推动了使用JVM的人们向前发展并最终创造了伟大的JVM编程,如Scala和Clojure语言。如果我错了,请纠正我。此外,CLR让Sun的人重新审视它,因为Java有点老了,随着Java8的到来,它现在才在很多方面迎头赶上。竞争是一件非常好的事情。另一个著名的NuGet示例是NuGet。在整个Windows中,尤其是在Windows开发中,这个包的管理轶事很糟糕。NuGet解决了很多问题,他们通过大量借鉴Python和Ruby做对了很多事情。有改进的余地吗?当然。但我并没有像使用NuGet时那样感到像其他一些包升级选项那样痛苦。Mono对于Mono的开发者来说,我不能说太多。他们创造的东西真是太神奇了。在没有任何官方支持的情况下,也不管潜在的法律问题悬在他们头上,他们继续前进并创建了一个实际取代官方运行时的实现。我有一些在生产环境中运行的应用程序已经在Mono下运行了将近一年而没有任何问题。它的产品准备好了吗?这可能取决于您的应用程序(请参阅下面的“Mono”)。CQRS和事件溯源可以说,.NET最好的地方之一是它是CQRS和相关技术的发源地:事件溯源。即便如此,CQRS+ES本身并没有什么新意。正如GregYoung会告诉您的那样,这是一堆为我们重新包装和重新命名的40年历史的原料。我在大型代码库方面遇到了一些非常严重的问题,当我5年前使用CQRS+ES时,它完全释放了我的域。CQRS+ES现在被命名为schema,它的增长是显而易见的。这可能是因为.NET已经能够与其他开发平台交互。除此之外,大多数创新都来自外部。撇开缺点不谈,让我们看看出了什么问题,以及为什么我不再使用.NET框架。关于我最近的开发平台迁移,最激励我的是我能够利用许多最好的部分并留下不好的部分(如下所述)。Windows如前所述,在基于Web的服务器软件方面,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分钟感觉就像是永恒。VisualStudio的另一个眼中钉是VisualStudio。我需要一个远远超出我预期的IDE来进行任何类型的开发,这一想法困扰着我。它只是像Windows一样的巨大资源消耗。我有一个带有核心i73770K3.5GHZ的台式机,配备16GB内存和最大4512GBSSD。几乎刷爆了Windows体验指数,但Windows+VS还是很慢。(是的,ReSharper让它变慢了,但ReSharper是值得的。)现在我在MacBookPro上开发,它的CPU马力比我强大的台式机低,但运行速度明显更快,经过短暂的学习曲线后,UX(用户体验)无限好。事实上,我什至不再使用鼠标——我的手总是放在键盘或触控板上,我可以使用手势来操作我的电脑并让它做出响应——这与在Windows中不同。关于VS的一个很酷的事情是调试器。它非常容易查看和使用。每隔一段时间就会在监视窗口中报告不正确的值,导致调试花费更多时间。同时,这也是一个很大的负面影响,因为CLR默认的多线程世界让我首先需要一个调试器。没有调试器是一种自由的体验,因为它迫使你以另一种方式编程。VS也有创建“csproj”和“sln”文件的坏习惯。我讨厌这些。当然,C#必须知道编译什么,什么时候编译。我明白这一点。在Golang中,引用是代码中非常重要的语句。如果它不是在.NET中使用的项目文件,我可能会使用简单的文本编辑器来编写C#代码并且更流利地使用该语言。这些文件在使用gitrebase操作时也会导致合并冲突。不要让我开始了解换行符的区别。我无法相信直到今天我们还在处理这样的事情。如果VS解决方案文件以Linux行结尾结尾,双击它不会加载解决方案,因为VS解决方案文件解析器无法读取它。SourceControl幸运的是,我早就跳出微软的sourcecontrol(版本控制系统VSS)阵营了。在VSS多次丢失我的提交后,我在2000年初使用了Subversion。然后git(译者注:git是一个开源的版本控制系统、内容管理系统等)出现了,我又迷上了它。不幸的是,没有Windows界面——这是我的典型遭遇。最终有人创建了一个界面,我使用了它并且没有回头。Git是一把非常锋利的刀,但是当你正确使用它时,它是一个强大而高效的工具。我曾经在一个小项目中使用过TFS(译者注:TeamFoundationServer,工作流协作引擎),它是一个怪物——就像Redmond(译者注:美国微软总部)的所有产品一样。它感染了我的项目文件并污染了我的源代码目录。可恶。不,还是谢谢你。任何一天给我命令行git...或者如果你需要来自GUI的一点爱,也许是SourceTree。Mono是的,这是第二次提到Mono。和Mono本身一样神奇。在.NET世界中,它仍然是二等公民。每当我尝试在Mono上运行任何重要的东西时,我通常都在与错误作斗争。幸运的是,我在Linux下载代码、发现问题、发送拉取请求和编译代码时并没有感到不自在。但我不记得我这样做了多少次。是的,CLR是一个巨大的怪物,对于一个非官方的应用程序来说,在不同的操作系统上具有相同的行为是一个分开红海的奇迹。但事实是,很难证明必须花费这么多时间来填补漏洞才能让我的代码正常工作。Mono的某些区域也很慢。也许它并不慢或超载,但对我来说网络服务器是关键。最终,它非常缓慢地到达底部-即使是微不足道的事情。我想好消息是它只能从这里变得更好。我还应该提到,Mono开发人员对Linux的遗忘可能比我所知道的要多,所以我不能太挑剔。IIS也许IIS正试图为太多的应用程序做太多的事情。它从一个Web服务器变成了一个像J2EE应用程序容器这样的应用程序主机。它也处于缓慢的一面。我想如果我需要更多的性能我应该写我自己的网络服务器,但我真的很想只专注于我的应用程序的代码。可能利用WindowsEventServer就可以了,但是nginx(译者注:一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器)和其他人就是不喜欢在Windows中生产。基于虚拟JVM的实现,比如Netty(译者注:JBOSS提供的java开源框架),可以轻松处理650K+/秒的请求。IIS在运行一个简单的CLR应用程序“Hello,World!”时令人窒息。它每秒处理大约50K个请求。(作为一个有趣的题外话,基准测试开发人员通过TCP套接字创建了一个简单的C#Web服务器,每秒可以处理大约120K个请求。)#p#Narrowpsychology几年前有一个名为ALT.NET的运动。该运动的全部目的是在整个我们自己之外寻找更广泛的开发社区,并将不同的部分聚集在一起。有趣的是,这是StructureMap、Autofac、NuGet、ASP.NETMVC和许多其他项目的灵感来源。在传统的.NET圈子里,这场运动受到了很多蔑视和蔑视。我认为这是整个社区普遍狭隘和懒惰的一个很好的例子。(事实上??,其中一些可能会消失并随着不同的技术弹出,包括Redis、MongoBD和其他技术。)有很多很棒的解决方案。认为微软注定是唯一正确的道路是荒谬的。如果是这样,我们仍在使用VisualStudio的设计工具将按钮和链接元素拖放到WebForm界面上,我们将设置按钮并依靠ViewState来帮助我们解决可怕的HTTP恐惧分离。在我部署的一个代码库中摆脱最后一个WebForm的那一天是值得庆祝的光荣日子。谁曾认为“网络控制”是个好主意?显然是因为喝了Kool-Aid(译者注:卡夫公司出品的一种饮料,这里是指知道不管怎样都是命中注定或危险的,带有负面的含义)而想的,完全接受了。它狠狠地咬了我一下。见过2MB的ViewState吗?[注:当我写这篇文章时,原标题“为什么我不再使用.NET”指的是整个.NET生态系统。标题感觉有点短,所以我将其更新为“为什么我不再使用.NETFramework”。我认为.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处理这个问题的方式——它简单、优雅、易于推理,没有意大利面条状的回调。SQLServer作为.NET开发人员,当您开始一个新项目时,通常会做一些事情:创建一个新的解决方案并将其部署到TeamFoundationServer(译者注:MicrosoftApplication生命周期管理(ALM)的核心协作平台)解决方案)在IIS中创建相应的网站门户创建一个新的SQLServer数据库在解决方案中关联EntityFramework(通常是2010年之后创建的项目)开始设计你的数据库和ActiveRecordEntities大多数情况下这不是正确的写代码方式.当然,它在某些情况下可能会起作用,但作为“默认架构”,它并不是您想要的。为什么在我们了解问题域之前就做出了任何技术选择?这简直是??本末倒置。Microsoft生态系统鼓励每个人都使用SQLServer。在VisualStudio中与SQL服务交互或使用SQLManagementStudio(及其前身SQL查询分析器)非常容易。这种以数据库为中心的关注是唯一或唯一正确方法的一部分。它让你更加迷恋微软。供应商锁定总是对供应商有利。为什么我们会这样发展?为什么我们不更多地考虑应用程序的行为方式而不是它的存储方式?现在我所有的项目都使用基于JSON的键/值存储。有了这种功能,我可以选择任何我想要的存储引擎,包括SQLServer、Oracle、PostgreSQL、MySQL、Cassandra、CouchDB、CouchBase、Dynamo、SimpleDB、S3、Riak、BerkeleyDB、Firebird、Hypertable、RavenDB、Redis、TokyoCabinet/Tyrant、AzureBlob、文件系统中的明文JSON文件等。突然间,我们能够开始根据其优点而不是仅仅根据其熟悉程度来选择存储引擎。题外话:曾经在AWSRDS云上运行过SQLServer吗?不要这样做。当然它会起作用,但是像复制这样简单的东西是不存在的。文章中充斥着对无法在AWSRDS上运行的SQLServer的引用。结论也许我在软件开发中学到的两个最重要的教训是:边界和封装(以多种形式)的重要性为获得正确的模型和抽象付出代价许多年前我讨厌“模型”这个词。每个人都把它扔来扔去,这是一个超载的术语,很难理解它的含义和重要性。在这一点上,我只想说模型是您想要封装的现实的有限表示。也许最简单的例子是地球的墨卡托投影。这确实说明了一件事:导航。拿来做别的,也不是一文不值。如果您不专注于为使模型正确、封装业务现实而付出代价,那么任何技术都无法拯救您。我对.NET最大的抱怨是,“唯一正确的方法”会让您远离理想模型,并将您推向实现细节和技术缺陷。这种关注导致技术实施流血并感染模型,最终导致模型腐烂,因为它无法适应不断变化的业务需求。当这种情况发生时,开发人员像吸毒者一样挣扎和踢,他们从一种新技术转向另一种新技术,希望下一个强大的技术能够治愈他们的疾病。技术本身不是万能的,而是权衡和选择。只有正确理解业务行为并将它们封装到结构良好、易于理解的模型中,才能帮助将技术堆栈保持在其所属的位置——作为实施细节。这就是我离开.NETFramework的原因,因为它不断重申自己并希望超越它:一个实现细节。地面需要的不仅仅是它自己:一个实现细节。原文链接:JonathanOliver翻译:伯乐在线-EluQ翻译链接:http://blog.jobbole.com/72987/
