• 2016-05-23

    Moco 0.11.0发布

    Tag:moco

    前版信息:Moco 0.10.2发布

    我很高兴地宣布,Moco 0.11.0发布了。

    Moco是什么?

    Moco是一个可以轻松搭建测试服务器的框架/工具/程序库。

    变更

    本次发布主要增加了两个大的特性:REST API 和 JUnit 集成。

    众所周知,REST 服务几乎已经成了现代服务端开发的标配。为了简化 REST API 的模拟,Moco 专门提供了特定的 API,比如,下面这个例子:

    RestServer server = restServer(port, log());
    ResourceObject resource = new ResourceObject();
    resource.code = 1;
    resource.message = "hello";

    server.resource("targets",
        get("1").response(toJson(resource))
    );

    RestServer 的 resource 方法是为配置资源而设计的,主要配置资源的名字,以及访问的设置。这里的例子里,我们声明了一个名为 targets 的资源,我们还配置了一个 get 方法,当资源 ID 为1时,返回相应的对象。这个配置可以通过 /targets/1 访问得到。

    REST API 同样支持 JSON 配置文件,上面的例子用 JSON 配置文件的形式可以写成如下格式:

    [
    "resource": {
      "name": "targets",
      "get": [
        {
          "id": "1",
          "response": {
            "json": {
              "code": 1,
              "message": "foo"
            }
          }
        }
      ]
    }
    ]

    访问 REST API 的文档可以了解更多细节。

    Moco 的 JUnit 集成是利用 JUnit 的特性,进一步简化测试代码的编写。

    public class MocoJunitJsonHttpRunnerTest {
        @Rule
        public MocoJunitRunner runner = MocoJunitRunner.jsonHttpRunner(12306, "foo.json");

        @Test
        public void should_return_expected_message() throws IOException {
            Content content = Request.Get("http://localhost:12306").execute().returnContent();
            assertThat(content.asString(), is("foo"));
        }
    }

    这里声明了一个 JUnit 的规则(Rule),它会在测试运行之前启动一个 Moco 服务器,在测试运行完毕之后关闭它。利用 Rule 的特性,就不必在每个测试里去启停 Moco 服务器了。

    更多发布相关信息,请参考 Release Notes

  • 2015-09-05

    Moco 0.10.2发布

    Tag:moco

    前版信息:Moco 0.10.1发布

    我很高兴地宣布,Moco 0.10.2发布了。

    Moco是什么?

    Moco是一个可以轻松搭建测试服务器的框架/工具/程序库。

    变更

    本次发布主要是一些API的增强和内部细节的改进。

    对于json的Java API增加了对于普通Java对象的支持。这样一来,我们就可以通过编写普通的Java对象,让它自动转换成对应的json。比如,下面的代码是对请求的支持:

      server.request(json(pojo)).response("foo");

    应答的支持是这样的:

      server.request(by(uri("/json"))).response(toJson(pojo));

    因为这个普通Java对象到json的自动转换是由Jackson实现的,所以,这里的对象类需要按照Jackson的方式进行声明,比如,下面是一个例子:

      public class PlainA {
        public int code;
        public String message;
      }

    更多Jackson的用法,可以参考Jackson的文档

    另外,本次的API增强还包括了对于redirect的模板支持,这样,redirect的API就可以实现更强大的跳转效果:

      server.redirectTo(template("${var}", "var", "http://github.com"));

    更多发布相关信息,请参考Release Notes

  • 这是我在知乎上的一篇回帖:

    要是写代码 写到三十岁没升到管理怎么办啊?

    我每天还在写代码,与人讨论技术实现细节,35岁那年,我写的Moco拿了Oracle的Duke选择奖。

    思维误区

    我还没开始工作的时候,有人就在说:程序员能做到30岁吗?
    我快到30岁时,有人在问:35岁还能做程序员吗?
    过了35之后,我已经看到了新的讨论:40岁程序员怎么办?
    估计10年之后,新的讨论会是:程序员50岁以后的职业发展是什么样子的。

    这反映了一个重要的事实,程序员是中国的一个新兴职业,发展时间还不够长。当时间逐渐拉长,越来越多大龄程序员就会出现。

    写代码和做管理

    如果你热爱写代码,那就去写。但是,这里必须知道一个前提,写代码和写代码是不一样的。

    以现在的普遍情况看,20多岁的程序员大多属于初出茅庐,写代码大多是以完成功能为主,而到了30多岁,写程序大约十年左右,需要考虑的方方面面必然要更多,比如,这个需求是否合理,从架构层面会造成什么样的影响,是否能找到更简洁的解决方案,这个代码写出来别人是否容易理解等等。

    30岁之后,精力会下降,这是生理决定的,如果这时候还和年轻人比拼堆代码的速度,靠加班熬夜,那必然是输了。而且,这种做法始终在低水平徘徊,自己做时间长了也会心生厌倦,所以,这不是一个可持续的模式。

    很多人想30岁就做管理,可是,哪有那么多人让你管理啊!为什么之前有那么多少年得志的故事?还是前面的那个逻辑,之前做的人少,所以,机会多。现在IT行业的人才积累已经达到了相当的规模,机会就会减少。当然,投身创业公司是另外一个选择,但前提是这个创业公司能做起来。不过,即便是有机会,为什么是你?

    不管做什么,自己有本事才是前提。

    成长之路

    以我个人的成长经验来看,不断地和更高水平的人过招,是保证成长的前提。

    初入职场,我也以为自己的成长路径会是写几年程序,然后,做管理。很幸运的是,在职业生涯之初,我遇到一个水平很高的人,他让我看到了一种心生向往的状态,于是,我就下定决心,成为一个优秀的程序员。更为幸运的是,我们俩成了很好的朋友,十几年下来,每当我进步了一些,他却又在我前面更远的地方。虽然我们做的领域截然不同,但从他身上得到的启发却一直激励我前进,比如,看到了他做的一个东西,我便下定决心有一个自己的代表作,这就是后来的Moco。如今,他年近40,依然是各大公司争相高薪邀请的人,而我知道,有他在前面奔跑,我就不能停下来。

    加入ThoughtWorks的选择,也是为了与高手过招。2007年加入时,那里汇聚了当时我听说过的许多牛人,后来,还有机会和Martin Fowler这样的大师请教问题。在ThoughtWorks工作的八年,让我打开了自己的眼界,能够更加虚心地向更多高手学习,得到了个人全方位的综合提高。

    就发展而言,如果身边没有高手怎么办?那就去找一个能和高手近距离过招的地方。

    不过,这里说的并不等价于大公司。大公司里固然有很多高手,但问题是你有多少机会和这些人一起工作。比如,我们知道Jeff Dean很厉害,但加入Google就能和他一起工作吗?所以,比起在哪里工作,和什么样的人在一起工作会更重要。

    从正常选择公司的方式来说,面试是一个了解公司、了解团队的机会。如果负责招聘的人会和你一起工作,那就可以好好考察一番。如果不是,那一定要尝试见见团队,最重要的是,见见团队里的高手。如果这个高手的状态不能让你羡慕,那他就不是你的目标。

    当然,有了高手,如何成长,那就是每个人自己的事情了。

  • 2015-05-12

    Moco 0.10.1发布

    Tag:moco

    前版信息:Moco 0.10.0发布

    我很高兴地宣布,Moco 0.10.1发布了。

    Moco是什么?

    Moco是一个可以轻松搭建测试服务器的框架/工具/程序库。

    变更

    本次发布对使用Java API的用户最大影响在于,原来的httpserver已经废弃了,推荐使用httpServer。

        HttpServer server = httpServer(12306);

    另外一个废弃掉的API是没有TimeUnit的latency,推荐使用有时间单位的latency接口。

        server.response(latency(1, TimeUnit.SECONDS));

    以上废弃的API将会在下一次发布中移除,请尽早更新。

    接下来,比较大的变动是增加了字符集,file和pathResource都可以进行字符集的处理。

        server.response(file("gbk.response", Charset.forName("GBK")));

    甚至,日志也指定对应的字符集:

        HttpServer server = httpServer(port(), log("path.log", Charset.forName("UTF-8")));

    模板在原来对内容处理的基础上,增加了对文件名的处理:

        server.response(file(template("${var}.response", "var", "foo")));

    这样一来,你可以把更多模板的特性用在文件名上,比如jsonPath、xpath等,也就是说,可以把不同请求应答的结果,放到不同的文件里。当然,你可以把它用在JSON配置文件里:

    [
      {
        "response":
        {
          "file":
          {
            "name": {
              "template": {
                "with" : "${var}.response",
                "vars" : {
                  "var" : "foo"
                }
              }
            }
          }
        }
      }
    ]

    这次发布还有一个针对于JSON API的调整,就是现在可以mount的时候,额外增加应答配置,比如像下面这样:

    [
      {
        "mount" :
        {
          "dir" : "src/test/resources/mount",
          "uri" : "/mount-response",
          "headers" : {
            "Content-Type" : "text/plain"
          }
        }
      }
    ]

    还有一个针对全局配置的特性,就是配置全局Request,如果你想实现一个全局token,保证每次请求都带过来,现在,就不必在每个请求上编写,只要配置一个全局的就好了:

    [
      {
        "request" : {
          "headers" : {
            "foo" : "bar"
          }
        },
        "include": "blah.json"
      }
    ]

    还有一个实现细节方面的调整,如果在模板里采用了xpath或jsonpath,可能会返回多个值,可以参考freemarker的文档编写对多值对象的处理。

    更多发布相关信息,请参考Release Notes

  • 2015-03-29

    开始新旅程

    离开ThoughtWorks,已经有一个星期了。

    我在ThoughtWorks待了八年,ThoughtWorks中国区从三十多人成长到五百多人,办公室由一个变成了五个,第六个也很快就要开了。八年里,我做了许多项目,面对过形形色色的人:交付或是咨询,国内或是海外。我也随着这个公司逐渐成长,曾经的我只是一个窝在角落里只知道写代码的程序员,到如今,有了更强大的内心,有了属于自己的独立思考,有了更宽的视野:

    • 我做出了郑大晔校,给毕业生提供一些入门培训,“帮助他人成长”成了我在ThoughtWorks技术之外的最重要个人标签;
    • 开启了常规性校园活动的先河,给新的ThoughtWorker一个展示自己的舞台,也搭起公司与学校之间的桥梁,间接造成了校园招聘简历数量不断增长;
    • 推动起技术大会,给了那些只知道坐在自己办公室里ThoughtWorker们有了一个跨越办公室思考的机会;
    • 参与了西安和成都两个办公室的建立,成为了一个拓荒者,也为两个办公室培养了一些中坚力量;
    • 当然,还有我的Moco,一些不期而至的鼓励给了我些虚名,也让我越发相信坚持的力量。

    八年里,我经历了自己许多的人生阶段,结婚生子,从一个傻小子变成了需要关心另一个傻小子成长的人父。

    八年的时间,我的身上已经留下深深的ThoughtWorks烙印,我已经习惯了称自己为一个“ThoughtWorker”。对我来说,ThoughtWorks几乎就是我的另一个家,那个家里有的是不只是同事,也许,还是亲人。

    但是,我还是选择了离开。

    ThoughtWorks是鼓励一个人不断成长的,不断跳出自己的舒适区。随着在一个地方待的时间越来越长,那些曾经的挑战就变得没那么复杂,我越来越舒服。即便是在其他人看来压力颇大的一些项目,我都可以和客户谈笑风生,让客户包容我们团队做得欠佳的地方。但这种舒服让我的内心越来越不安,因为那几乎意味着我没有任何成长,我担心的不是自己的今天,而是未来。

    创新,是在ThoughtWorks这几年里不断在提的另一个话题。我也刚好有了一个创新的机会:Moco,它在最近两年多的时间里,由我的一个小玩具变成给许多人提供帮助的开源项目。Moco让我看到了创新的价值,给其他人带来的一些改变。我希望自己能够再有机会做一些别人没做,或是别人没做好的事情。在我看来,这是做开发里最有趣的部分,也是我当年投身软件开发行业的初衷所在。

    如今创业成了主旋律,大环境向好,我的一些朋友纷纷离开自己的熟悉领域,投身到创业大潮中。一些朋友与我交流了他们要做或是在做的事情,ThoughtWorks教会了我如何把事情做好,所以,我也难免好为人师地多嘴两句,给出一些自己的看法,一来二去,越聊越深,朋友们给出了邀约,而我也动了心思。

    最终,我决定离开ThoughtWorks,成为创业大军的一员,去做一些我认为与众不同的事情。这会是一段不同于以往的经历,我选择了一个自己完全不熟悉的领域,在未来一段时间内,我唯有不断学习,才能让自己适应新的环境。

    生命不息,折腾不止,加油!