论坛首页 Java企业应用论坛

解决侵入的根本方法讨论

浏览 16245 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-12-16  

 

最近又看到一些关于框架侵入性的讨论, 有些想法, 谨此抛砖引玉.

我觉得软件开发框架之所以跟侵入性纠缠不清, 根本的原因还是框架要支持应用的某种/某些逻辑和功能, 可以说是部分的去实现应用的目标. 但是这些功能如果不能让应用去定制, 其现实应用代价就又很微渺了. 所以框架是需要和应用交流的, 而交流的主要目的是为了定制.

想到这个地方, 我的反应是声明式编程, 让应用通过某种方式表达出自己的定制需求, 这个表达的方式就可以是多种多样的了: 通过遵循约定, 继承特定框架基类, 实现特定框架接口, 标注Annotation, 编写配置文件, 调用框架API, 等等.

而像Java这样的静态语言所能支持的表达方式, 无论怎么看都可以挂上 "侵入性" 的标签, 因为如果框架一旦定了它要求应用采纳的方式, 应用就得跟着它走. 在应用需求表达方式问题上, 框架之间的相容性既没有理论研究, 更没有实践习惯.

这里提到 "框架的侵入性" 好像用的是它最宽泛的涵义, 就是对应用编程行为的影响. 要是这么说任何框架都不可能没有侵入性了, 只是有些让应用开发人员的日子很难过, 有些则好一点. 不过以目前的软件体系局势来看, 绝对的 "侵入性" 问题还没有办法解决, 更现实一点, 似乎只有它对单元化开发和测试的影响比较有可能解决, 眼下讨论才比较有现实意义.

不过对下一代软件框架体系, 我倒是感到有些期望, 随着Annotation的成熟和普及, 对于基于Java的开发来说, 我觉得这个趋势已经临近了. 我的想法是可以运用一下逆向思维, 既然应用与框架的交互无可避免, 那么与其被动的接受框架的 "侵入" 不如由应用自身采取主动行为, 进行 "引入".

应用的主动引入可以从已有的 声明式编程 出发, 对于比较大的综合应用方向, 比如 Web应用, 以制定通用的应用需求表达规范为手段, 通过公开的规范, 协调应用程序和系统框架之间的交流. 这听起来就是JCP要为JavaEE做的事情, 是的, 以截至到目前的软件体系局势, 这个事情还不得不由人力, 物力, 财力丰厚的商业实体去完成, 它们也必须在这个领域有足够的商业利益吸引也才有动力去做.

但是同样是JCP出来的J2EE规范, Servlet很成功, 而EJB却不是. 并且Servlet很好的解决了它那个年代的Web开发问题, 而软硬件的发展所推动出来的新需求, 新问题又飞快增长, 对新规范的需求不仅是本身增长很快, 它的增长速度也会随着时间增长. JCP已经开始显得笨拙且乏力了.

一个本质性的问题是: 目前的规范是基于少量编程语言API的大部分的自然语言描述. 基于这样的模式, 成本太高, 就算是目前的大型开源社区要开发自己的体系规范也会是难上加难.

在这个方向上, DSL(Domain Specific Language)是个很好的创意, 可以有针对性的简化专门领域的规约方式. 不过, 我觉得还有DSL没有特别关注的一点, 就是同一种语言中声明与实现语法的分离与融汇:
  DSL倾向于作为一种声明式的语言, 被设计为独立使用, 它很可能由另一种通用语言进行解释而实现. 它的语法很可能可以直接调用实现语言, 但很难变成编写应用所用语言的一部分. (我很期望它变成应用代码的声明部分)

回到解决侵入性的问题上来, 我设想的方式是目前还没有的, 至少还没有系统化. 那就是可以用一种语法给应用编程语言增加用于声明的语法, 同时这种语法也照顾到给应用声明的需求提供实现的系统编程语言语法, 从而这样的语法可以同时 表达/约束/支持 应用声明和系统实现.

看上去动态语言在这个方向上有最深厚的长远潜力, 不过用于有分析需求的通用工业开发领域, 动态语言要走的路还有点长.

