乐趣区

关于架构设计:你的业务是可变的吗

请不要跟我说用 ES 或者其余,其实很多中小公司的业务就是如此,就是基于 mysql 或者 sqlserver 来搞这样的业务

业务场景

不晓得通过 D 妹子的论述,大家理解状况了没。这里菜菜再具体说一下。D 妹子的程序记录了订单的 log 来供其余业务(比方统计)应用,这里就以统计业务来说,OrderLog 表设计如下:

列名 数据类型 形容
OrderId nvarchar(100) 订单号,主键
UserId int 下单用户 id
Amount int 订单的金额
其余字段省略 …

除此之外还有一个用户信息表 UserInfo,设计如下:

列名 数据类型 形容
UserId int 用户 id, 主键
ProvinceId int 用户省的 id
CityId int 用户市的 id
CountyId int 用户区县的 id

波及到拆单等简单的订单操作,表的设计可能并非如此,然而不影响菜菜要说的事

变数的业务

当初如果要统计某个省的订单总数,sql 如下:

select count(0) from OrderLog o inner join UserInfo u on o.UserId=u.UserId where ProvinceId=@ProvinceId

有问题吗,sql 没问题,这时候用户 A 的省市区县信息忽然变了(兴许是在其余地区买房,户口迁徙了),也就是说 UserInfo 表里的信息变了,那用以上的 sql 统计用户 A 以前省市区县的订单信息是不是就会出错了呢?(产品狗说在哪下的订单就属于哪的订单)

业务的定位

以上的问题你感觉是不是很简略呢?只有略微批改一下表兴许就够了。然而,菜菜要说的不是针对这一个业务场景,而是所有的业务场景的设计。那你有没有想过为什么 D 妹子的设计会呈现这样的问题呢?

深刻理解业务能力防止以上相似的谬误产生,肯定要深刻理解不变和可变的业务点。拿 D 妹子的统计来说,你的业务是统计区域的订单数,这个业务在产品设计上定义的是不变性,也就是说在行为产生的那个工夫点就确定了业务性质,这个业务的性质不会随着其余变而变。具体到以后业务就是:用户在 X 省下的订单不会随着用户区域信息的变动而变动,说白了就是说用户在 X 省生成的订单永远属于 X 省。

谈到业务性质的不变性,对应的就有业务的可变性。如果你开发过相似于 QQ 空间这样的业务,那必定也做过相似访客的性能。当要显示访客记录的时候,访客的名称在少数状况的设计中属于可变性的业务。什么意思呢?也就是说一个用户批改了姓名,那所有显示这个用户拜访记录的的中央姓名都会同时扭转。

说到这里,各位再回头看一下 D 妹子的业务,这里又牵扯到一个零碎设计的问题,家喻户晓,一个好的零碎设计须要把业务的变动点形象提取进去,D 妹子订单统计的业务变动点在于用户的省市区县会变动,订单的金额、订单号等信息不会变动。所以你们感觉是不是 D 妹子的数据表能够批改一下呢?

数据表的改良

改良用户信息

依照以上的论述,D 妹子业务的变动点在于用户的省市区域信息,所以能够把用户信息的表形象提取进去, 主键不再是用户 id

列名 数据类型 形容
Id int 主键 Id,主键
UserId int 用户 id
ProvinceId int 用户省的 id
CityId int 用户市的 id
CountyId int 用户区县的 id

这样的话用户订单 log 表中就变为

列名 数据类型 形容
OrderId nvarchar(100) 订单号,主键
UserBId int 对应用户表中的主键 id
Amount int 订单的金额
其余字段省略 …

这样设计的话,如果用户的省市区县信息有变动,相应的用户信息表中会存在多条用户省市区县数据

这里的用户信息表并非是用户对象的主表,而是依据订单业务衍生进去的表

改良业务数据表

依据业务的变性和不变性,既然把订单区域统计的业务定义为不变的业务性质,那订单的 log 表齐全能够这样设计

列名 数据类型 形容
OrderId nvarchar(100) 订单号,主键
UserId int 下单用户 id
ProvinceId int 用户省的 id
CityId int 用户市的 id
CountyId int 用户区县的 id
Amount int 订单的金额
其余字段省略 …

写在最初

各位读到这里,可能会感觉菜菜这次写的其实很鸡肋,然而,D 妹子的场景却是实在环境中遇到的问题。问题的实质还是变性业务和非变性业务的定义和划分,和架构设计一样,数据库的设计其实也须要把变动的业务存储点进行形象,其实应该说是抽离进去。

心愿大家有所播种 – 菜菜

支付架构师进阶材料大礼包

退出移动版