填坑要诀:二、从小而精到大而全

这个小而精,在软件领域,也有其他类似的叫法,比如内聚、解耦,再比如SRP-单一职责原则等,大家都非常推崇或建议这个风格、规范、原则。

而这个大而全,一看就是大锅绘,一锅端这种类型,在软件领域是大家都非常不建议使用的。

但是,在现代软件架构中,往往架构层次或模块较多,如果在每个地方都是用小而精可能有一些其他方面的问题。

就举个我前两天的一个例子说明下。

运营要在端内搞个一个活动,为了和日本那边的新年元旦红白歌会相呼应。活动是这样设计的:

  1. 每个人可以加入红、白这两支队伍中的一个队伍
  2. 每个人可以做活动给自己的队伍增加年糕数目,年糕数目最多的队伍获胜

对于个人的数据,就包括自己是哪个队伍的,自己获得的年糕数目,在己方队伍中的排名等。

底层的存储采用的是redis,自己的队伍采用string的get、set(依赖用户id),排行榜直接用zset,这样年糕数目用zscore(依赖用户id和队伍id),排名用zrank(依赖用户id和队伍id),这样这三个数目在数据层就是三个操作。

到了service层,我也对应的写了三个方法。

到了web层,我也写了三个对应的接口。

这个时候,同前端同学对接的时候就有问题了,前端的首页就要展示如上这三个数据。

第一个问题来了,查询用户的年糕数目和排名能不能只传一个参数用户id,这样查询后面两个和队伍相关的数据时就不依赖于第一个请求的返回值。

第二个问题来了,即便修改后,这三个请求互相独立,但是仍然要请求三次,特别是首页这个页面,访问量会多,能不能合成一个。

所以,最终的结果,我把首页所有请求的数据写成了一个接口返回。

上面这个例子只是工作中非常小的一块,实际工作中,可能遇到更复杂、更多变的需求,这个时候,就需要对接口的粒度进行设计和考量了,是用小而精,还是大而全呢?

根据我的经验,越靠近底层,越要小而精,越靠近用户,可以大而全。

对于设计良好的架构或代码,底层改动基本很小,采用小而精,可以使代码更简单,同时可以更好的支持上层服务的调用。比如上面的例子中,在数据层,就采用小而精的设计,对redis的每个操作都独立,同时对service层可见。

对于靠近用户的一侧,是变化较多的,可以采用大而全的设计,简化交互流程和细节。比如上面的例子中,直面用户的web层就需要对接口做这种大而全的设计。

那对于中间层呢?比如上面例子中的service层,该采用怎样的策略? 我是这样认为的,service层,必须要提供小而精的接口,这样调用方可以精确控制。同时,可以根据业务情况或需求,提供部分大而全的接口,这样也方便调用方处理。


最后修改于 2019-01-16