软件设计之美
郑晔
开源项目 Moco 作者
19890 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 42 讲
软件设计之美
15
15
1.0x
00:00/00:00
登录|注册

02 | 分离关注点:软件设计至关重要的第一步

你好!我是郑晔。
上一讲我们讲了软件开发就是在解决问题。那问题一般是如何解决的呢?最常见的解决问题思路是分而治之,也就是说,我们要先把问题拆分开。在每个问题都得到解决之后,再把这些解决好的子问题以恰当的方式组装起来。如何分解与组合,就是我们要在软件设计中考虑的问题。
然而,在软件设计这个环节中,大部分人都把焦点放在了如何组合上,却忽略了至关重要的第一步:分解。你可能会觉得:“分解?我会啊,不就是把一个大系统拆成若干个子系统,再把子系统再拆成若干个模块,一层一层拆下去嘛。”
然而,在我看来,这种程度的分解远远不够,因为分解出来的粒度太大了。粒度太大会造成什么影响呢?这会导致我们把不同的东西混淆在一起为日后埋下许多隐患。
为什么这么说呢?我来给你举个例子。

一个失败的分解案例

我曾经见过一个故障频出的清结算系统,它的主要职责是执行清结算。一开始我觉得,清结算系统是一个业务规则比较多的系统,偶尔出点故障,也是情有可原。
但是在分析了这个系统的故障报告后,我们发现这个系统设计得极其复杂。其中有一处是这样的:上游系统以推送的方式向这个系统发消息。在原本的实现中,开发人员发现这个过程可能会丢消息,于是,他们设计了一个补偿机制。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

