2009年5月24日星期日

改进实现

TimeMachine的第一个实现跑起来了,跟预期的行为一样。但进一步想想,有两点不足:
  1. 每睡一小时/一分钟都会输出一条日志,一个周末下来,输出了很多重复的日志。
  2. 端午节要到了,原来的实现只考虑了周末,没有考虑这种节假日休息,周日反而要工作的情况。
解决起来也很简单:
  1. 在WorkTimeControllerImpl中添加一个方法“Date nextStartTime()”,计算下一次开始工作的时间,这样waitTillStartTime()就可以只输出一条日志,然后一直睡到下次开始工作。
  2. 在WorkTimeControllerImpl中添加一个非工作日列表,包括正常周末和节假日。
这个故事有两点意义:
  1. 重复的无用信息是不好的。Don't Repeat Yourself. 无用的信息会干扰有用的信息。
  2. WorkTimeController和TimeMachine接口都不需要改变,这就是区分“做什么”和“怎么做”的好处。
一次就做对是不容易的事。就像书法家写作品,写了很多,满意的不多。

2009年5月21日星期四

TimeMachine

手上在写的程序希望能够跑着就不要人管,但只在工作日的9:00到11:30,13:30到15:30做需要做的事,其他时间休息。

所以我设计了一个WorkTimeController,它有3个方法:
void waitTillStartTime();
void skipLunchTime();
boolean afterEndTime();

waitTillStartTime()负责跳过双休日、国定假日,直到工作日的9:00为止。它在8:00之前,会sleep(ONE_HOUR),再检查一下时间。在8:00之后,会sleep(ONE_MINUTE),再检查一下时间。

skipLunchTime()在工作时间会立即返回,在午休时间会sleep(ONE_MINUTE),再检查一下时间。

afterEndTime()判断是否在15:30以后了。

工作程序有一个doOneDayJob()方法:
void doOneDayJob() {
workTimeController.waitTillStartTime();
while (true) {
doSomeJob();
workTimeController.skipLunchTime();
if(workTimeController.afterEndTime()) {
break;
}
}
}
这样就完成了一天的工作。

现在的问题是,如何来验证这些时间控制动作都是正确的?难道只有让时间来证明?“Time, goes by, so slowly...”

于是我设计了一个TimeMachine接口,包含两个方法:
long currentTimeMillis();
void sleep(long time);
WorkTimeController使用TimeMachine来获取当前时间和休息。

TimeMachine的正常实现是很直接的,我设计它的目的在于,可以实现一个MockTimeMachine。这个MockTimeMachine的sleep方法什么也不做,立即返回。而它的currentTimeMillis方法则依次返回一组预先设定好的时间。这样,我们就得到了一个时光机,可以检测在一些关键的时间点程序行为是否正常。

时间是一个关注点,在这个例子里,我们实现了时间关注点的分离,改善了程序的可测试性。

2009年5月14日星期四

彩色UML总能给出漂亮的领域模型


手上在写的一个程序需要不断抓取实时信息,然后根据既定的策略做出相应的反应。写着写着,就觉得结构有点乱了。等一下!我还没有用彩色UML建过领域模型!

特定的Info触发Strategy创建Executing,Executing在被创建之后可以接受Info,并创建ExecutingDetail。Strategy可以控制在执行的Executing的数目。Executing实际上是一个有限状态自动机的实例。

画了类图以后,感觉好多了。方法学就是习惯。习惯就是不那么做就感觉不舒服。

试着用Netbeans画了个序列图。VisualParadigm接手UML模块后,带来了易用性。

2009年5月10日星期日

最大价值

“如果你的男朋友跟你谈恋爱三个月了,还没有谈到未来,那么你们就没有未来”。这是以前看到的一个笑话。现在我改编了一个新版本:“如果你的项目开始三个月了,还没有提供客户价值,那就永远不能提供客户价值”。

这句话很极端,我相信一定能找出反例。所以如果您不同意,一笑而过就可以了。

早交付、常交付客户价值,是敏捷方法学的核心。这样做的直接结果就是提高了ROI。所以,向商业客户推销敏捷方法是不难的,只要告诉他们可以提高ROI就可以了。

体现客户价值的需求有很多项,先交付哪一项?答案很简单,先交付最有价值的那一项。如果你运气好,最有价值的那项需求碰巧可能是最容易用计算机系统实现的。那项需求如果用人工来做,成本可能极大,精度和时间上可能完全做不到;但对于计算机系统,则是轻而易举的事。

但是,要明白什么是客户的最大价值,需要和客户进行充分地沟通。要让客户了解计算机系统可以做到什么。如果客户对计算机系统缺乏了解,就不能提出计算机系统对他最大的帮助是什么。开发者要尽可能了解客户的业务特点,和客户一起,找出计算机系统能够实现的最大价值。

鼠标的发明者Douglas Engelbart说,计算机的作用是IA(人类智能的扩展)。我们要找到人的弱点和计算机的长处,然后取长补短。

七个习惯说“要事第一”,TOC理论说“找到瓶颈并加以改善”,棋谚说“急所先于大场”,道理都是类似的。可做的事情有很多,做不完,要列出优先级。

宫本武藏在《五轮书》说:以剑法而言,敌一人与万人其理雷同。做一个人的小项目和做一万人的大项目,道理是一样的。

