一种API代码结构的设计思路

来源:互联网 发布:网络诽谤罪的处罚 编辑:程序博客网 时间:2024/04/30 20:17

Prologue

在写API的过程中有这样三种产物

  • 文档

    几乎没人爱写文档,写了也懒得维护。可是同时API的文档对于其他程序员来说又是赖以生存的必需品。因此大家对文档都是爱恨交加,恨自己要维护文档,爱别人写好的漂亮文档;恨别人的烂文档错文档,爱自己随便乱写乃至不写文档。

  • 操场

    比文档更高一个层次的奢侈品,不用写代码简单点点或者repl形式马上就能探索接口的行为。不像仅对别人,操场的存在对自己开发接口也是很有帮助的。

    没操场的时候,大家往往人肉建一个文件当操场用,在里面各种玩API,但使着编译型语言的兄弟们没那么好运,他们更需要有操场。

    当然如果实践TDD或BDD的话,用例大概能代替操场一部分的作用,但这只对写接口的人管用。对调用接口的人来说,操场的作用是难以取代的。

  • 字段校验逻辑

    自己写接口的时候必须要做的事情。没做那是100%bug。

想想这三个产物的共同特点是什么?插入一段广告,哦不,我先把他们捏成一张表

 别人的接口自己的接口文档没有会死没用,不想写操场超级提升幸福感想用,懒得写字段校验不太关心必须写

他们的共同特点是均源自接口输入的schema

大家为啥不喜欢写文档?为啥懒得实现操场?我觉得很可能源自程序员的直觉。程序员天生讨厌重复,他们知道重复意味着修改的时候要同步维护,意味着大量重复的劳动和不同步带来的各种巨坑,Duplicate Is EvilDUPLICATE IS EVIL

换个角度说,怎么诱使程序员乖乖地写文档呢?首先利诱“写文档的话送你个操场玩玩”,然后威逼“反正你也得校验字段,咱们校验字段的方式就是写文档”,最后再给个枣子“这文档不用维护,以后改程序的同时文档自动一起改”

前言到此为止,结论只有一个:

我们要让文档、操场、字段校验三位一体!让不写文档比写文档难!让所有接口都有100%准确的文档和操场!消灭天下没文档的接口!消灭一切和实际接口不符的文档!

具体实现的思路其实刚才已经偷偷提到了,那就是聚焦接口的输入schema,以schema作为数据源,文档、操场、字段校验是schema的3种不同的应用。所以我们要构建的就是 a)meta-schema,即如何定义schema b)如何通过schema生成3种不同的产物。

Meta-Schema

程序员做事大体上有两种选择:找现成的轮子削成方的来用或自己造个方的轮子。我们想要的轮子“方”在哪里呢?嗯,schema大家都拿来做校验,但我们希望不仅能校验,还能生成文档和操场,也就是说希望它能够内嵌一些描述文字,最好校验规则也能轻松转换成文字展示。

自己造轮子的话,下面是一个基本的结构可以参考

class Schema {    string uri;//接口位置/调用时的名称/url等    string name;//接口中文名    string desc;//说明    array fields;//接口字段}class Field {    string key;//字段key    string desc;//说明    bool required;//是否必填    array constraints;//字段约束}class Constraint {    bool check(value);//校验    string describe();//描述}//Constraint常见的子类有:类型校验,长度/范围校验,正则校验等

找轮子的话,我用过json-schema做这一块,能用,很多语言都有校验的实现,还有类似json-editor这样的web editor实现,操场比较好搞。大体上能内嵌说明文字,各种语言都有良好实现,数据结构清晰容易导入导出的schema项目都可以用。

DSL for Meta-Schema

“好麻烦,我还是if if if吧”

只有schema还不够,你会需要负责教会所有同事一门新手艺,这可能将我们的努力毁于一旦,自己用起来也不爽。我们要的是DSL,要IDE的代码提示,要code-as-configuration。

怎么实现DSL超出本文范围,有机会我会再写这方面的东西,js的话大概300行代码就能实现类似这样的dsl了

    legate().define        .name('测试接口')        .desc('演示API用的测试接口')        .cmd('test')        .param            .int('num', '一个数字', [3, 100])            .string('str', '字符串', [2, 5])            .regex('reg', '有追求的字符串', /a.+b/)        .endParam        .logic(function(param) {            return {                result: 'from remote',                param: param            };        })    .endDefine    .mount(legateServer);

有了DSL,基本上已经可以宣告不写文档比写文档难了,下面要给按我们的meta-schema做事的乖孩子说好的三大产物。

显灵

其实原本写到这里就可以收笔了,因为定义好了数据结构,写写视图对程序员来说实在没啥挑战,不是么?

文档就是

loop schemas schema  show schema  loop schema.fields field    show field

操场就是文档套上

<form target="result"></form><iframe id="result">

校验就是

loop schema.fields field  if no $data[field]    if field.required      BIG-BANG!    else      continue  loop field.constraints constraint    constraint.check $data[field]

啊,不小心还顺便实现了分发或者说路由呢

loop schemas schema  if $request match schema.uri    return run schema, $requestNOT-FOUND!

是不是根本停不下来?

另一个好消息是,这个思路下各种其他开源项目都很容易拿过来套上,比如之前提过的json-schema和json-editor,比如最近的swagger.io等等,只要把握住核心是schema,操场/文档/校验逻辑等都是schema的视图,世界便尽在我们的掌握之中。

附《The Pragmatic Programmer》中的相关tips

[11] Don't Repeat Yourself
[12] Make It Easy to Reuse
[17] Program Close to the Problem domain
[68] Build Documentation In, Don't Bolt It On


转载自 http://press.mcfog.wang/2015/02/my-api-programming-style/
前情回顾 如何编写API的文档?

0 0
原创粉丝点击