2009年1月26日星期一

彩色UML建模、SOA和《目标》

彩色UML的主要思想是组件化。粉红色的MI(时刻时段)是组件的核心,同时粉红色的MI也代表着事务,这些事务串在一起,组成了流程。

每一个粉红色的MI及其相关的黄色角色、绿色参与方-地点-物品和蓝色描述构成了业务流程中的一个步骤。根据彩色建模的伸缩性设计,这个步骤的粒度可大可小。可以是大粒度的“完成一次销售”,也可以是小粒度的“开发票”或“收款”。

SOA的思想是要把事务组件web service化,再用BPEL来组织流程,以这种方式来组织业务逻辑。
另外,在数据逻辑或信息逻辑的方面,SOA会把一些数据分析和挖掘的方法也设计成可以复用的web service。

彩色UML方法里面的一些思想,比如“评估销售的及时性”,就带有很大的数据分析的味道。

换句话说,我们先对业务过程记上流水账,然后再对流水账进行分析。我们记录下When/Who/What/Where/Why and How(‘5Ws and an H’ ),然后就可以进行各种分析了。你可以在数据库中只记录下最小粒度的业务事件,然后以虚拟数据源或信息服务的方式,提供大粒度的业务事件的相关信息。

为了让流程能够灵活变化,我们可以考虑消除步骤之间的耦合,即在红色的MI之间不建立直接关联,而是利用它们共同的关注的内容,如“订单”,来组织流程。如果我们要“评估销售的及时性”,只要得到“订单”下单的时间和付款的时间之差。设想有一个信息服务,作为一个虚拟数据源,提供一段时间内所有订单的完成时间和各步骤完成的时间。

Goldratt的《目标》是所有管理者都应该读的一本书。其中提到了一个重要观点:所有在原材料方面的投资,如果还没有变成有效产出(产品卖出去并收回货款),都应该看成是负债。这种负债乘以天数,是一个重要的测量指标。我们应该努力减小它。根据这一观点,制造业的企业提出了许多解决方案,如按订单生产、精益制造等等。而制造业的人们学到的东西,看来IT业都要重新学习。

回到我们的主题,这和彩色UML或SOA有什么关系?

关系就在于:我们的IT系统,要能够帮助企业的决策者找到系统瓶颈。看过《目标》的人应该记得,那里面有个神奇的CIO,每次都能告诉厂长系统的新瓶颈出现在哪里。然后大家不断优化瓶颈,使系统的产能和效率不断提高。

如果您就是那位CIO,请你告诉我,我们的订单执行过程中,哪(几)个环节耗时最多?




2009年1月15日星期四

设计决定、反悔、霰弹式修改和架构污染

(老文章,曾在《程序员》杂志发表。用了vim得到彩色的代码,但可惜在《程序员》上没有印出彩色。)


设计决定

“好吧,在这一个项目中我们就使用Google Guice!”我们坚毅、果敢、英明神武的首席架构师宣布了这个决定。

为什么不呢?依赖注入是这么成功的一个概念,我们使用Spring作为依赖注入框架已经好多年了。而Google Guice又给我们带来了许多的改进。

首先,Guice抛弃了XML配置文件,这使它具备了“重构友好”的特征。在Guice中,我们通过Java代码来说明接口(服务)和实现类的绑定,例如下面这一段代码:

public class MyModule extends AbstractModule {
protected void configure() {
bind(Service.
class)
.to(ServiceImpl.
class)
.in(Scopes.SINGLETON);
}
}

这样,当我们需要重构(修改)接口或实现类的名称时,就可以利用集成开发环境提供的重构功能来完成,不需要再手工修改XML中的类名。在重构深入人心的今天,我们不希望改一个类名还需要额外的工作。

第二,在抛弃了XML配置文件之后,应用程序就不再需要一个XML解析器了。这样,Guice就比Spring“瘦身”了不少。高手们总是对减少资源的占用怀有特殊的爱好,不是吗?Guice 1.0Jar包只有544K(高手可能会认为还是大了一点),不依赖于其他的Jar包。另外,由于不需要读取并解析XML配置文件,执行的速度也提高了不少。

第三,Guice使用了JDK 5的新功能,其中一项就是泛型。我们不再像以前使用Spring那样进行强制类型转换了,我们有了编译时刻的类型安全检查,而且代码也简化了。我们像下面这段代码那样取得组件实例:

public class MyApplication {
public static void main(String[] args) {
Injector injector = Guice.createInjector(
new MyModule());
Client client = injector.getInstance(Client.
class);
client.go();
}
}

第四,Guice使用了JDK 5的另一项新功能,annotation!这个词太可爱了,听起来和innovation有点相似,以至于我们一时间不知道如何将它翻译成中文。Guice提供了近乎神奇的@Inject annotation,满足您各式各样的注入需要!(我相信这些注入方式都是在Martin Fowler的那篇著名文章中提到的。)

