写点什么

论“万剑归宗”思想对开发设计的一点“肤浅”作用

用户头像
八苦-瞿昙
关注
发布于: 2020 年 11 月 25 日
论“万剑归宗”思想对开发设计的一点“肤浅”作用

为什么叫“万剑归宗”?

这里有一个富含仙侠中二气息的霸气名字:“万剑归宗

这其实只是为了忽悠大家注意力而故意取得名字,

实际上就是

我们不用学术性的严谨讲法去阐述这些概念,

毕竟我也就是个数学的战 5 渣,说也说不清楚

先入为主误区思维举例

下面我们先举个真实案例(具体业务内容有所调整)来阐述先入为主的误区

导致看起来没毛病却实际上不好用挺麻烦的情况


有类似这样一个业务:

为了吸引用户,业务部门打算推出像任天堂的 switch 账号可以一台机器关联多个不同账号且能共享游戏使用权一样的福利,

让原本美国,中国,加拿大三个国家不同子站点不同账号管理机制下分开的会员合并在一起,让任意一个国家账号开通了会员,玩家其他国家账号同样享有相等的会员权力,

至于玩家关联的账号提供通道给玩家自己关联

ps:这里的例子,请大家先忽略为什么不让三个国家都能使用同一个账号这么明显最简单的解决方案,就当这是锁区或者前人留下的一动要炸掉整个系统的不可抗力因素


业务需求分析

  1. 美国,中国,加拿大 三个国家三个不同账号,

  2. 本来业务上所有账号都不会有同名存在,也就是一个账号是唯一,即使不同国家也不允许相同

  3. 一个玩家可以有 1 个或多个账号

  4. 一个玩家可以有 0 个或 1 个会员

  5. 一个会员可以在美国,中国,加拿大 三个国家都起作用

  6. 需要保存新的账号关联关系

总结:核心问题在于实现保存账号关联关系


朴实无华的设计

这时候小白同学已经明白了一切根本焦点 保存账号关联关系,

就开始了朴实无华的设计思考:

  1. 我们需要一段关系记录来记录一个玩家的账号关系,

所以新增 表 [PlayerMapping] 来保存

  1. 一个玩家一段关系一条记录数据少,看起来简单,找起来方便

  2. 多个国家,嗯,现在三个国家三个字段,简单明了

  3. 嗯,这样看来,没有多个账号 mapping,mapping 表也不需要写数据

  4. 会员表原来就会记录哪个账号是会员,join 一下 mapping 表,就可以拿到玩家所有的会员账号了,简单


最后 PlayerMapping 表就是这样

| id | USAPlayer | ChinaPlayer | CANPlayer |

| ----| ---- | ---- | ---- |

| 1 | Gold | Shen | girl |

| 2 | Gddd | Sddd | null |


看起来好像也没啥大问题,虽然感觉要新加国家会加字段这点非常别扭

实际使用

这里为了简单,就只举 sql 伪码的两个例子说明:

新增 mapping 关系

IF not EXISTS(select top 1 1 from [dbo].[PlayerMapping] C WITH(NOLOCK)ON c.USAPlayer   = @Player OR c.ChinaPlayer     = @Player OR c.CANPlayer   = @Player)BEGIN
insert into [dbo].[PlayerMapping] ( USAPlayer ,ChinaPlayer ,CANPlayer ) select CASE when @Country = 'USA' then @Player when @MappingCountry = 'USA' then @MappingPlayer else null end, CASE when @Country = 'China' then @Player when @MappingCountry = 'China' then @MappingPlayer else null end, CASE when @Country = 'CAN' then @Player when @MappingCountry = 'CAN' then @MappingPlayer else null end
else UPDATE c set c.USAPlayer = CASE when @Country = 'USA' then @Player when @MappingCountry = 'USA' then @MappingPlayer else c.USAPlayer end, c.ChinaPlayer= CASE when @Country = 'China' then @Player when @MappingCountry = 'China' then @MappingPlayer else c.ChinaPlayer end, c.CANPlayer = CASE when @Country = 'CAN' then @Player when @MappingCountry = 'CAN' then @MappingPlayer else c.CANPlayer end from [dbo].[PlayerMapping] c where c.USAPlayer = @Player OR c.ChinaPlayer = @Player OR c.CANPlayer = @Playerend
复制代码


