写点什么

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

用户头像
八苦-瞿昙
关注
发布于: 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 = @Player
end



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

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,'') end
FROM 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.Player
WHERE A.Status='会员'
SELECT DISTINCT
Discount
,Player
FROM (
SELECT
Discount
,USAPlayer AS Player
FROM @Players
WHERE USAPlayer <> ''
UNION ALL
SELECT
Discount
,ChinaPlayer AS Player
FROM @Players
WHERE ChinaPlayer <> ''
UNION ALL
SELECT
Discount
,CANPlayer AS Player
FROM @Players
WHERE 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)
BEGIN
SET @mappingid = UUID()
END
insert into [dbo].[PlayerMapping]
(
Player
,MappingId
)
select @mappingPlayer,@mappingid



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

SELECT
A.Discount
,c.Player
FROM 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 日阅读数: 461
用户头像

八苦-瞿昙

关注

一个假和尚,不懂人情世故。 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
回复
没有更多了
论“万剑归宗”思想对开发设计的一点“肤浅”作用