上面各位很高兴能有关于这方面的讨论,zjsun
这位兄弟,提出了很多想法和我这里团队开发的平台十分相像,我们的平台名称就叫快速开发平台(Rapid Application Builder)我觉得要做一个十分庞大的快速构件平台,从目前国内来看可能性不是很大,如果将开发人员全部套死在平台框架中,我想很多程序员都会觉得不是很舒服。在这里我想提提我作为RAB平台作者的一些想法,如果提的有什么不对,恕小弟水平有限。
我们的快速开发理念其实就是节约开发过程中的成本,诚然我的目标也是在快速开发的同时保留足够的开放性和扩展性。所以整体架构还是基于J2EE的分布式架构。当然快速开发是我们的根本目的,所以框架所提供的功能就是降低开发的工作量。我在设计之初就认为表现层GUI的工作量是整个开发过程中,反复最厉害,工作量最大的地方。所以我们的平台更加专注于解决表现层问题。而传统的B/S结构已经很难适应快速开发的需求,无论实在开发的效率还是用户操作的友好性稳定性。所以我们采用Swing外加Java Web Start作为表现层。
我们有长期从事Swing开发的经验,对Swing的底层技术十分了解,所以我们首先开发了一套Swing组件,我认为纯Java的组件有良好的封装性和扩展性,所以我们设计之初就通过接口的定义,使组件有良好的扩展性,可以完全兼容SWT组件。Web Start也提供了我们和B/S架构一样的自动安装和更新的功能。而且Swing在使用下来性能方面远远剩余B/S架构,稳定性远远高出了AJAX。
我认为让程序员所见即所得远远不够,让用户所见即所得才能解决根本问题,所以我做了一套GUI设计器,和大多数产品公司的GUI设计器不同,我的设计器完全是和最终的运行环境完全结合,非但可以通过GUI设计器创建一个GUI,就算最终用户使用时也可以进行随心所与的调整。此外我们设计了组件库机制,通过工具为数据库每一个需要展现的字段分配一个UI组件,包括这个字段需要展现时的掩码,长度,大小写,格式,国际化资源键等等,这样在UI设计时,可以直接从组件库中选择要展现的字段,拖入界面中即可,同时我们的MVC是一种动态的MVC,Model的字段以及其层次的关系完全由页面驱动,即用户需要看到什么数据字段,那Model中就有什么字段,绑定当然也是完全自动的。与Web的MVC相比,我们更加注重多层次的数据绑定,我们将业务之间的复杂关系尽量都在页面中实现,当然这个还是靠我们强大的数据表格组件支持。表现层最终的存储形式我们也zjsun一样采用的是解释机制,用xml来表明具体的使用控件,控件的属性位置。此外我们还对Model做了镜像,也就是再作修改操作时,保存修改前的数据,提交UI数据时,只提交修改后的数据,这样大大减小了数据传输量。
我们还做了一个页面Lazy Loading的机制,就是当有传统的Tab页存在时,第一次装载,只会实例化用户所见的组件,而看不见的组件只有等到点上的时候才能实例化,这样我们就算再复杂的UI,装载速度也非常快,加上我们采用SAX解析UI的xml,我们打开一个非常复杂的UI一般最多只要3s不到,Lazy Loading对于开发人员来说也是完全透明的,这是因为我们的组件对于开发人员来说完全接口化,开发人员不用关心具体的组件实例对象,所以我们实现了一套Fake组件,其只是实现组件接口,在UI解析时,如果需要Lazy Loading的组件,他只会实例化Fake组件,而Fake组件不需要利用图形资源所以的开销十分的小,可以忽略不计,而除了图形资源外,Fake组件包含了全部组件功能,包括enable,visiable,位置设定,还有数据绑定的特性,所以开发人员如果需要对Lazy Loading组件进行操作时不用关心其是否时Lazy组件一样可以操作,而当Lazy组件需要真正实例化时,我们会将其对应的Fake组件数据传递给真正的实例组件。
在服务器端,我们用的是传统的Stateless Bean作为Facade组件,我们的快速开发理念就是后端提供一个通用的CRUD组件,根据前台的Model来驱动对数据库进行CRUD操作。我们完全拆散了ORM的概念,将其分为OM和RM,在做CUD操作时,我们会按照Model的关系层次,按照最简单的主从关系进行单表的OM操作。在查询操作时,我们会利用RM的关系按照主从关系进行SQL的自动拼接。这样就完成了GUI的数据完全自动的Persistence。ORM的拆分,也是的我们的Persistence技术又很强的扩展性,因为对于Persistence来说我们最后都是对单表进行操作,基本不会用到级连功能,所以我们完全可以抽象出对于单表的CRUD接口,然后通过不同实现的适配器加其操作,比如Hibernate,JDO等等。其性能进过我们长期测试不存在任何问题。当然通用的CRUD对于处理复杂的业务逻辑来说远远不够,我们利用AOP的思想对于通用CRUD组件进行了拦截操作,也就是在其CRUD操作的之前或者之后,进行增强,或者直接拦截操作。这样对于大多数情况下的业务处理,既可以利用CRUD组件提供的大部分功能,也可以对其某些特定逻辑增强。由于利用Facade模式,我们前后台逻辑的调用有可能没有足够的OO化,所以我们采用了和RMI一样的原理,利用Groovy实现了Stub,利用和Spring的BeanFactory一样的设计方式――面向业务接口的调用,当需要调用后台逻辑,我们会用Groovy生成一个Stub代理前台的调用通过Facade委派给后台特定的逻辑组件返回结果,这些对于调用者来说完全透明,对于复杂的逻辑抽象的更好的话,可以完全做到前后台逻辑无关。
当然除了上面这些技术核心之外,我们还有完善的基于角色的Privilege Infrastructure, Menu Setup,Module Setup等等一些外围的基础设施。还有基于Groovy的业务规则引擎,基于企业内部组织结构客户化设定(UI的xml文件,或者业务规则)。我们还有动态的报表引擎(JasperReport,可以让用户在运行时修改报表的布局,字体,甚至文字(国外这种是绝对不允许的,国内我们几个客户强烈要求这个功能,因为可以做假账),修改完之后也可以保存修改后的布局,我们还整合了IReport和我们报表数据源框架(也是基于XML的数据源定义框架)使用户可以在运行时直接通过IReport和提供的数据源通过拖拽的方式创建一张新报表。
可以看出我们的平台和业务数据源结合十分紧密,无论是UI,还是Persistence,还是报表,这其实就是我们核心思想的体现,我认为快速平台真正需要实现就是需要有强大的GUI和完整的数据源的支持。在这基础上实现诸如工作流,规则引擎等等一系列的子系统拿就不是什么难事。而在这些基础架构上实现的项目,甚至产品也会有很强的生命力。
如果有朋友对我们的平台有兴趣,或者希望交流一些技术,可以直接联系我,我的msn是xiefeng2002@hotmail.com。我很希望有更多的朋友加入讨论。

xf的平台看上去不错,原来国人还是有在默默做事的。

乘这个机会,我将前段时间总结衡量一个真正优秀构件平台的标准成立如下,以便各位有兴趣者参与评价:

灵活性:灵活性是可维护性和可扩展性的集中体现,基于组件的架构实现完全松耦合,各层之间真正彻底解耦 。

快速性:过分灵活就造成异常复杂(one size fit all),导致开发效率降低,一个好的框架必须能够适用快速开发。

可伸缩性:没有一个固定解决方案适合大中小所有规模系统,但是小型系统的架构必须将来能够平滑过渡到大型系统,而不是推倒重来。

透明性:一个框架不能对开发者限制太多,也不能将开发者封装在一个黑盒子中,应该可以让开发者越过该框架操作该框架力所不能及的功能。

良好性能:该框架要提供缓存或池功能提升性能,同时框架本身也必须提高性能,不能因为采取新技术而忽略性能要求。

状态管理:状态是业务逻辑中主要操作对象,是等同于数据库的重要概念,一个框架应该提供领域模型的Session状态管理。

开发流程模板化:由于一个功能需要跨越J2EE多层结构,容易造成开发思路和管理混乱,这就要求框架架构适合规模化批量生产。

遵循OOA/OOD/OOP等设计原则,不能变相以数据库或传统过程语言思维替代OO。

谢谢大哥的指点,你提的很多思想我们有的已经实现也有的正朝着这个方向努力,我们的平台还是一个非常年轻的产品,正在通过不断的项目来完善产品,毕竟实践出真理,呵呵!以后有机会多给小弟一点指教,小弟受益非浅。

>,正在通过不断的项目来完善产品,毕竟实践出真理
在这里不断看到各种高手浮现,欣慰国人还是自强不息,关键还是多多交流才能多多提高,一起努力吧。

跟我想要的东西非常类似了,我想请教一下,你在做这个东西的时候选的框架和用到的东西。你说的动态Model我很感兴趣。不知道你如何实现?Hash? 那么跟关系数据库映射的时候会不会造成历史数据的问题?

ex:我做个流程,用了一段时间,变更表单,添加的字段是很重要的,你如何实现原来的数据用原来的东西来查看?因为新的已经和历史数据不符合了

这个朋友,你的需求我还不是特别清楚,我们这里表现层是一个动态Model,其实就是对HashMap的封装,查询数据的时候,会根据当前动态Model里面所有的field到后台去查询,自动完成的实现,其实是我们后台有一个关系引擎来得到每个查询字段的关系。然后拼接sql,得到查询结果。你如果有什么问题的话可以和我直接交流,msn:xiefeng2002@hotmail.com

很高兴大家谈论业务构件平台时,谈到了Model,领域模型驱动设计(Domain-Driven Design 简称DDD)应该是最新业务构件平台的一个基本方向。

现在很多开发框架是以减少层次达到快速开发的,甚至将UI和领域合并在一起,DDD专家Eric Evans认为这些都是旁门左道,这些所谓智能UI快速可视化构建工具的特点如下:
1.将所有业务逻辑放在表现界面层处理(例如Action中嵌入业务代码),将整个应用系统分割成一个个小的功能函数,有时伪称构件;用一个关系数据库作为数据的共享存储地,使用最自动化的图形设计结构,充分利用可视化的编程工具。

这些都是错误的,真理应该是:领域和UI彻底分离。

xf:
这个朋友,你的需求我还不是特别清楚,我们这里表现层是一个动态Model,其实就是对HashMap的封装,查询数据的时候,会根据当前动态Model里面所有的field到后台去查询,自动完成的实现,其实是我们后台有一个关系引擎来得到每个查询字段的关系。然后拼接sql,得到查询结果。你如果有什么问题的话可以和我直接交流,msn:xiefeng2002@hotmail.com
------------
我也作过类似的事情,不过是在.net中。完整的实现了前台,业务,数据层的对应。不过这么做在java里面我不太清楚能否得到容器的支撑。在.net里面这些都是我自己搞定的。我理解Hibernet多半没法用了,缓存也得自己搞定。这个都还不是痛苦的。痛苦的是做设计的时候,没有工具可以帮你映射。程序员拿到动态Model的时候也比较头痛。而且Model变化有时候不是简单的增加Field映射到数据库,如何处理扩展关系我也觉得很头痛。我最近看数据仓库设计的时候也一直在想这个问题,是否有元表来指挥?(又回到了数据库决定设计思想?呵呵)

不知道这些你怎么解决的,听听你的思路 :)。


