现如今后台服务大部分以微服务的形式存在,每个微服务负责实现应用的一个功能模块。而微服务是由一个个接口组成,每个接口实现某个功能模块下的子功能。
以一个IM应用为例,那么它的功能架构可能是下面这样的。
所以如果是后台开发的同学,经常需要实现一个后台微服务来提供相应的功能。
服务是以接口的形式提供服务,在实现服务时,我们要将一个大的功能拆分成一个个独立的子功能来实现,每一个子功能就是我们要在服务中实现的一个接口。 有时一个服务会有很多接口,每个接口所要实现的功能可能会有关联,那么这就非常考验设计服务接口的功底,让服务变得简单可靠。
业界已经有很多比较成熟的实践原则,可以帮助我们设计实现出一个可靠易维护的服务。
服务接口设计原则并没有严格的规范,下面介绍个人认为最为重要的几个原则。
每个API接口应该只专注一件事。
这样会让接口的功能单一,实现起来简单,维护起来容易,降低了接口因功能冗杂而出错的概率。
不是随便一个功能就要有个接口。
虽然一个接口应该只专注一件事,但并不是每一个功能都要新建一个接口。要有充分的理由和考虑,即这个接口的存在是十分有意义和价值的。无意义的接口不仅增加了维护的难度,更重要是对于程序的可控性的大大降低,接口也会十分臃肿。
相关功能我们应该考虑合成为一个接口来实现。
一个接口要包含完整的业务功能,而不同接口之间的关联要尽可能的小。
这样便降低了对其他接口的依赖程度,如此其他接口的变动对当前接口的影响也会降低。一般都是通过消息中间件 MQ 来完成接口之间的耦合。
指对扩展开放,对修改关闭。
这句话怎么理解呢,也就是说,我们在设计一个接口的时候,应当使这个接口可以在不被修改的前提下被扩展,换句话说就是,应当可以在不修改源代码的情况下改变这个接口的行为。
比如 IM 应用中,当用户输入用户简介时有个长度限制,我们不应该将长度限制写死在代码,可以通过配置文件的方式来动态扩展,这就做到了对扩展开放(用户简介长度可以变更),对修改关闭(不需要修改代码)。
我们应该尽可能地使微服务是一个无状态的服务。
状态即数据。如果某一调用方的请求一定要落到某一后台节点,使用服务在本地缓存的数据(状态),那么这个服务就是有状态的服务。
我们以前在本地内存中建立的数据缓存、Session缓存,到现在的微服务架构中就应该把这些数据迁移到分布式缓存中存储,让业务服务变成一个无状态的计算节点。迁移后,就可以做到按需动态伸缩,微服务应用在运行时动态增删节点,就不再需要考虑缓存数据如何同步的问题。
接口要具备统一的命名规范、统一的出入参风格、统一的异常处理流程、统一的错误码定义、统一的版本规范等。
统一规范的接口有很多优点,自解释、易学习,难误用,易维护等。
可靠性只有靠不断追求最大程度的简化而得到。
乏味是一种美德。与生活中的其他东西不同,对于软件而言,“乏味”实际上是非常正面的态度。我们不想要自发性的和有趣的程序;我们希望这些程序按设计执行,可以预见性地完成商业目标。与侦探小说不同,缺少刺激、悬念和困惑是源代码的理想特征。
因为工程师也是人,他们经常对于自己编写的代码形成一种情感依附,这些冲突在大规模清理源代码的时候并不少见。一些人可能会提出抗议,“如果我们以后需要这个代码怎么办?”,“我们为什么不只是把这些代码注释掉,这样稍后再使用它的时候会更容易。”,“为什么不增加一个功能开关?”,这些都是糟糕的建议。源代码控制系统中的更改反转很容易,数百行的注释代码则会造成干扰和混乱;那些由于功能开关没有启用而没有被执行的代码,就像一个定时炸弹等待爆炸。极端地说,当你指望一个Web服务7*24可以用时,某种程度上,每一行新代码都是负担。
法国诗人Antoine de Saint-Exupéry曾写道,“不是在不能添加更多的时候,而是没有什么可以去掉的时候,才能达到完美”。这个原则同样适用于软件的设计和构建。API设计是这个规则应该被遵循的一个清晰的例子。书写一个明确的、简单的API是接口可靠的保证。我们向API消费者提供的方法和参数越少,这些API就越容易理解。在软件工程上,少就是多!一个很小的,很简单的API通常也是一个对问题深刻理解的标志。
软件的简单性是可靠性的前提条件。当我们考虑如何简化一个给定的任务的每一步时,我们并不是在偷懒。相反,我们是在明确实际上要完成的任务是什么,以及如何容易地做到。我们对新功能说“不”的时候,不是在限制创新,而是在保持环境整洁,以免分心。这样我们可以持续关注创新,并且可以进行真正的工程工作。
[1] CSDN.服务API设计 之 API设计原则 [2] 知乎.怎么理解软件设计中的开闭原则? [3] 微服务的4个设计原则和19个解决方案