目前基于Java的开发, 利用起Annotation机制会在这个方向上有长足进展, 应用通过引用标注来声明需求, 系统在编译时通过Annotation Processor以及Language Model, 在运行时通过反射, 两者结合起来去理解和实现应用的需求. 而定义和引用Annotation都受到新增的Java语法约束.
不过基于Annotation机制的 应用/系统 交流有时候还是需要一些自然语言描述的规范, 好在这个已经比纯粹描述/理解大篇的约定和接口调用逻辑顺序简易多了. 同时Annotation引用只能放在modifier的位置还是一个过大的约束, 这个还需要Java语言进一步的演进去解决.

总结下来, 系统框架通过 "侵入" 要达到的 应用定制 目的是不可避免的, 而要解决被动的受到 "侵入" 的局面, 我所能想到的最好方法就是去主动 "引入". 而 "引入" 所能达到的 "主动" 程度取决于其方式方法的灵活程度和负面影响大小. 当应用的特定需求可以通过统一的(声明)方式利用大多不同系统(包括测试时的Mock系统)而实现时, 应用的 "引入" 行为也就达到了一个比较理想的主动程度, 从而可以视为没有被特定系统 "侵入" 了.

   发表时间:2006-12-16  
变被动为主动?
0 请登录后投票
   发表时间:2006-12-17  
还是实例说话。就拿我最熟的IoC容器来说吧。


传统的avalon为什么说侵入性高?因为它要求你的组件都要实现一个接口。一个没有实现这个接口的遗留系统怎么办?对不起,没办法?

spring/pico为什么侵入性低?因为它们把这个框架和组件之间的协议从一个proprietary接口降低成一个一般来说比较约定俗成的convention:java bean或者constructor。

不是spring/pico没有侵入性,而是这种侵入性一般来说采取了群众比较喜闻乐见的形势。
问:如果我的组件没有遵循java bean规范,或者没有实现要求的constructor怎么办?
答:这是一个伪问题么?有谁会不遵循java bean或者constructor呢?

统计上的优势(大量的人和应用都事实上遵循了java bean规范)掩盖了侵入性,或者说这个侵入性无足轻重了。这就叫convention over configuration吧。

然后annotation的引入也没有彻底解决侵入性。它解决的是delcarative programming这一部分。语法漂亮了。但是你还是要引入框架要求的annotation类型。

真正的无侵入性,在我看来,是框架对组件完全没有任何要求(不妨碍框架应用convention over configuration,缺省情况仍然假设组件遵循java bean规范)。比如说,你的组件没实现setService1(),而是initService1()。框架当然不可能预见到这点。但是你可以告诉框架亚:
框架.registerComponent(MyComponent.class, "请用initService1()来设置service1的依赖")


这里用的是自然语言来和框架交互。事实上框架当然不会这么聪明,肯定是要用某种框架理解的api来和框架交互。但是基本的意思就是这样,对MyComponent完全无侵入。

其实,这和用xml配置文件来配置没有本质区别。于是,又回到了原始的“xml配置也是侵入”,“框架理解的api也是侵入”的悖论。

而且,这种配置从实际角度不见得有通过annotation侵入MyComponent来得方便。

spring对这类非标准的问题的解决方案和我提的不同。它回避了困难,放弃了“无侵入性”的目标,转而用侵入这个万应灵丹来解决问题(BeanFactoryAware等等)。可以看作一种折衷吧。


对此,我要说的有两点:
1。在组建级别的侵入和在和框架集成部分的侵入本质上是不同的。和框架集成的地方侵入是自然的。或者根本不能叫做“侵入”。叫“依赖”可能更合理些。

2。考验功夫的就是这个xml配置或者api是否很麻烦。框架的目标应该是这部分做起来很简单,而且还足够灵活。如果它足够简单(搭配上convention over configuration),花在集成部分的工作量可以忽略,那么就可以在方便性上和annotation的declarative方法媲美,而且从侵入性上又优越,那么无论理论还是实际都可以站得上风了。不幸的是,spring这点上作的不好,配置文件繁琐地让人根本不敢考虑移植问题。而acegi之类的框架又走回了框架侵入的老路。当然,这并不妨碍spring的成功。(或者甚至有所帮助?)






0 请登录后投票
   发表时间:2006-12-17  
嗯,目前的局势确实如此.

我在顶楼提了一个

  所谓 "侵入" 其最终目的是为了让应用能够 "定制" 框架给它带来的功能

这个想法, 不知道 ajoo 是什么看法?
0 请登录后投票
   发表时间:2006-12-20  