Banq

现在很多开发框架是以减少层次达到快速开发的,甚至将UI和领域合并在一起 这些都是错误的,真理应该是:领域和UI彻底分离。

-----------------
开发我认可。不过如果这个东西要面对客户,我觉得其实不算问题。问题是怎么做好一个分层清晰,用户可操作的平台(快速用户配置+部分定制开发)我没有见过,也没有想明白,能否推荐一个比较成功的案例来分析呢?

也谈不上元表,其实我们还是保留着分布式架构,有着非常清晰的层次概念,在表现层Model就是负责数据采集以及数据展现的对象。我们这里用的动态Model的概念就是,可以动态的添加或者删除一个字段,其实就是对一个Map或者.Net里面的HashTable的一个MVC封装。这里我们平台本身的目的就是出于快速开发,所以对于一般性质的字段,我们认为是与数据库的某一个表,某一个字段所绑定,字段的标示,我们不是采用简单的类似name这样的描述,而是有具体表名对应,比如appuser.username的一个简单表识对象,有点像SCOPE里面的selector。在做数据CRUD操作时,我们是奖ORM拆开,变成了OM和RM,OM有一个单独的元配置信息维护,可以是xml也可以是数据库的一张表,用来向框架提供特定的一张表有那些属性,属性的类别等等。RM的配置信息,就是编制一个关系图,比如我们有这样的描述


