class="First">1 引言
去年6月,“弦哥”在博客园搞了一个架构分享评奖讨论——《.Net项目分层与文件夹结构大全(最佳架子奖,吐槽奖,阴沟翻船奖揭晓)》,并在评奖完了之后,发表了一个总结——《弦哥杯.Net搭架子大赛总结》,弦哥之后还发表了另一篇文章——《对面向接口编程、按分层建项目的反思和新的分层结构思路》。这几篇文章我个人觉得非常的有益,也很有意思。软件架构已经发展多年了,多层软件设计一直是主流,在一个解决方案中搞几十个甚至上百个的项目也不是少数,特别是企业级应用,弦哥的文章给了大家关于架构的分享与交流。在我说的第二篇文章,“弦哥”语言风格堪称“很黄很暴力”,幽默犀利,甚至讽刺起人来都不带脏,显得特有文化,由此也可以看出技术男都很有才且很多是“闷骚型”的,我没有多少文化,不过,我也觉得我也是有点“闷骚”的。对于“总结”这篇文章,我老是忍不住要去对个位,好像“弦哥”的“粗”与“插”、“道”总和我本人——“道法自然”所推崇的“插件化”开发方法有所关联。不过,我这里不想去反驳弦哥在这片文章的描述,主要是我实在干不过弦哥,哈哈。在这里,我想接着弦哥提出的很好的话题进行延展,谈一谈弦哥的总结及其结论依据和我的观点。
2 弦哥语录及其点评的获奖架子
=================以下言论抄自弦哥,产权属于弦哥本人======================
(1)最佳架子奖: 圣殿骑士!!!
评选理由:
老油条了,没啥好说的....分层的描述很准确。
特别是WebModel(ViewModel)的理解和描述很到位,避免了搞ViewModel的设计过渡之嫌,如果你有设计ViewModel的话....
可惜缺乏对数据访问层的描述,不知道会不会阴沟里翻船...
(2)阴沟翻船奖 Artech
弦哥点评:Artech算是园子里的大佬,貌似还出了书,不过发的这个架子有点出乎我意料,存在有一些值得商榷的问题:
1.从架子中的命名和大体结构明显看出是走的DDD,在DDD中数据访问的具体实现(就是夹子里的DataAccess)应该是放在基础设施层(就是夹子里的Infrastructure),而Artech却貌似只把Infrastructure作为了"非功能性需求"的Framework去用。并把Infrastructure叫“非业务模块”,显得有些外行....
2.Products.BusinessComponent业务逻辑层 直接引用了Products.DataAccess,这也是个严重的问题,如果DataAccess是没有接口的,那么业务逻辑层依赖数据访问层,在DDD和马丁大叔的企业架构设计中,是一个反模式!!!,如果DataAccess里有接口,那么,DataAccess的接口应该是放在业务逻辑层的,然后通过依赖反转去用,而DataAccess的具体实现是放在Infrastructure里的。
3.如果没有用WCF,那么我认可可以省略掉DTO,但架子里上的WCF,还把DTO和PO合二为一,这个我非常不赞同。
4.Products层和Products.BusinessComponent层边界不清晰,按Artech描述 ,两个层里都可以放业务逻辑,但描述的模棱两块。而且基本可以看出Products.BusinessEntity又还是失血模型,这个设计完全让人摸不着头脑。Products层我猜是有点DDD中Application层的意思,但Artech明显做的不对。
总之我感觉这个架子,装的成分比较大,思路十分不清晰,命名很不规范,有失水准。
=================以上言论抄自弦哥,产权属于弦哥本人======================
弦哥的评奖结果,我个人很认可,这两位技术大佬大家都很熟悉,要是不知道这两位老大,我觉得都不好意思在博客园里面混了。他们的架构都是典型的分层体系结构,他们的架构代表了博客园技术界的顶尖水平(没见老赵的分享,我觉得很是遗憾,老赵也是顶尖的技术闷骚男了)。从名字看,这两个架子好像都是电子商务相关的项目,一个是“HP”商店,另一个是Video商店,看来“电商”这么火爆是很有道理的。我想这样的项目也必然是一个团队来开发的,不同的人负责不同的功能模块。
后面,弦哥也写了一篇总结,这篇总结很好看,“很黄很暴力”,弦哥的文化水平之高与之闷骚可见一斑。下面我抄一些弦哥的原话。
=================以下言论抄自弦哥,产权属于弦哥本人======================
……
复杂的东西是没有人会喜欢的,这也是理,但不能一概而论 。就像“大道至简”,也有很多人爱BB,而且BB的很爽,四字一出道袍都TM飘起来了...我们拿国学和西学的对比来说明这个问题:
……
有时候太简单意味着太粗,看上去很好,但很多复杂场景你根本没考虑,全在理想状态下活着。细节决定成败,细节很繁琐很讨厌,但你无法屏蔽,你也无法给别人屏蔽....还真TM当自己是道长咋地~?
……
“粗”和“插”都是男人喜欢的两个字眼,但真的万金油吗?近些年基于SOA的粗粒度服务思想和面向构件、插件的开发平台在大厂商的摇旗呐喊中大行其道。国内有些农民科学家见状也按耐不住,纷纷山寨,甚至披上国学的外衣装神弄鬼。简单的“插”不是不好,但要看情况,比如娇小的日本妞,基本问题不大,但电信、银行、医疗这些大行业系统就如俄罗斯姑娘,你那玩意儿就是牙签搅水桶,能好使吗?
=================以上言论抄自弦哥,产权属于弦哥本人======================
弦哥原文更精彩,一定要拜读!!!在这里,咱们先来看看两位大佬的架构。
3 从分层引出我推崇的”插件化架构观“
博客园这两位技术大佬圣殿骑士与Artech采用的分层有点类似,甚至构建了一些接口,用于层间解耦。在这种分层架构下,假设我们要实现3个功能,那么这三个功能的实现会在上面的不同项目中由不同的代码来提供。正如我在《白话插件框架原理》描述的一样,这三个功能至少横跨了表示层、业务层、数据层等层次,这些层次都由不同的项目来实现。
下面看看PetShop的Product功能的实现,Petshop的架构如下图所示,由很多项目组成,各个层次使用至少一个项目来组织代码。
其中Product功能在Web、BLL、DALFactory、OracleDAL等项目中含有各个层次实现的代码。
这种基于分层的架构设计,已经是架构的一大进步,但是会有什么问题呢?我们设想一下,假设这样的项目是由多个人来开发的那么:
(1)团队里面所有的人,都要下载到这样的代码,你开发一个功能的时候,需要先学习,然后根据架构师知道,跨越不同的项目添加这个功能需要的界面、业务逻辑、数据访问等代码,当然,还有相应的接口;
(2)团队不同成员开发完成后,都需要提交相应的代码,然后大家一起将所作的功能集成起来,这个集成可能会从头做最后;
(3)实现一个简单的功能,也必须遵循这样的架构,从界面、业务逻辑、数据访问等,甚至接口 + 实现层次,没有伸缩性;
(4)不同成员的代码可能交织在一起,出了问题甚至还不知道到底是谁干的;
(5)有一部分层次,可能存在每一个人都会修改同一个文件的代码,比如主界面,这时候代码的集成、版本控制、合并就更加麻烦了;
(6)如果让一个新人来开发功能,你有没有觉得入门很难,感觉整个解决方案很复杂?
(7)后期维护呢,你怎么知道层间这些代码的依赖关系,你更改了会影响到其它功能,其它层次吗?
(8)当我们只需要开发一个功能的时候,为什么需要下载所有的代码?为什么每个人都有所有代码的访问权限?
(9)如果一个功能在每一个层间,考虑了解耦,还大量使用了接口,这对调试、代码定位,不更麻烦了吗?(这点,弦哥在后面的一片文章也描述到了:《对面向接口编程、按分层建项目的反思和新的分层结构思路》)。
以上这些问题,估计弦哥也发现了,他在后面也特意发表了这篇文章《对面向接口编程、按分层建项目的反思和新的分层结构思路》,我对里面所描述的思路非常的赞同。弦哥考虑以后一个模块就一个文件夹,里面包含这个模块所有的东西(FYI:我所提倡的插件化其实与之非常吻合,:),如果你用OSGi.NET插件框架开发MVC应用,那将与以下的解决方案几乎类似了,甚至更简洁),另外,也不整那么多的接口,因为没有意义。
弦哥对自己新架构的评价如下:
“整个视野非常干净,你可以集中精力干你自己的事了!
接下来我们看看新框架整体的结构,只有三个项目!!!”
好了,下面我想来谈谈我的“插件化架构观“。
上面我已经提到了分层及其存在的一些问题,这样的问题随着项目越发复杂,其问题就越发明显。我本人从2006年开始就在思索,对于一个稍微大点、负责的项目,该如何更好的把一帮人协作起来,让他们来一起又快又简单的实现一个项目。2006年我们有一个项目,9个人来参与,需要干1年,从需求分析到功能实现、测试与维护,把这么多人组织起来用这么长的时间,有什么好方法?如果用传统的分层,那就需要把所有人的工作都混在一起,我非常厌倦这种不同的人将代码写在一块,需要不停整合不停交付,不停交付,不停测试,对我来说,一想到后面这种协作方式,我烦透了!
我觉得更好的方法是,每一个人都可以只关注直接的功能实现,每一个人都可以独立的来进行开发,每一个人可以采用更合适的架构,每一个人都可以保持简单!!也就是说,如果有一套方法,使得每一个人可以直接切入到自己需要实现的需求,那么这可能是最简单省事的,他不用关心界面、不用关心其他人开发方式、不用关心通用功能、不用管集成、不用遵循一堆接口,在我的功能里面,怎么简单就怎么来,N层?不,如果简单的话,我用一层就实现,不行就两层、三层,什么面向接口、什么IoC,通通说不,因为没有必要,在这个功能实现里面,不需要考虑太多扩展,不需要考虑太多复用,一切按照需要的来做,不用遵守一堆的约束。总而言之,我对现有的方式已经烦透了,因为我特别懒,我就想简单快速的实现,然后能快快的涨工资,快快的拿到项目奖金!!
下面,我们来看一下,如果使用插件化以后,假设还是实现3个功能,那么此时,整个系统就变成由一对插件组成的应用了。
每一个插件均独立实现,它在自己的插件项目里面实现了界面、业务逻辑和数据访问,在开发测试过程中,只需要自己的项目。可以根据需要来进行分层,视角就非常的清晰了。
如果组织得更好,不同的插件可以放到不同的解决方案中,比如如下解决方案是由程序猿A开发的功能。
如下解决方案是由程序猿B开发的功能。
这两个程序猿开发完成后,可以直接组装在一起就变成如下的软件了。
4 插件化与分层的简单对比
从上面的文字,估计你已经能够知道二者的区别了,我这里简单用功能A、B、C的实现来说说二者区别:
(1)在分层,一个功能,比如功能A,在实现中,需要同时跨越多个项目;在插件化,一个功能在一个插件项目中实现,一个插件项目里面直接包含了相关的所有代码;
(2)在分层,所有人都需要下载到复杂的代码;在插件化,每一个人只需要下载自己实现的那一部分代码,非常的简单与清晰;
(3)在分层,大家的代码都放在一起,需要不停的集成;在插件化,每一个人的代码都与另一个人的代码互相隔离,互不相干;
(4)在分层,每次发布都需要进行合并集成,可能需要更改代码;在插件化,集成几乎可以在几秒内完成,大家独立开发、测试、发布,只需要将每一个人发布的项目拷贝到插件目录就集成好了;
(5)在分层,每一个人都需要遵循层次划分方法,不管功能简单与复杂,都需要整那么多的层次;在插件化,每一个功能可以按照复杂度来处理,什么N层、面向接口、IoC,我们可以说不,可以用1层、2层或者3层。
从这些文字你可以看出了,插件化拥有很强的吸引力,但是,为什么我们很难在实际项目中来使用插件化呢?下面,我想针对这个问题做个描述——那就是关于插件化的误区。
5 插件化误用及我认为理想的插件化框架
使我们开发协作过程保持简单是我不停的思索更好方法来协作开发的原因。插件化(或者模块化)的架构是目前最好的选择了。不过,一开始,我是自己根据自己的理论来设计插件框架的,当自己设计插件框架的时候,我总是逃脱不了传统的插件化方法,那就是整个插件接口,插件实现就必须使用这个接口,如果有什么很多功能是,甚至这个接口需要不停改变,这是插件也需要不停的适应。这种拥有过多约束的插件化框架在一定程度改善了分层架构的缺陷,但是却带来了下面的问题:(1)接口的定义影响系统的适应性;(2)插件框架带来了额外的约束,使得其他人在开发时需要不停与插件框架API打交道。这让其他人痛苦不堪。我想,关于插件化的方法,很多人也估计有碰到这样的问题,并且深有同感。
那么,有什么更好的方法可以既改善分层的缺陷,又能避免上述”插件化“问题吗?我的观点是,插件化思想是很好的架构,如果你使用插件化并碰到上述的两个问题,那么一定是误用了插件化了。下面我来介绍一下插件化的误用及我的插件化架构思想。
纵观目前国内外,好像在.NET界还很少有成熟的插件框架解决方案(当然,我们的OSGi.NET插件框架除外,这框架是完全免费开放的,商用也不限制,只是苦于我们现在需要挣钱,暂时无法完全开源,请谅解,:),需要的同学可以从 http://www.iopenworks.com/ 这个网站下载)。很多人也特别痛恨各类框架,这些框架并没有很好的解决我们面临的问题,却带来更多的约束、学习成本和维护成本。这让我们对框架有很多负面的想法,特别当我们只是一个小程序员时,我们更关注的是如何快速来实现功能,我们可能理解不了框架设计者和架构师的所谓框架。传统的插件框架都基本摆脱不了以下的”行规“,因为很多书本和理论也是这么写的,这些”行规“突出了:
(1)插件框架是高深的技术,比如”热插拔“,这种观点强调的是技术本身,这项技术有多么先进,有多么强的可扩展性等;
(2)插件框架基本都与一些界面绑定起来,要使用插件框架就需要学习如何使用界面,要接受这套界面风格样式,当然这也为插件框架的复杂性带来了影响,使设计插件框架时需要来考虑各种各样的界面;
(3)插件框架本身实现了一堆功能,通过API说明书,来学会使用它们,并进行调用;
(4)插件框架在开发维护过程中,由于带来了很强的侵略性,使我们的插件需要严重依赖于框架本身,这既带来了复杂性,也随着插件框架的不稳定性带来更多负面的影响;
(5)插件框架设计的合理与否,关系到其他人是否可以接受并使用。
现在,我们再来看看那弦哥提出的”粗“与”插“的观点,可能也是由这些问题引起的,我们再来回顾一下弦哥精彩言论。
=================以下言论抄自弦哥,产权属于弦哥本人======================
“粗”和“插”都是男人喜欢的两个字眼,但真的万金油吗?近些年基于SOA的粗粒度服务思想和面向构件、插件的开发平台在大厂商的摇旗呐喊中大行其道。国内有些农民科学家见状也按耐不住,纷纷山寨,甚至披上国学的外衣装神弄鬼。简单的“插”不是不好,但要看情况,比如娇小的日本妞,基本问题不大,但电信、银行、医疗这些大行业系统就如俄罗斯姑娘,你那玩意儿就是牙签搅水桶,能好使吗?
=================以上言论抄自弦哥,产权属于弦哥本人======================
起初我很难理解为什么弦哥会觉得电信、医疗等大行业系统,采用插件化无法满足,并觉得”插“太细了,这些”大姑娘“没有办法被很好的满足。因为,从我的角度,插件化(或者模块化)最初就是在复杂领域中应用的,你看主流的IDE(Eclipse使用OSGi插件化规范构建、Visual Studio使用MAF/MEF框架构建、SharpDevelop使用SD内核、MonoDevelop使用Mono.Addins插件内核)等很多复杂软件,基本都是使用插件化构建的,我真不认为插件化无法满足这些行业”大姑娘“。看来,阻碍我们接受插件化架构方法,是因为传统的”行规“引起的,我们学习到的”插件化“太过于强调技术本身,并且设计的初衷可能是为了追求”热插拔很酷“这一说,从而让弦哥和咱们这样的码农的厌烦。
那么,谈到这,我不得不描述一下我的插件化观。
(1)插件化不是复杂高深的技术,不是为了强调技术先进性,要解决的是如何实现隔离的模块化开发,使每一个人都独立、简单、并行;
(2)插件化必须要保持简单,我们只是想获取到模块化的优势,不是为了整个什么高深的技术,因此,需要很快的就学会如何来开发;
(3)插件化必须没有侵入性,开发插件时,我们不需要与插件框架打交道,不需要了解插件框架的技术原理和细节,不需要掌握插件框架API,我们可以使用传统的开发方式来快快的开发一个插件,实现我们的功能;
(4)插件框架不应该与界面绑定一起,也就是说,插件框架内核必须保持简单,只需要提供插件的隔离与组装、插件通讯和扩展,不应该附带实现一个界面。插件框架附带界面实现,是传统的方法,但是这也给我们带来了强制的约束,是我们在开发设计中都必须遵循,很烦;
(5)插件框架可以适用任何应用,这样,我们可以在所有的应用类型中使用统一的规范,减少成本。
如果用简单的一句话,我想说的是理想的插件化框架应该使我们少加班多挣钱,稍微技术一点的说法应该是:
插件框架只是实现了我们要的模块化思想,解决了分层架构下的团队协作缺陷,使每一个功能的实现更加的独立,但不要附带任何约束。凡是过多约束的插件框架都不会被我们这帮懒惰的程序猿接受。
本文就到此结束了,希望大家能够热烈的参与架构讨论,分享自己的架构心得、对插件化架构的考虑,后面可以请弦哥再用很犀利的语言为我们评奖,当然,我也建议弦哥再举办一次这样的大赛。这样在博客园Dudu的带领下,我们可以早日有一个更加优越的方法,使得我们能够成为真正的IT白领,能够真正进入”嫁人就嫁程序猿“的理想社会,实现”程序猿崛起“!:)
附:插件化应用系统分享。
我们来看一下一个插件化应用系统,这是一个大型公建能耗采集分析平台。
系统架构如下所示,这是一个分布式系统。
Web分析平台项目结构如下所示,共16个插件,9个是新定义,其余为复用,另外新定义的数据模型插件在其它程序中共享。这里有7个应用插件,每一个插件都独立实现一部分功能,由不同的开发人员来独立实现,开发中不需要关心界面、数据库访问、权限等通用功能,这些由历史项目积累下来,直接重用。
GPRS通讯服务器项目如下所示,12个插件,2个是新定义,其余为复用;数据模型等插件与Web平台共享。
配置管理工具项目如下所示。11个插件,2个是新定义,其余为复用;数据模型等插件与Web平台共享。
数据上报与接收系统项目如下所示。5个插件,1个是新定义,其余为复用;数据模型等插件与Web平台共享。
系统使用插件仓库来实现插件发布、管理、复用、组装、升级。
开发过程中,实现了“DevOps”。
集成测试部署时,只需要简单通过下载安装或者直接下载升级即可。
下载安装组装后,就是如下的效果了,它很快就实现两个开发人员功能的集成了。
应用插件化开发成果如下:
•通过大量复用减少开发成本超过50%
•由4个程序构成,由5个人开发,历时1.5个月,已完成工作量超过70%
•系统间有大量可复用插件
•稳定集成与发布
•开发习惯一致,井井有条