逸言

对Log进行mock

| Comments

在我们进行的一个项目中,需要测试是否按照要求正确写入到日志中。例如,我们定义了这样的类和方法:

public class ServiceClient {
     public <S, D> D sendRequest(S request, final Class<D> responseType) {
          Source source = jaxbUtil.marshall(request);
          return sendRequest(source, responseType);
     }

     private <D> D sendRequest(Source source, final Class<D> responseType) {
          return webServiceTemplate.sendSourceAndReceive(source, SourceExtractor<D>() {
               @Override
               public D extractData(Source response) throws IOException, TransformerException {
                      if (LOG.isDebugEnabled()) {
                           LOG.debug(String.format("Received response: %s", XmlSourceUtil.toXml(response)));
                      }
                      return jaxbUtil.unmarshall(response, responseType);
               }
     });
}

现在,我们要测试在Debug被enable的情况下,是否真正写了日志。我们不可能在单元测试中去访问日志文件,然后判断日志是否写入。一方面,这影响了单元测试的速度,另一方面也会造成对日志文件的依赖。我们的做法是在测试时,获得该日志,然后将该日志的所有Appenders去掉,然后加入属于内存中的Appender,即WriterAppender,然后获得该Appender写入的日志内容,对这个内容进行断言。

案例分析:基于消息的分布式架构

| Comments

美国计算机科学家,LaTex的作者Leslie Lamport说:“分布式系统就是这样一个系统,系统中一个你甚至都不知道的计算机出了故障,却可能导致你自己的计算机不可用。”一语道破了开发分布式系统的玄机,那就是它的复杂与不可控。所以Martin Fowler强调:分布式调用的第一原则就是不要分布式。这句话看似颇具哲理,然而就企业应用系统而言,只要整个系统在不停地演化,并有多个子系统共同存在时,这条原则就会被迫打破。盖因为在当今的企业应用系统中,很难寻找到完全不需要分布式调用的场景。Martin Fowler提出的这条原则,一方面是希望设计者能够审慎地对待分布式调用,另一方面却也是分布式系统自身存在的缺陷所致。无论是CORBA,还是EJB 2;无论是RPC平台,还是Web Service,都因为驻留在不同进程空间的分布式组件,而引入额外的复杂度,并可能对系统的效率、可靠性、可预测性等诸多方面带来负面的影响。

然而,不可否认的是在企业应用系统领域,我们总是会面对不同系统之间的通信、集成与整合,尤其当面临异构系统时,这种分布式的调用与通信变得越重要,它在架构设计中就更加凸显其价值。并且,从业务分析与架构质量的角度来讲,我们也希望在系统架构中尽可能地形成对服务的重用,通过独立运行在进程中服务的形式,彻底解除客户端与服务端的耦合。这常常是架构演化的必然道路。在我的同事陈金洲发表在InfoQ上的文章《架构腐化之谜》中,就认为可以通过“将独立的模块放入独立的进程”来解决架构因为代码规模变大而腐化的问题。

Octopress的新浪微博插件

| Comments

在GitHub上搭建了Octopress博客后,我一直在尝试改进或增强一些功能。有一些功能可以在网上找到第三方插件。因为我在GitHub上的博客是刚刚申请,并没有太多人知道我的博客域名。如果希望我自己新写的博客让更多人知道,最好的方式还是能够将链接发到我的新浪微博中。一些插件为octopress提供了新浪微博的share按钮,但这并不是我想要的。也许已经有快速现成的方法支持我想要的功能,但我没有找到。那么何必还去上穷碧落下黄泉的去搜索了,身为一个程序员,这种事情就自己搞定好了。正好可以练手Ruby。经过半天的代码编写和测试,我的这个新浪微博插件就实现了。它主要能够运行rake命令,解析最新博客的标题与URL,再替换weibo-config.yml配置文件中配置的微博模板的内容,并将其发布到新浪微博中。

Octopress博客问题解决方案与技巧

| Comments

在GitHub上创建了自己的博客后,先后在Jekyll和Octopress之间来回折腾了好一段时间。之前打算直接使用Jekyll提供的博客模板,后来觉得太费神,看到Octopress还不错,且它也是基于Jekyll,并能非常方便地部署到GitHub上。经过最初的安装到对博客的深入改造,目前我的博客需要的功能已经大致完成。在这个过程中,也碰到了许多问题。通过搜索Google以及自己阅读Octopress代码,找到了对应的解决办法。此外,也有一些小技巧的积累。考虑到还有许多正在使用或想要使用Octopress的朋友,因此在这里集中分享一下。

文学与软件

| Comments

卡尔维诺在哈佛大学的文学讲座(即诺顿论坛,是为纪念美国著名学者诺顿开设的,每年邀请世界文化名人作讲座,艾略特、博尔赫斯也曾获邀参加诺顿讲座)被他的妻子编成了一本独立的书《美国讲稿》。这本书展现了卡尔维诺的文学精神,体现了他的文学态度和气质。不过,我在阅读该书时,却发现了一些与编程有关的内容。

1、文学中的重构

达芬奇在《大西洋草图》中记述了他幻想中海怪的形象,进行了前后三次重构。最初的描述是:

啊,人们多次在波浪翻滚的广阔海洋之中看到你,看到你那长满鬃毛的黑色背脊,你像一座大山,傲慢地徐徐前进!

软件系统的稳定性

| Comments

软件系统的稳定性,主要决定于整体的系统架构设计,然而也不可忽略编程的细节,正所谓“千里之堤,溃于蚁穴”,一旦考虑不周,看似无关紧要的代码片段可能会带来整体软件系统的崩溃。这正是我阅读Release It!的直接感受。究其原因,一方面是程序员对代码质量的追求不够,在项目进度的压力下,只考虑了功能实现,而不用过多的追求质量属性;第二则是对编程语言的正确编码方式不够了解,不知如何有效而正确的编码;第三则是知识量的不足,在编程时没有意识到实现会对哪些因素造成影响。

NoSQL走向成熟

| Comments

本文是InfoQ中文站2012年12月《架构师》刊首语。

在玛雅预言中的末世之年,整个IT业界却似乎可以用“波澜不惊”四个字来概括。没有惊天动地的大新闻来攫取眼球,对于媒体人而言,或许是一种不幸;但对于程序员,却可以减少太多技术选择带来的茫然。没有你方唱罢我登场的喧嚣,没有概念经济的浮夸与炒作,许多技术于是从绚烂归于平淡。

技术由绚烂归于平淡,并不意味着它将落伍于时代,退出历史舞台,而是大浪淘沙炼出真金,乃返璞归真的升华。业界颇有几种技术正是沿着这样的发展脉络不屈地前进,例如本期《架构师》专题讨论的技术NoSQL。

在MAC的IntelliJ下使用SBT与ScalaTest

| Comments

正如我们在Java项目中会使用Maven或Gradle作为构建工具一样,在Scala中,最为流行的构建非SBT莫属。在Mac下安装SBT其实很容易,你可以用Macports或者homebrew来安装,只需要敲一条命令即可。

port install sbt

或者:

brew install sbt

要在IntelliJ Idea下要使用SBT似乎也很简单,因为你可以直接在Idea中下载安装sbt的插件。这一点都不费功夫。但我现在希望sbt对依赖的管理,要能很好地集成到Idea中。就像gradle一样,我只需要在build.gradle脚本中添加:apply plugin: ‘idea’,就可以在命令行中运行gradle idea,然后就能更新IntelliJ中项目的依赖了。例如,我要在IntelliJ中的Scala项目中使用ScalaTest来写单元测试。为了获得该ScalaTest Repository,就可以在build.sbt中添加:

Tasking in TDD

| Comments

我和同事李彦辉今天结对实现了一个User Story,这个故事的需求在昨天已经讨论得比较清楚,其中一部分工作因为数据安全以及部署基础设施的原因,由澳洲的客户来实现完成。因此,我们的工作就变成为将消息propogate到指定的external queue。这事实上可以理解为两部分工作,第一是生成或组装Queue希望获得的消息,第二才是消息的propogation。

消息的获得大约要经历如下步骤。首先是通过GlobalCustomer的Id,获得对应的指定产品的ProductCustomer(可能包含多个)。由于GlobalCustomer与ProductCustomer之间存在多对多的关系,我们还需要根据获得的每个ProductCustomer,逆向反推出它所对应的GlobalCustomer(可能包含多个)。在得到ProductCustomer对应的GlobalCustomer后,再调用GetConsent的Web Service,获得每个GlobalCustomer对应的Consent信息。之后,再根据Consent信息中包含的某些Indicator值,运用业务规则,获得最终external queue需要的由indicator值以及客户的基本信息组成的消息。