<bean name="appuserrole">
<pk name=
"orgchartunid" relation="appuser.orgchartunid"/>
<pk name=
"roleunid" relation="approle.unid"/>
</bean>

用来表明appuserrole中主键orgchartunid是与appuser中的orgchartunid关联,还有roleunid与approle中的unid关联。这里还可以给出更加复杂的关系描述,比如左连右连等等。
此外我们的每一个功能模块,其本省都有一定的配置信息,这里最主要的就是这个模块对应的是那张主表信息,举个例子比如我们有一个模块入入角色,以及给这个角色委派user的功能模块,其对应主表就是approle
在也页面上有approle.roleid,approle.description,这些role的基本信息,还有一个表单控件(表单控件完全是我们自己实现,机制极为复杂,有点类似PB的数据窗口,有增,删,改3个缓冲区),表单信息表明的就是这个role可以委派多个user,其中信息有,appuser.username,appuser.description.appuser.orgchartunid,而这里我们的表单控件还可以指定一个极为重要的属性,也就是表明你这个表单控件的数据在动态Model中的标示名,同样按照上面提到的描述方式,我们用这个表单控件所需要更新的1-*的那个主表,以及一个任意的属性名做标示,这里我们就定义为appuserrole.rolelist。
我随便拿一些数据举例子,当这个模块需要完成Insert时,前台的动态Model也就是Map中就会有这样的结构
approle.roleid-"admin"
approle.description="admin"
appuserrole.rolelist=[{appuser.username="xf",appuser.description="xf",appuser.orgchartunid=1},
{appuser.username="xf1",appuser.description="xf1",appuser.orgchartunid=2}]
然后数据以及当前模块的配置信息会传递个我们服务器上的CRUD引擎,引擎根据当前功能模块主表的名称,来从Map的第一个层次结构中提取当前主表的数据,如果发现不是对应当前主表的字段则舍弃,最后更具OM的信息决定那些字段需要Persistence到数据库。当读到appuserrole.rolelist的时候,引擎发现是一个Collection集合,于是根据当前Collection集合的标示也就是appuserrole.rolelist得到这个集合数据所需要更新的表appuserrole,然后遍厉这个Collection同理做Persistence的操作。这里会发现appuserrole的一个主键appuserrole.orgchartunid没有出现再数据集中,我们这里采用了类似图论的一个算法,将RM的关系编织成关系图,然后根据当前的主表,以及Context的数据(这里更新appuserrole的时候Map第一个层次结构的数据就是其Context)可以得到当前主表的主键数据,所以这里我们可以根据approle.unid的值以及appuserrole的表名和RM的关系得到appuserrole.roleunid的值,然后再做Persistence的操作。
更新和删除也是按照insert的方式来做。
但是查询的时候就十分复杂,就类似你贴字中提到的情况一样,要考虑动态添加后,数据字段的扩展关系。首先我们会将前台动态Model需要展现的这些字段传递个CRUD引擎,根据当前功能模块主表,以及Model层次结构,和需要展现的字段,一层一层的查询数据。这里还是利用了上问提到类似图论的算法,给出任意数据字段,以及其所在层次对应的主表,得到这个数据字段与当前主表的关系,比如这里就是approle.unid=appuserrole.roleunid,其它的字段就拼接出select appuserrole.unid,appuser.username,appuser.description from
appuserrole,approle where appuserrole.roleunid=approle.unid最终得到DAO的数据查询语句。通过DAO得到结果值。通过简单的关系Cache,轻量级的DAO封装不会对这样查询的性能造成任何影响。这样如果在表现层再多加一些appuser的数据字段,照旧可以完成自动的CRUD操作。
当然实际项目中,这种简单的操作还毕竟少,有的时候需要支持复杂的子查询,有的时候需要按照某一个字段排序,或者压根不和数据库打交道,所以我们用AOP的方式对CRUD操作做了非常多的增强功能。总之实现动态Model最终重要的一点就是有一个强大的RM引擎支持。