查找所有有会员折扣的账号信息

DECLARE @Players table (    USAPlayer varCHAR(60)    ,ChinaPlayer varCHAR(60)    ,CANPlayer varCHAR(60)    ,Discount  DECIMAL(18,2))
INSERT INTO @Players( Discount ,USAPlayer ,ChinaPlayer ,CANPlayer)SELECT A.Discount ,CASE when A.Country = 'USA' then A.Player else isnull(c.USAPlayer,'') end ,CASE when A.Country = 'China' then A.Player else isnull(C.ChinaPlayer,'') end ,CASE when A.Country = 'CAN' then A.Player else isnull(c.CANPlayer,'') endFROM dbo.Player A WITH(NOLOCK) LEFT JOIN [dbo].[PlayerMapping] C WITH(NOLOCK)ON c.USAPlayer = A.Player OR c.ChinaPlayer = A.Player OR c.CANPlayer = A.PlayerWHERE A.Status='会员'
SELECT DISTINCT Discount ,PlayerFROM (SELECT Discount ,USAPlayer AS PlayerFROM @PlayersWHERE USAPlayer <> ''UNION ALLSELECT Discount ,ChinaPlayer AS PlayerFROM @PlayersWHERE ChinaPlayer <> ''UNION ALLSELECT Discount ,CANPlayer AS PlayerFROM @PlayersWHERE CANPlayer <> '') A
复制代码


en....

是不是大家都觉得这两段 sql 都挺复杂的呢?

可能是作者 sql 功力不行,大家可以试试看能不能写出在这样设计下更好更快更简单的 sql 呢?


如果重头用"万剑归宗"来思考呢?

好吧,其实我们是用 穷举法数学归纳法来思考

大家都知道 穷举法 实际是一种数学证明法,

一个证明法怎么能帮助我们思考呢?

当然是直接不行,但它可以用来证明我们想法简不简单,好不好用

比如上面朴实无华的设计

如何用 穷举法 证明设计是不是简明?

我们设计 mapping 表的目的是为了帮助我们找到用户实际有多少个账号,

那么我们需要证明的命题就是当 mapping 表 有 N 条 mapping 记录时能帮我们用一个 player 名字找到实际有多少个账号

假设 这个 player 叫 Gold

当 N = 0,mapping 表不存在 Gold,找到账号为 0 , 不对劲,玩家肯定得有个账号,否则 Gold 从那里来?

当 N= 1, mapping 记录有三个字段 USAPlayer,ChinaPlayer, CANPlayer, 无法确定 Gold 唯一确定规则,只能其中一个等于 Gold 就算有效


如上,每一个证明,我们都没办法直接用最简单的条件确定,要不得已用多余的规则确定

所以根据以上问题,我们可以尝试做出如下调整

当 N = 0,mapping 表不存在 Gold,找到账号为 0 , 不对劲,玩家肯定得有个账号,否则 Gold 从那里来?

那么我们保证即使玩家只有一个账号,mapping 表也有数据,那么 N=0 的情况不存在了,那么也是证明有效

当 N= 1, mapping 记录有三个字段 USAPlayer,ChinaPlayer, CANPlayer, 无法确定 Gold 唯一确定规则,只能其中一个等于 Gold 就算有效

问题出在有三个字段,那么我们把三个字段砍成一个字段不就解决这个问题了吗?

PlayerMapping 表就是这样

| id | Player |

| ----| ---- |

| 1 | Gold |

| 2 | Gddd |

| 3 | Shen |

| 4 | girl |

| 5 | Sddd |

但是这样好像无法 mapping,应该加 mapping 绑定 id 去确定关系,就是这样

| id | Player | MappingId |

