业务代码抽象原则

模块内聚

把具有强关联性的业务逻辑放在一个模块叫功能性内聚,功能性内聚被认为是最佳实践。不论如何聚合,我们还是会看到很多对象会跟其他的对象发生关联,形成了一个复杂的关系网,不论是一对一、一对多还是多对多。来自模型的挑战常常不是让它们尽量完整,而是让它们尽量地简单和容易理解。这意味着,除非直到模型中嵌入了对领域的深层理解,否则大多数时候需要对模型中的关系进行消减和简化。 首先,要删除模型中非基本的关联关系。它们可能在领域中是存在的,但它们在我们的模型中不是必要的,所以我们要删除它们。其次,可以通过添加约束的方式来减少多重性。如果很多对象满足一种关系,那么在这个关系上加入正确的约束之后,很有可能只有一个对象会继续满足这种关系。第三,很多时候双向关联可以被转换成非双向的关联。

分层架构

底层是细粒度的服务,上层聚合下层服务。当上层需要聚合的服务在多个模块(团队)时,我们还是本着领域划分的原则,谁的领域知识是最重要的或者说占比最多的,那么这个就该谁聚合。下面是主流的分层方案,供大家参考:

  1. 展示层:向用户展示软件的功能和信息
  2. 应用层:应用的逻辑的协调,不包含业务逻辑和业务对象的状态,包含会话的上下文
  3. 领域层:核心业务逻辑,业务对象状态保持,包含完整的领域信息
  4. 基础层:实体对象的持久化,公用库,基础服务

服务接口原则

  1. 读与写操作都尽可能保证接口幂等性,对于写操作,利用乐观锁解决并发的问题。
  2. 接口要尽可能可以降级。
  3. 需求确定之后,接口和数据模型先行,协议和字段需要在Java Doc和Swagger API Docs中详细描述。
  4. 领域层接口先从一个较大的服务边界开始,然后随着时间推移基于业务需求来重构成更小的接口。我们应该关注微服务的范围,而不是一味的把服务做小。一个服务的(正确的)大小应该等于满足某个特定业务能力所需要的大小。他们应该是内聚而完整的。
  5. 接口需要向下兼容,因此接口应当都带上版本号,如果底层的数据接口发生了颠覆性变化,要充分考虑老版本接口问题,特别是C端产品。
  6. 接口要尽量保证无状态,如果的确有状态,可以按状态划分为多个接口。
  7. 不能过度抽象接口,例如public Map query(Map map)这类接口,维护和使用都非常困难。但是也不能不抽象,否则接口数会暴增,随着业务的稳定,有必要抽象合并。