我这里有可能说得比较乱,呵呵,语文水平比较差,如果还有疑问的话,我们可以继续讨论。

也谈不上元表,其实我们还是保留着分布式架构,有着非常清晰的层次概念,在表现层Model就是负责数据采集以及数据展现的对象。我们这里用的动态Model的概念就是,可以动态的添加或者删除一个字段,并且自动与CRUD引擎结合。动态Model其实就是对一个Map或者.Net里面的HashTable的一个MVC封装。这里我们平台本身的目的就是出于快速开发,所以对于一般性质的字段,我们认为是与数据库的某一个表,某一个字段所绑定,字段的标示,我们不是采用简单的类似name这样的描述,而是有具体表名对应,比如appuser.username的一个简单表识对象,有点像SCOPE里面的selector。在做数据CRUD操作时,我们是奖ORM拆开,变成了OM和RM,OM有一个单独的元配置信息维护,可以是xml也可以是数据库的一张表,用来向框架提供特定的一张表有那些属性,属性的类别等等。RM的配置信息,就是编制一个关系图,比如我们有这样的描述


<bean name="appuserrole">
<pk name=
"orgchartunid" relation="appuser.orgchartunid"/>
<pk name=
"roleunid" relation="approle.unid"/>
</bean>

用来表明appuserrole中主键orgchartunid是与appuser中的orgchartunid关联,还有roleunid与approle中的unid关联。这里还可以给出更加复杂的关系描述,比如左连右连等等。
此外我们的每一个功能模块,都有一定的配置信息,这里最主要的就是这个模块对应的主表信息,举个例子比如我们有一个模块录入系统角色,以及给这个角色委派user的功能模块,其对应主表就是approle
在页面上有approle.roleid,approle.description,这些role的基本信息,还有一个表单控件(表单控件完全是我们自己实现,机制极为复杂,有点类似PB的数据窗口,有增,删,改3个缓冲区),表单信息表明的就是这个role可以委派多个user,其中信息有,appuser.username,appuser.description.appuser.orgchartunid,而这里我们的表单控件还可以指定一个极为重要的属性,也就是表明你这个表单控件的数据在动态Model中的标示名,同样按照上面提到的描述方式,我们用这个表单控件所需要更新的1-*的那个主表,以及一个任意的属性名做标示,这里我们就定义为appuserrole.rolelist。
我随便拿一些数据举例子,当这个模块需要完成Insert时,前台的动态Model也就是Map中就会有这样的结构
approle.roleid-"admin"
approle.description="admin"
appuserrole.rolelist=[{appuser.username="xf",appuser.description="xf",appuser.orgchartunid=1},
{appuser.username="xf1",appuser.description="xf1",appuser.orgchartunid=2}]
然后数据以及当前模块的配置信息会传递个我们服务器上的CRUD引擎,引擎根据当前功能模块主表的名称,来从Map的第一个层次结构中提取当前主表的数据,如果发现不是对应当前主表的字段则舍弃,最后更具OM的信息决定那些字段需要Persistence到数据库。当读到appuserrole.rolelist的时候,引擎发现是一个Collection集合,于是根据当前Collection集合的标示也就是appuserrole.rolelist得到这个集合数据所需要更新的表appuserrole,然后遍厉这个Collection同理做Persistence的操作。这里会发现appuserrole的一个主键appuserrole.orgchartunid没有出现再数据集中,我们这里采用了类似图论的一个算法,将RM的关系编织成关系图,然后根据当前的主表,以及Context的数据(更新appuserrole的时候,Map第一个层次结构的数据就是其Context)可以得到当前主表的主键数据,所以这里我们可以根据approle.unid的值以及appuserrole的表名和RM的关系得到appuserrole.roleunid的值,然后再做Persistence的操作。
更新和删除也是按照insert的方式来做。
但是查询的时候就十分复杂,就类似你贴字中提到的情况一样,要考虑动态添加后,数据字段的扩展关系。首先我们会将前台动态Model需要展现的这些字段传递个CRUD引擎,根据当前功能模块主表,以及Model层次结构,和需要展现的字段,一层一层的查询数据。这里还是利用了上问提到类似图论的算法,给出任意数据字段,以及其所在层次对应的主表,得到这个数据字段与当前主表的关系,比如这里就是approle.unid=appuserrole.roleunid,其它的字段就拼接出select appuserrole.unid,appuser.username,appuser.description from
appuserrole,approle where appuserrole.roleunid=approle.unid最终得到DAO的数据查询语句。通过DAO得到结果值。通过简单的关系Cache,轻量级的DAO封装不会对这样查询的性能造成任何影响。这样如果在表现层再多加一些appuser的数据字段,照旧可以完成自动的CRUD操作。
当然实际项目中,这种简单的操作还毕竟少,有的时候需要支持复杂的子查询,有的时候需要按照某一个字段排序,或者压根不和数据库打交道,所以我们用AOP的方式对CRUD操作做了非常多的增强功能。总之实现动态Model最终重要的一点就是有一个强大的RM引擎支持。

我这里有可能说得比较乱,呵呵,语文水平比较差,如果还有疑问的话,我们可以继续讨论。

访问 http://www.extract.com.cn:8060 无需帐号和密码,点击业务系统看看我们的Extraction应用构建平台构建的业务系统例子;

业务系统所有功能的开发都来自平台构建,没有一行Java代码;快速构件平台其实并不是不可企及的东西,重要的是优秀的设计,加足够的投入;加快开发速度并节省开发成本也需要付出,快速构建开发可以做的足够强大,但在获得效率和更低成本的同时损失的是开发的乐趣和自由性;不过商业环境下乐趣和自由好像不是很有价值,当年风光的裁缝和手工艺者,最终也得成为生产流水线上的操作工;

>开发我认可。不过如果这个东西要面对客户,我觉得其实不算问题。问题>是怎么做好一个分层清晰,用户可操作的平台(快速用户配置+部分定制>开发)我没有见过,也没有想明白,能否推荐一个比较成功的案例来分析>呢?

现代业务平台架构应该在什么理论指导下?无疑是MDD模型驱动设计和DDD,Eric的DDD是一本具有很大影响力的书籍

http://www.jdon.com/mda/ddd.html