| ----| ---- | ---- |

| 1 | Gold | M |

| 3 | Shen | M |

| 4 | girl | M |


这样再次套用穷举法:

假设 这个 player 叫 Gold,MappingId 都为 M

当 N = 0, 不存在这样情况,证明成立

当 N= 1,那必定只有一条 Gold ,证明成立

当 N=2, Gold 对应的 MappingId 可以找账号信息,证明成立

当 N=3, Gold 对应的 MappingId 可以找账号信息,证明成立

当 N=4,一个玩家暂时没有那么过 country,证明成立

当 N= 。。。。。


哇哦,这样好像没有问题了耶

那么我们确实没有问题了吗?

细看我们的穷举内容,只列举了一个玩家的三个国家情况,如果国家还要扩充呢?100 个玩家呢?10000 个玩家呢?

如何用 数学归纳法 证明设计是不是简明?

其实吧,对我们程序员来说,

我们不是数学家,我们不需要写什么证明式,

我们的证明式其实就是我们的程序,


比如上面的命题

当 mapping 表 有 N 条 mapping 记录时能帮我们用一个 player 名字找到实际有多少个账号

我们按照现在的 mapping 表 设计

| id | Player | MappingId |

| ----| ---- | ---- |

| 1 | Gold | M1 |

| 2 | Gddd | M2 |

| 3 | Shen | M1 |

| 4 | girl | M1 |

| 5 | Sddd | M2 |


写出来的 sql 就是这样

declare @mappingid = SELECT top 1 mappingid from [dbo].[PlayerMapping] C WITH(NOLOCK) where c.Player = @Player
select Player FROM [dbo].[PlayerMapping] C WITH(NOLOCK)where c.MappingId = @mappingid
复制代码

这样的 证明式 我们自己看出合不合理,简明不简明,实在不行还可以跑程序测试

当然如果我们写不出这样的 sql,必须添加 if else ,那必然是我们方案还存在一些特殊情况,这种时候就需要我们自行取舍,找到一个平衡的点


新方案实际使用

新增 mapping 关系

declare @mappingid VARCHAR(60) = SELECT top 1 mappingid from [dbo].[PlayerMapping] C WITH(NOLOCK) where c.Player = @Player
IF(@mappingid IS NULL)BEGINSET @mappingid = UUID()END
insert into [dbo].[PlayerMapping] ( Player ,MappingId ) select @mappingPlayer,@mappingid
复制代码


查找所有有会员折扣的账号信息

SELECT      A.Discount    ,c.PlayerFROM dbo.Player A WITH(NOLOCK) inner JOIN [dbo].[PlayerMapping] b WITH(NOLOCK)ON b.Player  = A.Player inner JOIN [dbo].[PlayerMapping] c WITH(NOLOCK)ON c.MappingId  = b.MappingId WHERE A.Status='会员'
复制代码


总结

其实说了那么多,大家是不是已经发现了,

什么 穷举法啊 数学归纳法啊 从初中开始,

我们都是学过的,

并且我们经常做事情也是这样做的,

但是为什么我们却时常做出东东总是差别人家孩子那么一丢丢呢?

个人觉得还是我们心中差了一个字: 静

发布于: 2020 年 11 月 25 日阅读数: 484
用户头像

八苦-瞿昙

关注

一个假和尚,不懂人情世故。 2018.11.23 加入

会点点技术,能写些代码,只爱静静。 g hub: https://github.com/fs7744 黑历史:https://www.cnblogs.com/fs7744

评论 (4 条评论)

发布
用户头像
《风云》漫画迷前来支持。
2020 年 11 月 30 日 19:38
回复
暴露年龄了,哈哈
2020 年 12 月 01 日 16:46
回复
用户头像
"个人觉得还是我们心中差了一个字: 静"这就是你修佛的理由?
2020 年 11 月 27 日 11:07
回复
众生皆佛
2020 年 12 月 01 日 16:46
回复
没有更多了
论“万剑归宗”思想对开发设计的一点“肤浅”作用