软件设计中的关键一步:分离关注点 在软件设计中,分离关注点是至关重要的一步。文章强调了正确分解问题的重要性,以及分离关注点的必要性。作者通过举例说明了一个失败的分解案例,强调了分解的重要性,并提出了解决方案。在设计中,将一个模块的不同维度分开,有一个专门的说法,叫分离关注点。分离关注点很重要,一方面,不同的关注点混在一起会带来许多问题;另一方面,分离关注点有助于我们发现不同模块的共性,更好地进行设计。分离关注点,是我们在做设计的时候,需要时时绷起的一根弦。文章还提到了两种常见的关注点混淆的情况,即技术和业务的混淆,以及不同数据变动方向的混淆。最后,作者提出了思考题,鼓励读者去了解CQRS(Command Query Responsibility Segregation),并在留言区分享想法。 总的来说,本文强调了在软件设计中正确分解问题的重要性,以及分离关注点的必要性。通过合适的分解和解决方案,可以避免后续问题的发生,提升系统的稳定性和效率。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《软件设计之美》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(55)

  • 最新
  • 精选
  • Jxin
    1.cqrs,命令与查询分离,最早是在ddd实战里面看到。其分离啦增删改与查询这两个关注点。 2.静态上,拆分了这两块的代码。使各自可以采用不同的技术栈,做针对性的调优。动态上,切分了流量,能够更灵活的做资源分配。 3.查询服务的实现。可以走从库,这有利于降低主库压力,也可以做到水平扩展。但需要注意数据延迟的问题。在异步同步和同步多写上要做好权衡。 也可以都走主库,这时候查询服务最好能增加缓存层,以降低主库压力,而增删改服务要做好缓存的级联操作,以保证缓存的时效性。 当然也可以走非关系型数据库,搜索引擎类的es,solr,分布式存储的tidb等等,按需选择。

    作者回复: 非常棒的分享!

    2020-05-27
    2
    65
  • 西西弗与卡夫卡
    近期有一本书《被统治的艺术》,正好和软件设计中的职责分离策略异曲同工。 我们知道明朝自朱元璋开始有一个顶层设计,就是每家每户做什么,一开始就规定好了。军队也是一个固定职业,即军户制。比如说国家需要100万个士兵,那就要有100万个军户,每户出一个兵,世世代代都是这样。如果这个兵逃了或者死了怎么办?家族里就再出一个来补充。 这会带来什么后果呢?你可以想象一下,如果儿童节的时候你正坐在家里跟妻子儿女享天伦之乐,忽然有人闯进来,把你抓走了去当兵,只是因为你家族里面的另外一个人当了逃兵或者死掉了。 可见,这样的顶层设计会给自己的家族带来各种不确定性甚至家庭悲剧。人民群众想出了很多的策略来对付这样的制度。 有种设计是这样的,就是每个家族中选出一个分支代表整个家族去当兵,与之相对的是家族的其他分支需要共同出一笔钱,世世代代赡养这个当兵的分支。此外还有其他一些「福利」,比如说,如果原本他在家族中的排位比较低,那他的后代就可以在家族的各项活动中提升座次。 这个世世代代当兵的分支会比较惨,但带来的好处是这个家族中的其他分支就会少受骚扰,得以繁衍。 事实上这样的策略运行得不错,有些家族好几代人一直都执行这样的策略,甚至贯穿了几乎整个明代。 某种角度说,这就是一种职责分离,将国家统治的要求和家族稳定繁衍的需要分开。

    作者回复: 刚好最近万维钢老师讲了这本书中的内容,但你从软件设计的角度去理解这个问题,确实让人有一种耳目一新的感觉。

    2020-05-27
    2
    49
  • 夏天
    我发现大家在工作中往往不做分离,分析需求的时候把方案揉在一起。 可以怎样去练习做分离呢?

    作者回复: 有一种从小事练起的方法,就是写代码时,把自己写的函数行数限定在一定的规模之下,比如,10行。超过10行的代码,你就要去仔细想想是否是有东西混在了一起。 这种方法锻炼的就是找出不同关注点的思维习惯,一旦你具备了这种思维习惯,再去看大的设计,自然也会发现不同的关注点。

    2020-05-27
    34
  • 北天魔狼
    想起Kent Beck 说的一句话,大致意思是:我不准备在这本书里讲高并发问题,我的做法是把高并发问题从我的程序里移出去

    作者回复: 没错,就是这样。

    2020-05-27
    29
  • 飞翔
    老师 比如说订单系统 先下单写到数据库 然后发送消息给消息队列 这两部 没法放到一个事务中去。 如果用本地消息表, order 写数据库 然后 在写本地消息表 这样这两步就放到一个事务中去了 保证肯定成功, 然后在有线程 读取本地消息表 发送队列 如果成功更改本地消息表状态 。 从设计角度讲这就没分离关注点, 这个应该怎么分呀?

    作者回复: 我们来分析一下这个需求,下单入库和发消息给下游,这确实是两个动作,但这两个动作的顺序一定是这样吗?它们一定要在一个线程里完成吗? 我们可不可以先发消息呢?比如,我们把消息发给下游之后,有一个下游接收到消息之后,再把消息入库。如果这样做的话,发消息,由消息队列保证消息不丢,下游入库,又可以保证订单持久化。你看,在这个设计中,其实,并不需要事务,所以,我们也不必为事务纠结了。

    2020-05-28
    10
    28
  • Rovebiy
    老师,我觉得补偿机制还是要的吧,就算换吞吐量大的消息队列,丢失消息还是有可能出现的,只是几率小很多。只是他补偿机制设计得不合理?

    作者回复: 如果我们分析是不是丢消息,就要看它在什么情况下丢消息。在之前的业务场景中,丢消息就是因为消息队列处理不过来,而我们换了吞吐更好的队列就不存在这个问题了。 其实,我们真正需要的是可靠的信息传送通道,至于是不是消息队列不重要。如果怕丢消息,可以在生产者端重试,可以在消费者端做幂等。补偿是一个能把场景弄复杂的做法,不鼓励。

    2020-05-29
    4
    13
  • 小学一年级
    郑老师 我有个需求描述下(类比): 用户购买网站会员 我目前的设计用了两张表 一张表存储用户购买会员的所有记录, 另一张表 存当前的会员信息 (主要是 开始,结束时间,没有会员等级之类) 单独设计这张表的目的是为了sql关联查询方便,不用再判断是否过期。 但有个问题:我要用定时器一直扫这表,等会员过期了要删除记录。 请问郑老师 我这么做的问题在哪? 更好的解决方式应该是什么?如果做到更细维度的拆分?

    作者回复: 首先,你的描述没有把业务和实现分清楚。 你的业务是实现一个会员系统,具体到这里,是判断用户当前是否是会员。更具体一点的话,会涉及会员购买,主要是会员时间要延长,还会涉及到会员资格的判断,也就是当前用户是否是会员。 基于这些内容的判断,可以有不同的实现。根据你当前的实现,可以这样做: * 购买会员,如果会员信息不存在,则添加会员信息,如果会员信息存在,则修改会员结束时间。 * 会员资格判别,根据用户 ID 和当前时间是否在时间范围内查询查询,如果记录存在,则是会员,否则不是。 结合你提供的信息,可以考虑的点是: * 购买会员时,可以产生会员购买记录,此记录仅供后续查询使用; * 只有当会员信息表过大时,才考虑是否需要删除。 在这个实现中,把购买和会员信息分开,把会员信息是否生效与记录是否删除分开了。 以上仅仅是根据你提供的信息进行的分析,如有不当之处,欢迎继续讨论。

    2020-06-11
    11
  • 桃源小盼
    能提供关于分离关注点更多的例子或者相关资料吗?

    作者回复: 专栏后面还会多次提到分离关注点的,敬请期待!

    2020-05-27
    11
  • 业余爱好者
    技术和业务混杂的情况,让我想起来一篇文章,大意是说要区分技术异常和业务异常的。也就是说,技术层面的异常信息不应该暴露给上层的业务人员。典型的例子就是大型网站的错误页面,而不是直接把后台的npe堆栈信息抛给用户。

    作者回复: 这是一个很好的例子,确实要做区分。

    2020-05-27
    2
    11
  • 我是小妖怪🇨🇳
    有感觉,但是又不明确,没有get到那个点,应该举一下具体的业务来说明或者证明,感觉是理论上的

    作者回复: 你把你困惑的点提出来,我争取进一步讲清楚。 我在部落里写了一个回答,可以参考一下。 http://gk.link/a/10iHp

    2020-05-27
    9
收起评论
显示
设置
留言
55
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部