Skip to content

1.结果or异常

  • 对于新增/修改,返回结果需不需要数据结果,还是直接返回true? 这取决于业务系统操作的连续性,如果在一个前台页面有一系列完整的操作,返回数据更好.
  • 对于无法执行的操作,返回操作失败异常还是false? 最好是返回异常,利用Optional.orElseThrow()和全局异常处理,比如修改传入的ID是非法的.

2.数据安全权限

  • 业务数据操作 对于多租户系统而言,单一数据操作如果仅通过主键ID并不可靠,最好通过继承的方式将租户的ID都写入到具体的业务表,然后操作的时候增加该条件.
  • 用户信息 可以自定义一个用户上下文对象,方便取值. RBAC是一种基于角色控制权限的模型,这种模型理论上可以处理所有的权限问题,包括业务权限和数据权限.实际上其中存在一些细节问题. 业务权限简单理解就是 接口权限, 某个用户是否可以调用某个接口,比如新增A,修改B...,业务权限比较简单,元数据(接口地址\接口名称)注册后,很容易分配,直接在拦截器中根据用户请求上下文进行判断即可. 数据权限粒度更细,比如涉及到 分享 功能的业务系统,用户A分享给B的数据,对于B来说可能只有权限.这种情况下行级数据权限就不能简单的在一个地方处理了,实际处理中可能需要对SQL进行拦截处理亦或是对SQL进行拼接.

2.1 RBAC

业务权限

数据权限

增加数据应该按照业务权限处理,在数据还未产生的情况下,无法直接使用数据权限控制

一般而言 在 新增/查看/修改 权限的基础上,才可以 删除,逻辑删除可以理解为 一种特殊的修改

权限 一般建立在 增/查的基础上

分页查可能需要抽象 资源组的概念,对主键进行一对多关联,方便权限表存储.

  • 关联操作

关联操作涉及多个模型的情况下,最好直接从 最小粒度 进行控制,比如 模型A属于模型B的子模型,实际上一般可以直接理解 能够修改A即能够修改B,不过也可以分别 判断.

3.数据校验

都放是最可靠的,尤其是可能存在NPE的代码,因为service的method可能被多个地方调用.可使用Spring Validated完成校验.

4.分页查询/restful风格

对于restful风格的接口而言,可能需要get接口完成分页查询,对于条件不多的,可以用get和query param实现,后台分别用两个vo接收(pageVO/dataVO),对于条件较多的查询来说,get请求参数不够直观,可以使用post,仅将page信息放置于query param或 path param

5. 避免死代码

  1. 尽可能定义常量替代直接四处使用的值
  2. 利用占位符%s或{},复用这些常量
  3. 不确定/易变的常量配置化
  4. 避免使用+等直接操作字符串

6. 生命周期

在平时的代码开发中,经常需要对原有的业务逻辑进行扩展,所以往往需要在设计之初引入生命周期的概念 并结合适配器的设计模式能极大提高代码的扩展性

举个例子,如下接口LifeCycle,提供了beforeafter的默认实现,对于需要进行扩展的实现可以很容易进行操作, 同时不会影响已有的其它实现.

java
public interface LifeCycle<I,O> {
    default void before(Context context,I i){};
    default void after(Context context,I i){};
    O execute(Context context, I i);
}

7. 上下文

实际上上文中的Context即为 上下文对象,上下文的使用场景非常广泛,上下文目的在于提供业务逻辑全生命周期中都有可能用到其它数据

8. OpenMetadata设计和借鉴

资产元数据

比如DB,Table,Pipeline,Report,Message都可以被认为是资产,而对资产元数据的维护是数据治理的基础.

存储

使用mysql8(json)和es(资产检索),其中对于元数据表存储设计非常简洁,扩展性强,可以参考如下

  • table_entity: id,fullyQualifiedName,json,ts 其中json存具体的table属性
  • dbservice_entity: id,name,type,json,ts json存数据库连接等属性
  • entity_relationship来存储所有的关联关系 : fromId,toId,fromEntity,toEntity,relation,ts

ingest

它使用python来进行三方集成