原生优先
在写自定义代码去做某件事之前,先确认平台是不是已经能做到这件事。这不是风格上的偏好选择。它会直接影响你的构建运行起来要花多少成本、能不能安全地迁移,以及日后别人理解它有多容易。
一句话讲清这个道理
如果一个人能够指着某项能力、把它说成平台的一项功能,那么这项能力几乎肯定已经内置在平台里了。你自己用自定义代码把它重新做一遍,会把它的实际作用藏到一段别人必须去读的代码背后,还往往会随着平台演进而逐渐落伍过时,而且很多时候最终还需要一个内置方式原本根本用不到的登录凭证。
平台开箱即用通常已经提供了什么
这一类可正常运行的平台,出厂就自带大量现成的能力:读写结构化记录、通过常用渠道发送邮件和聊天消息、日历、电子表格、文件存储、处理传入的文档、暂停一个流程以等待人来处理、从一个流程调用另一个流程、在流程内部做路由和循环,以及干净地终止一次运行。与各类账户和其他系统的连接,都保存在平台自身的连接存储中——配置一次,由构建引用,绝不会被带进构建自己的逻辑里。
在写下第一行自定义代码之前,值得先查一查平台当前的能力清单,看看有没有现成的东西已经能完成这项工作。新的能力会不断持续上线,最安全的默认做法永远是先查看、再动手构建。
什么时候自定义代码才真正站得住脚
以下两件事必须同时成立:
- 没有任何内置能力能完成这项工作,而且你能具体说出自己查过什么、为什么那些都不够用。
- 这段代码是纯粹的——它只对拿到手的值进行计算,本身不会带着自己的凭证去调用另一个系统。如果它确实需要触达另一个系统,也要通过平台自身的某个连接去做,而不是靠代码里嵌的一个密钥。
任何偏离原生优先原则的例外情况,都应该被明明白白地记录下来:考虑过什么、为什么没有采用,以及将来要满足什么条件才能让这段自定义代码退役。把这种例外当作一项临时的、有名有姓的债务来对待,而不是一个悄悄变成永久的选择——一旦平台上线了能做同样工作的内置方式,就立刻让它退役。
为什么这件事比听起来更重要
- 构建里的任何东西都不应该保存凭证。 一个只使用平台自身连接的构建,不包含任何登录信息、任何 API 密钥,任何这类东西都没有。这意味着这个构建本身可以被安全地分享、导出,或者迁移到另一个账户——里面没有任何东西需要被轮换、被脱敏或者让人担心。
- 一个使用内置能力构建出来的东西,非开发人员也能读懂。 他们可以打开它,一步一步地看到每个部分在做什么,根本不需要打开任何代码。自定义代码则会把这一切藏到一堵只有开发人员才能读懂的墙后面。
- 它经得起迁移。 把一个完全用内置能力构建出来的东西导出到另一个账户,不需要任何重新接线。一个把凭证写死在里面的构建则会失效——更糟的情况是,它悄悄地继续运行,用的却是错误账户的权限。像 Gmail 这样使用服务商登录的连接,由有权限的人在每个账户上完成一次授权即可;邮件服务器(SMTP)连接则是用服务器信息配置一次即可。
好的样子是什么
- 这个构建在平台自身的视图里,能够一步步读下去,不需要打开任何代码就能看懂。
- 在构建的逻辑里搜索任何凭证类的东西,结果什么都搜不到。
- 如果有自定义代码,每一段都附有一条说明,写明考虑过哪项内置能力、为什么它不够用。
- 把这个构建迁移到另一个账户,不会改变它的任何行为。
一个实际例子
以一个报价助手为例:发送完成后的文档完全不需要任何自定义代码——读取记录、按状态路由、格式化日期、发送邮件、更新记录,这些步骤全部都是内置的。审批环节的做法也是一样,用一个内置任务暂停流程、等人做出决定,然后自己接着往下走,把文档发出去。自定义代码通常只局限于少数几件事:算术运算、一次数据库查询、一次最终核查,以及文档本身的排版。