可编程的软件服务

这些年,软件工程师的数量激增猛涨,越来越多的人,具备了用代码解决问题的能力了。这样的发展趋势,对软件行业本身也产生了一定的影响。下面我来列举三个例子:


其一,Racket 支持 “面向语言进行编程”(LOP),是一门 “可编程” 的编程语言。旨在解决使用特定语言编程的时候,eDSL 难集成的问题。语言,本来就是编程用的,语言本身也变成了可编程的,这是一件有趣的事情。


其二,Roslyn 不再是一个编译工具了,而是一个 “编译平台”(Compiler Platform)。因为它共享了编译器内部的工作机制,让世界以编程的方式消费。编译器,不再作为单独的一个工具提供服务了,而是变得更加开放了。


其三,“基础设施即代码”(IaC),它本来是随着 2006 年第二代 web 框架的潮流而出现的,当时人们正在考虑底层的计算资源,能否以按需计费的方式提供服务。基础设施不再使用人工配置的方式提供支持了,而是使用高级的编程语言进行控制


这三个例子,共同反映了一种新的潮流,现有软件行业内部的一些概念,正在朝着更加有利于编程的方式在发展了。这是全民编程能力提高之后,必然会发生的事情。下文我们就讨论一下,现阶段或者未来,我们应该如何转换想法,如何提供可编程的软件服务。

API 治理

对于一个成型的软件系统而言,人们看到的更多是它提供了哪些功能,而不是它的软件架构。但其实它内部的组成方式,以及怎样与外界进行交互,才是最容易被忽视的一点。软件架构是与组织架构密不可分的,康威定律 指出,

设计系统的架构受制于产生这些设计的组织的沟通结构。


不同形式的组织架构,就会衍生出不同的软件架构。合理架构的目的,正是为了降低研发成本,用最恰当的方式尽可能多的满足各方利益。《Clean Architecture》也指出了软件架构对于确定边界的重要性,

Software architecture is the art of drawing lines that I call boundaries.

Those boundaries separate software elements from one another, and restrict those on one side from knowing about those on the other.


所以,软件架构是真实世界的各方利益,投射到软件系统中的写照。好的架构形式,可以促进多方协作,避免不必要的争论。它将不太相关的部分,内聚到独立的子系统中,人们只需要关注系统间是如何交互的即可。


让依赖可追踪,是我对系统间依赖如何处理的个人体会。我曾参与过很多遗留系统的迁移工作,也曾亲身体会到了这样的迁移会带来的各种问题,称之为 “给飞机换引擎” 也不为过。一个遗留系统有哪些 api 被外部系统所使用是很难确定的,直接导致了我们对这些遗留系统的无能为力。所以让系统的所有依赖可被追踪,是一个美好的愿景。


有很多人已经这样做了,开放的 api 接口并不是直接暴露给用户,而是对这些 api 进行治理。当要依赖某一个 api 的时候,要先到某个管理系统中进行授权。这样做会有很多好处,一方面不会暴露出难以收回的接口,另一方面,这些接口的使用情况,也都一目了然了。

命令行接口

编程设计领域流传着一些 “警句”,称为《Epigrams in Programming》。其中,有一句是这样说的:一个优秀的系统,不能没有命令行接口,

A good system can’t have a weak command language.


命令行接口是面向程序的,而常见的图形界面是面向人的。一个系统如果只提供图形界面,那么就难以用程序的方式跟它进行交互,这会使得它自己变得封闭,无法纳入到一个更大的软件生态圈中。《Linux/Unix设计思想》也有这样的说法,

良好的程序员编写优秀代码,优秀的程序员借用优秀代码


能将其他软件模块、程序或配置文件,集成到自己的应用程序中,会成倍的放大前辈程序员们的工作成果,这就是软件的 “杠杆效应”。命令行接口,使得系统可以被当做软件杠杆来使用。