结论:定制开发的成本是很高的,客户的价值也很多,我们要尽可能从最大价值开始。

PS:问:“不太理解这里客户价值指什么。是指客户最关心的feature吗?”

答:要让客户享受到实实在在的好处,挣到钱。这样客户就愿意掏钱支持下一步的开发。大家拿到钱,士气才会高。

 就像医生开药,不能说我的药吃两年,让你壮得像小伙。得是吃了一个月之后,关键症状有明显减轻。然后再说,坚持吃点啥,调理调理。也有可能吃了一个月的药后,后面的药都不用吃了。

 实际上,随着客户业务的发展,不断会有新的业务瓶颈出现,需要克服。IT系统也可以不断改进,提供新的客户价值。于是实现了双赢。 

所以在客户关心的feature中,弄清楚每个feature能帮客户挣(省)多少钱。这是提供解决方案的基础。

2009年5月6日星期三

美丽架构7原则

  1. 一处一事实。一个设计决定,只出现在一个地方。将来当这个设计决定改变时,改动量可以最少。参设计决定、反悔、霰弹式修改和架构污染
  2. 自动传播。有时候出于效率考虑,必须复制一些东西。系统需要保证这些复制很容易自动进行。现在流行的分布式版本控制系统(Git、Hg)就是很好的例子。还记得当初的EJB吗?事实是我们在写分布式应用,然后规范要求我们在几个地方尊重这个事实。EJB3.0改变了这种情况。
  3. 架构也包含构建过程。架构什么都不是,围绕架构的过程就是一切。
  4. 使用最少的机制。够用就好。要明确目标,优化瓶颈,不要沉迷于非瓶颈部分的优化。要事第一
  5. 设计引擎。利用引擎,我们把该放在一个地方的内容放在一个地方。例子有规则引擎、工作流引擎、脚本语言和DSL。但是在项目中自己实现一个引擎要考虑实现的成本和项目的经费。
  6. 支持伸缩。在负载增大的情况下,系统的表现如何?系统是怎样的方式实现伸缩?
  7. 抵制熵增。年轻时很美并不难,难的是一辈子到老都很美。美丽的架构能够经受时间的考验。

2009年5月4日星期一

DSL

不同领域的人讲着不同的语言。这些语言中的概念有特殊的语境,包含一些特殊的概念,是对话者多年潜心钻研的结果。

在考虑系统架构时,一般原则是按领域来分解系统。不同的系统组件由不同的领域专家来负责。例如,我们把系统分成三层:UI、业务、持久。

将不同领域的内容写在一段程序里,是公认的坏事。如果你看到某段代码中既有对HttpRequest的处理,又有业务规则,还有数据库连接和SQL语句,那么有两种可能:写这段程序的人是初学者或超高手(初学者不知有更好的写法,而超高手故意为之,因为写这段代码时的情形令他做出这种选择)。

业务领域可以继续划分,在一个企业里,财务、销售、生产、仓储物流等等都是不同的领域,拥有各自的领域专家。

架构师,是那种对每个领域都懂一点的人。而他懂的那一点,恰恰是这个领域的精华。这样,他就能设计出不同的领域如何组织成一个系统。

企业的CEO,也是那种对每个领域都懂一点的人。他甚至还懂信息技术。所以他知道怎么把属于不同领域的部门组合起来,形成一个系统,去实现整体的目标。

面向对象技术的强大就在于,可以形成自定义的概念抽象。然后,我们可以有一个执行引擎,执行由这些概念所组成的指令。

Groovy/JVM是个好引擎。

if ((new PriceDifference("zn0906", "zn0907") > 108)
      && new Tendency("zn0906").isUp())
{
    new KaiCangBuyIn("zn0907");
    new Delay(ONE_SECOND);
    new KaiCangSellOut("zn0906");
}

没有仔细学过Groovy,如果能把这些new去掉就更清晰了。

Google:广告界最懂信息技术的公司

Google是著名的搜索引擎,但搜索是免费的,它也不搞竞价排名。现在大家都知道了,它的盈利模式是广告业务。开展广告业务的公司很多,Google的核心竞争力在于,它是所有广告公司中最懂信息技术的。

早就听说Walmart建立了强大的数据仓库,通过数据分析来制定各种业务决策:商品的摆放位置、销售价格......,Walmart不记录客户的姓名,但是它的系统被一本讲客户关系管理的书列为重点案例。Tim O'Reilly在推销Web 2.0的概念时说:你们知道吗?Web 2.0最成功的典范不是Sun的员工blog,也不是Dell的产品评论,而是Walmart。因为它能根据销售信息决定采购、物流、上架。也就是说,它能根据环境变化来自动改变业务决策。这些环境变化的信息正是客户所提供的,这就是Web 2.0的精髓。Walmart是所有零售公司中最懂信息技术的。

英文资料常见到这样一个词组:informative decision,意为“信息充分的决定”。然而,环顾四周,这样的决定是少之又少。

做IT这行的人和公司,对信息技术的理解也有高下之分。作为一个软件公司的管理层或一个软件项目的经理,他们的日常决定有多少是informative decision?

谁是软件界最懂信息技术的公司?谁是金融界最懂信息技术的公司?谁是健身行业最懂信息技术的公司?

一般来说,最成功的人是拥有最好信息的人。