complystill 写道
嗯,目前的局势确实如此.

我在顶楼提了一个

  所谓 "侵入" 其最终目的是为了让应用能够 "定制" 框架给它带来的功能

这个想法, 不知道 ajoo 是什么看法?


我和你的看法不太一致。
一个框架到底定制能力要多强,这很难说,而且很容易陷入过渡设计或者设计不足之间的两难。
当然,通过侵入确实可以实现一些方便的定制,但是,几乎必然地,它同时也会影响一些其它的定制。只不过我们可以争辩说侵入实现的定制是有用的,而它妨碍的是你根本不需要的之类。


我对“侵入”的反感更多的是一种先验的哲学化倾向。本能地我就反感侵入。

今天看佛本,看到“圣人不死,大盗不止”。一个框架如果自以为是地说“我的侵入是为了给你提供方便性1,2,3”,在我看来这就是一种“自以为圣人”的倾向。

当然,现实中,有的“圣人”做的很失败,如ejb。而有的圣人则作得很成功,如spring,拥有大量的圣人门徒(acegi等)。

基本上,“圣人”就是说:放下你的锄头,跟我走,永远不要背叛,你就有福了。你要泡妞?一个好人不应该这么想的。你要在公共场合拉屎?你不觉得羞耻吗?

我认为好的框架不是这种圣人式框架,而是那些甘愿谦虚地作为一种工具,它不对你的编程方式作任何指手画脚的框架。


没有侵入性的副产品,是定制性几乎无穷,你愿意怎么使用这个框架都可以,即使是匪夷所思的方式。比如,你愿意拿砖头来磨成粉末然后放到烤箱里面去烤,可以,做就是了。框架并不需要弄个Grindable, Bakable接口来特地“支持”这个定制(当然,圣人的门徒会说,除了圣人提供的定制性,其它的都是你绝对不需要的。你为什么会想磨砖头?有病?),再就是你可以任意组合这些框架,你的生活你做主,这些框架只处理自己职责范围内的事情,绝对不会互相打架(当然,如果你的圣人说,你只许相信我,不许根别人钩三搭四,那就没办法了。实际上很多圣人系统的代价之一就是你不能随便和别人搭讪了,或者搭讪的代价比较大。看看那些“spring integrated”的广告语吧。难道一个组件不是天然就可以用在IoC容器里面吗?什么时候开始“IoC容器集成”居然也堂而皇之地算一个可以吹嘘的特性了?)

另一个考虑,是自恰性。很多有侵入的系统不是自恰的。比如spring里面,你的对象可以实现任意接口,除了以下几个:
BeanFactoryAware, ApplicationContextAware, BlahBlahAware (本列表持续更新中)

你可能觉得没什么阿。也许吧。反正我写和spring的集成代码时就很头疼这个持续更新的列表。如果明天spring又加了一个YetAnotherAware的marker interface,我还要回来增加一个"if(obj instanceof YetAnotherAware)",crap!



就像我们现实生活中没有人会用到String[][][][][]这种类型吧?我也没用过。但是如果某位圣人作了一个语言或者系统,然后告诉我说String[][][][][]被用作一个特殊的用途,我不能用,我也会觉得不爽的,非常不爽。特殊规则是对一个系统的美感(即使没有其它实际意义上的缺点)的严重伤害。



当然,事实上到底是那种哲学更实用,老实说我不知道。
0 请登录后投票
   发表时间:2006-12-21  
呵呵,这样讨论比较感性,这么说起来我对所有中到高级的编程语言都有点意见, 关于做整数除法运算的时候, 我如果用机器指令或者汇编语言写一个 DIV 指令, 执行了以后 AX 里就是商, 而 DX 里就是余数. 而中高级语言的话, 就算是 C 要同时获得这两个数也不得不完全没有必要的重复执行这个指令两次.
0 请登录后投票
   发表时间:2006-12-21  
太虚了,给点例子好么
0 请登录后投票
   发表时间:2006-12-21  
无侵入性似乎真的很难做到, 或者说根本做不到。 只能提高框架的灵活性, 只要能达到可忍受的地步,或者让程序员可以忽略的地步就可以了。 就像上文所说的 java bean 以及 default ctor.
从框架出来的本意是简化程序,或者应用的开发, 从这一点上,程序员也应该不会做一些自找麻烦的的事。
当然这对开发新的程序,或代码也许并不成为问题 ,因为在开发的过程中自然会考虑到“一些限制”,
但就像上文提出, 对于旧的系统,