有很多系统是没有命令行接口的,或者反而是优先提供一种图形界面,与用户进行交互。这样做虽然能够降低用户(人)的使用成本,但也使得其他的程序无法与之对接。并且用户在图形界面上的操作很难聚拢和量化,也为后文的一切从数据出发的研发方式埋下了隐患。


但也并不是所有的系统都得这么做的,这是由不同的业务类型来决定的,即不同系统的用户群体是不同的。提供软件服务的系统,通常它的用户也是开发者,他们更喜欢用程序的方式,自动化的解决一些问题。这个时候早于图形界面,优先提供一种对程序友好的方式来提供功能,未尝不是一个更省时省力的性价比更高的做法。

一切从数据出发

重视数据是近几年才开始流行的趋势,在以前,人们的关键决策,更多的是依靠行业经验和敏锐的直觉所做出来的,这其实是有挺大风险的。数据导向的研发方式,起源于人们多年来在自然科学领域中的反复实践,这是一套称为科学方法 的寻求知识的过程,总共分为三个阶段,

  • 问题的认知与表述

  • 实验数据的收集

  • 假说的构成与测试

数据成了衡量一个系统的成效,以及后期做出优化的关键法宝了。所以,一切从数据出发,从一开始就打好基础,也就顺理成章的成了新系统的研发标准了。它可能转变了我们的研发方式,所追求的不仅仅是提供哪些功能,而是要把功能、效果的验证,当做一个整体来考虑了。


结合上文图形界面和命令行的讨论,似乎命令行接口与数据导向的开发方式可以不谋而合。我在一个业务团队中曾经使用这样的一个命令行工具,至今为止都觉得是一种很好的体验。日常工作中编译打包各项事务,都交给这个命令行工具来执行,必要时我可以编写 shell 脚本来调用这些操作。相比图形界面,我并不需要打开一个网页来完成自己的工作。更重要的是,日常研发活动的行为数据,都能够被这个命令行工具收集上去,真是一个很赞的想法。

平台

一个系统在产品形态上是否构成了平台,指的是它的用户能否帮助它提供功能。当然这件事是有利有弊的,平台显然更难管控。但是从规模上来看,平台则更容易发展壮大。毕竟一个人或者几个人的能力是有限的,有更多的用户参与进来,就相当于做了乘法,而不是现有的几个人做加法。


在没有其他制约因素的情况下,我更倾向于从平台视角考虑问题,尤其用户也是开发者的时候。使用系统的人与开发系统的人,具有天然的平权性,他们都是开发者,都可以用程序解决问题。这样一来,系统所能提供的服务,就变成可扩展的了,开发资源可以随着事项的紧急程度,在平台与用户之间重新分配。所以说,平台打破了需求方与实现方的单向关系,大家一视同仁的看待所有的问题。


但有些 “平台”,其实并不是按平台的方式来做的。指的是 “平台” 帮助用户实现了太多的功能,用户想帮忙也帮不上。所以,并不是说人们都来用一个系统,这个系统就称为平台了。而是要想想,在平台上能否看到用户的影子。一个比较切题的例子是 VSCode 的插件系统,仅仅依靠 VSCode 团队是不可能完成现今的海量插件的。他们依靠了整个开发者社区,依靠了用户的聪明才智。


在《程序员的呐喊》中,作者有一段对平台的讨论,十分的鞭辟入里,

没有平台的产品的是没有用的,缺少平台支持的产品肯定会被有平台支持的同等产品取代。Google+ 错误的以为 Facebook 之所以成功是因为人家做了一个好产品。但那并不是他们成功的原因。Facebook 之所以那么成功是因为他们通过让其他人参与进来的方式,搭建了一整套各异的产品。Facebook 上有成百上千种消磨时间的好去处,所以才能满足所有人。

结语

本文总结了自己对软件服务的一些理解,有些观点认识的还不够全面。但要表达的想法是,面向开发者提供的软件,与面向最终用户提供的软件,可以是两种不同的软件形式,也具有不同的业务属性。随着这些年开发者大军日益强大起来,人们对开发者服务的诉求,也可能会发生转变。