我们可以实现构造方法中的注入,像下面这样:

public class Client {
private final Service service;

@Inject
public Client(Service service) {
this.service = service;
}

public void go() {
service.go();
}
}

也可以对属性直接注入,甚至不需要设值方法,像下面这样:

public class ServiceImpl implements Service {
@Inject
Emailer emailer;

public void go() {
// Some expensive stuff.
...
// Send confirmation.
emailer.send(
...);
}
}

第五,Guice有在真实应用中成功使用的历史。据说,它曾在Google的广告应用程序中使用,而Google的广告应用程序可能是目前世界上规模最大的应用程序!

最后,更重要的是,品牌就是品质。Google是如此受人尊敬的公司,吸引了许多重量级的人物加盟,已经成为许多IT人士向往的地方。使用Google的荣誉产品,就像使用JDK自带的包那样可靠,我们还有什么可担心的?据说Spring的新版本也向Guice学习,使用了annotation。模仿就是一种肯定,不是吗?


反悔

“新郎,你愿意娶新娘为妻吗?”

“是的,我愿意。”

“无论她将来是富有还是贫穷、或无论她将来身体健康或不适,你都愿意和她永远在一起吗?”

“是的,我愿意。”

“将来看到更漂亮、更好、更合适的,你也不会改变今天这个决定吗?”

如果理性地回答,答案就太不浪漫了。因为未来不可预见的事情实在太多。好在热恋中的人们倾向于不那么理性,所以答案是“永远。如果非要加上一个期限,我希望是一万年”。

我们的架构师正在与Guice开始一段新的感情。这种感觉太好了,上次有这种感觉好像还是在刚使用Spring的时候,那已经是几年前的事情了。现在他压根没想到以后可能会像抛弃Spring一样抛弃Guice

直到有一天,一个刚刚参加工作的小兄弟问了他一个很傻的编译错误。他告诉这个小兄弟,要使用@Inject,必须这样:

import com.google.inject.Inject;

小兄弟满意地继续他的开发,但我们的架构师却觉得有一丝不祥的感觉掠过,空气中似乎飘荡着一种坏味道。

他检查了一下项目源代码。在第一次迭代中,我们写了50多个类,其中大约有一半都包含了@Inject!这种情况不妙,简直太不妙了。这违反了他多年的经验所建立起来的原则信仰。

这违反了Larry Constantine的“高内聚、低耦合”的原则。这条伟大的原则如此简单而深奥,以至于不断受到人们的践踏。

虽然“疯狂的Bob Lee”为Guice设计出了极小的API接口,但在使用@Inject这一点上,却让人不太赞同。他似乎鼓励我们在自己代码的各处插入@Inject

当我们把一个设计决定分散到代码的不同地方,它就会成为难以改变的既成事实。即使是对于JDK自带的类,我们也不能这么做。我们不能在所有的业务类中都引用JDBC的包,使用ConnectionStatementRowSet。相反,我们应该把它们放在持久层中。也许,我们应该使用Hibernate这样的框架,将它们封装起来。也许我们还需要再封装一层,设计一个PersistentLayer接口和一个PersistentLayerHibernateImpl实现。这样,如果我们以后有新想法,只要再写个PersistentLayerJdbcImplPersistentLayerDb4oImplPersistentLayerIbatisImplPersistentLayerHibernateAndIbatisMixImpl

如果我们把使用Guice这个设计决定作为一种默认的假定,让它散布在代码的各个角落,那么将来我们要反悔的代价就非常大。实际上,我们就不能反悔了。

我们会反悔吗?我们需要反悔吗?不能反悔的决定是我们可以承受的吗?

我们的架构师做出了一个痛苦的决定:我们需要能反悔。毕竟,作为一名架构师,他的全部声誉就在于设计出有弹性的架构,可以容纳将来可能的变化。


霰弹式修改

我们的架构师是经验丰富的。办法总比问题多,不是吗?关键是要发现问题。根据“所有的问题都可以通过添加一个间接的中间层来解决”这一原理,他设计了一个Factory,这是一个全局的Singleton

public class Factory {

private static Factory factory;

synchronized public static Factory getInstance() {
if (factory == null) {
factory =
new Factory();
}
return factory;
}

private Injector injector;

private Factory() {
injector = Guice.createInjector(
new MyModule());
}

public T getInstance(Class type) {
return injector.getInstance(type);
}
}

然后,在每个用到服务依赖注入的类中,在构造方法里加上赋值语句:

public class Client {
private Service service;

public Client() {
this.service = Factory.getInstance().getInstance(Service.class);
}

public void go() {
service.go();
}
}

注意,我们没有为service属性加上final关键词,这样您仍可以有setService()方法,可以利用Mock对象对Client类进行单元测试。

剩下的工作就是从项目已有的代码中去掉所有的@Inject。这是一种“霰弹式修改”,不幸中的万幸,我们只要修改20多个类,而不是200多个、2000多个。

由于有自动化的测试类作为保障,这种改动很快就完成了。如果以后我们想换一个依赖注入框架,就不需要“霰弹式修改”了。我们甚至可以很容易改回用Spring,当然,目前还没有这个必要。

再见了,@Inject


架构污染

不久后的一天,我们的架构师在浏览代码时,惊奇地又看到了@Inject

原因很快查到了,一个刚刚结束了婚假回到开发团队的开发人员,因为错过了关于这次修改的讨论,重新在代码中引入了@Inject

我们的架构师设计出的精美架构受到了污染。这种事情以前也发生过,似乎总是有各种各样的原因,导致架构在实现者手里变形。我们的架构设计师能设计故事的开始,却猜不中故事的结局。这种情况是他所痛恨的。

“我们需要有一种手段,能对架构的实现进行监控。”架构师在开发例会上说,“这不是不相信我们的程序员,人都可能犯错的。”

“信任,但要核查。”里根在签署核裁军条约时曾这么说。

一个对敏捷软件开发颇有研究的高级程序员说,“我最近看了一本书,书名是《持续集成》,书中提到了一个工具,好像叫JDepend,可以显示项目中的包依赖关系。正适合解决这个问题。”

后来的故事简单了,通过重构,我们将Factory放在了单独的一个包里,只有这个包才对Guice产生依赖。我们的架构师经常地查看JDepend的输出,看着他设计架构一天天地实现。


尾声

我们的架构师盯着他的二十二寸宽屏液晶显示器,回味着简洁优美的架构所带来的快感。一个念头在他脑海中闪现:“如果Guice不提供@Inject相关的功能,那Jar包就会更小了。”

Guice是开放源代码的,如果有时间,我们的架构师将替他的“新娘”瘦身,去掉@Inject相关的所有类,让这种架构污染永远也不可能再发生。但是现在,还有更多的项目工作等着他。也许等他忙完这段时间,会再来折腾一下这个问题。

生命在于折腾,不是吗?

分析代码和项目管理:Sonar

静态代码分析、测试覆盖率分析是持续集成的重要组成部分,最近看到的开源项目Sonar,带给了我更多启发。

第一,对多个项目的统一管理和集中展示。这适合在开发组织(乙方)中应用,特别是一些做外包的公司的QA部门。

第二,对主要测量指标的时间维度的关注。当前的状况固然重要,但更重要的是发展的历史和趋势:情况是在变得越来越好还是越来越糟?。

第三,单个项目管理的dashboard。把项目的主要测量指标以图表(仪表盘)的方式展现出来。

第四,向下钻取具体信息。允许进一步关注细节。

第五,覆盖云。用一种创新的方式体现被测试代码中各个类被关注的程度。这种方式似乎来自于Blog对Tag的一种管理,例如,Sun公司的博客中的Most Popular Tags。很直观。

关于CMM有一个简单易记的说法:第二级是“Plan the work”,第三级是“Work the plan”,第四级是“Measure the work”,第五级是“Work the meature”。Sonar给了我们一些第五级的启示:我们关注哪些项目测量指标?怎样展现和应对?

Netbeans 6.5和Liferay 5.1.2

自从Sun把Studio Creator合并到Netbeans 6中以后,开发Liferay的portlet就不像原来那么方便了。最近搜了一下网络,新出了一个攻略!我还没亲自试过,不过可信度应该比较高。

Portal和portlet的概念很适合企业应用的组件化开发、SOA和流程再造,为应用程序的表示层提供了灵活的解决方案。是好东西。

2009年1月6日星期二

FDD项目进度管理和停车场图

特征驱动开发有一个好处,进度的管理变成了一件很简单的事情。

每一个特征的实现分成两步:根据特征设计(DBF)和根据特征构造(BBF)。其中包含一些小的里程碑,每个里程碑代表着完成了一定百分比的工作量。领域走查:1%;设计:40%;设计审查:3%;编码:45%:代码审查:10%;提交构造:1%。

接下来的魔法就是由项目管理人员来告诉大家项目的进度。最具创新的就是“停车场图(Parking Lot Char or Parking Lot Diagram)”。下面是一个例子 :


绿色的部分代表已完成的特征集,红色的部分代表已延期特征集,蓝色的部分代表正在开发的特征集,白色的部分代表还未开始的特征集。点击图片可以链接到该图的原出处()。

怎样能画出这样的停车场图?好东东来了,你可以在这里下载一个Excel模板。

每个星期打印一张这样的图,贴在墙上,告诉所有感兴趣的人,我们工作做到哪儿了。另外,还可以打印已完成特征数(或包含总特征数)随时间变化的折线图。看到这样的图表,所有的人都会心情愉快的。