框架.registerComponent(MyComponent.class, "请用initService1()来设置service1的依赖")

这也许无非也是框架的一种能力, 当你写下这句话的时候,是否意味着, initService1() 不能带参数?

从某种意义上讲,这不是限制吧

不过我现在越来越讨厌复杂的“配置”

convention over configuration  倒是很好的途径,

毕竟大家都是守规矩的人, 真的不想守的时候, 可以 configuration..
0 请登录后投票
   发表时间:2006-12-21  
bencode 写道
无侵入性似乎真的很难做到, 或者说根本做不到。 只能提高框架的灵活性, 只要能达到可忍受的地步,或者让程序员可以忽略的地步就可以了。 就像上文所说的 java bean 以及 default ctor.
从框架出来的本意是简化程序,或者应用的开发,

java bean或者default ctor应该作为一个convention over configuration机制。如果不提供额外的configuraton倒也罢了,可以认为scope就这样。但是如果或者只能通过侵入来提供,就不能不说是一种遗憾了。
无侵入性真的很难么?ArrayList对容器内部的对象有侵入么?很难么?

引用

框架.registerComponent(MyComponent.class, "请用initService1()来设置service1的依赖")

这也许无非也是框架的一种能力, 当你写下这句话的时候,是否意味着, initService1() 不能带参数?

框架都能天才到分析我的自然语言了,猜测我的意思其实是initService1(someService1)应该不是难事吧?:)

引用

convention over configuration  倒是很好的途径,

毕竟大家都是守规矩的人, 真的不想守的时候, 可以 configuration..

守规矩的时候大家都半斤八两,无所谓侵入性了。但是当无法守规矩的时候,就得看框架的侵入性了。spring是通过“你想要额外的功能?好吧,你让我进入,大爷我就帮你。没人逼你亚,是你自愿的”。而我认为更理想的是:"要额外的功能?你可以告诉我说“请通过某某方法注入对某某的依赖”。什么?你觉得这么说太麻烦?想跟我心有灵犀一下?那样更爽一点?好吧,恭敬不如从命。"
这世界是多样化的。有人不在乎被进入,而有人在乎的。

0 请登录后投票
   发表时间:2006-12-22  
dongbin 写道
太虚了,给点例子好么

前面说了, 因为最终目的的不可避免性, 所以目前来说是没有实际的解决可能的, 只有在单元化开发和测试方面还有些现实问题可以讨论. 不过顶楼大部分是在表述我对下一代软件体系里相关问题的一些期望.

看到大家的讨论又想起来一点相关的东西, 对于 "框架" 这个东西似乎流行的时间还不太长, 我觉得从本质方面看, 以现在的 "框架" 向前追溯, 依次可以找到 "设计模式", "算法", 和 "数据结构". 把这个顺序倒过来就是 计算机程序设计专业知识的共享和传播 这件事所经过的一个发展历程.

最早的时候连面向对象的指导思想都没有, 也没有系统程序员与应用程序员之分, 计算机也就是做运算, 比自动计算器强不了多少, 那时候用编程解决问题的主要手段就是设计一个适合的数据结构, 再设计, 利用起一些相应的算法, 最终解决的是一些 "运算问题".

后来这个行业发展飞快, 迅速的向数学以外的应用领域延伸, 于是软件被开始用于解决 "自动化管理问题". 大量新问题的引入严重增加了对编程手段的需求, 于是软件开发自然拆分为 "设计" 和 "编码" 两个部分. 算法和数据结构的作用在基本的编码问题以外能发挥的作用不大, "软件设计" 更像是新增加出来的工种, 于是专门从事软件设计的人把一些精妙有效的程序模板归纳总结成 "设计模式" 来加以利用.

不久以前计算机在一些领域(比如互联网网站开发)的应用产生了质的飞跃, 这方面的开发工作从设计原则到编码技巧都已经发展出了成熟的公众基础, 人们已经不再需要自己凭空探索就能从广泛的资源获得可以实际应用的指导原则和解决手段. 于是智力投入的焦点就转移到综合,总结一定的公众知识资源, 转化成可以直接运行, 直接提供一部分软件功能的可重用组件上.

这大概就是框架的来历.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics