你的技术leader连这个都不懂?没有它就是没有设计的完成思考过程

在光速交付软件功能特性的时候,研发人员通常选择不去全局思考便动手实现,缺乏周边人员对齐,没有对利益相关者进行充分的访谈就开工了。而用例其实是设计的起点,如果连系统用例都不清楚,又何谈实现的是个正确的系统呢。而在我工作的过程中,有的高级工程师对用例2字都未听说过,或者选择在心里过一遍用例,而不是边思考边画出来。那么是时候讲讲用例的重要性,以及为何一定要把它画出来了。

以下大部分来自于我的读书笔记,以及个人思考总结。

业务逻辑

什么是业务逻辑?程序中真正用于赚钱或省钱的过程,无论是计算机执行的过程还是人工执行(我认为可以总结为直接创造价值的,而非高可靠,安全,韧性等)。例如银行贷款,让计算机计算利息,还是人用计算器计算不重要。关键业务逻辑通常需要处理数据。这些就是关键业务数据。由于逻辑和数据紧密相关,因此可以放在一个对象处理,即业务实体

用例

有的业务逻辑必须要自动化,而不能靠人工执行,即只有作为自动化的一部分才有意义。本质是关于如何操作一个自动化自动的描述,它定义了:

  • 用户输入
  • 得到的输出
  • 产生输出所需要采取的处理步骤

如上所述,用例控制着业务实体之间的交互方式。

  1. 用例不该描述用户界面,即不描述用户和系统间接口,输入流和输出流。
  2. 业务实体不知道哪个用例在控制他们(依赖反转原则DIP),底层的用例需要了解高层实体

例子

原始需求:

运维团队需要高效管控账号,需要将账号的申请自动化,减少人工的参与以提升工作效率。

另一方面研发需要账号登录控制台查看资源,也需要用户密码凭证以让程序操控资源

用户故事示例:

通过用户访谈,提炼用户故事等手段,将上述内容转化为用例视图,我们看下采访后总结的用户故事

  • 作为运维人员,需要控制他人web console的使用权限,仅赋予研发只读权限,以保证资源的安全
  • 作为研发人员,需要创建临时账号,以登录到web console进行问题定位和跟踪
  • 作为研发人员,需要申请账号,以配置给程序使用,操作系统的API

用例视图示例:

image.png 说明谁要使用系统,以及他们使用系统做什么,是需求分析阶段的输出件。以用例作为设计的驱动,驱动后续的设计,随时回顾自己的设计是否能支撑用例,保证部署视图,逻辑视图,开发视图,运行视图正确性

用例对架构设计和业务展开的支撑

什么是软件架构:

软件架构设计的主要目标是支撑软件系统的全生命周期,设计良好的架构可以让系统便于理解、易于修改、方便维护,并且能轻松部署。软件架构的终极目标就是最大化程序员的生产力,最小化系统的总运营成本。你需要考虑这些事情

  • 开发
  • 部署
  • 运行:架构设计的影响比较小(架构掌控不了代码执行效率),一般都可以通过增加硬件解决(短期,后期基于业务驱动再优化),因为硬件比人力便宜,基于投入产出比,所以才优先把优化重心放在别处。即便如此,架构应该让开发对系统的运行过程一目了然,即用例,功能,必备行为,简化他们对系统的理解,为的是为开发和维护提供帮助
  • 设备无关性:满足开闭原则,高层策略与底层实现细节分离
  • 维护:成本最高,探秘成本是找到新增功能和修复问题的最佳方式和位置。风险成本是上述修改时,总是衍生新的问题。架构的目的是降低两部分成本

软件至于硬件最大的不同是什么?是不断地,快速的变化

软件架构必须支持以下几点(独立性):

  • 系统的用例:架构必须能支持其自身的设计意图,架构必须为其用例提供支持,因此这是架构师首要关注的问题
  • 系统的运行:如果系统每秒处理1000个请求,架构的设计就必须能支持这种级别的吞吐和响应时间
  • 系统的维护
  • 系统的开发:康威定律任何一个组织在设计系统时,往往都会复制出一个与该组织内沟通结构相同的系统。这是因为团队要独立的完成工作,所以需要隔离良好,可独立开发的组件。
  • 系统的部署:便捷性,不该依赖成堆的脚本和配置

保留可选项:

  • 实现以上的平衡很困难,比如我们无法预知系统的所有用例,运行条件,开发团队的结构,或者系统的部署要求。即便提前了解,随着演进,需求会不断发生变化。即目标是模糊多变的。
  • 采用一些原则可以有助于解决平衡问题。将系统划分为隔离良好的组件,尽可能的为未来保留尽可能多的可选项

用例解耦:

按层解耦是水平切分,用例则是垂直切分。所以UI,业务逻辑,数据库等需要按照用例进行解耦。按照变更原因的不同进行垂直切分,就可以持续的加入新的用例,而不影响老的

解耦的模式:

  • 所有这些解耦对架构目标“系统运行”的意义:
    • 分层解耦可以让组件在不同服务器部署(服务数据库的分层隔离,这有点像SOA,即面向服务的架构)
  • 按用例,比如不同吞吐的用例可以分开,高吞吐,低吞吐,那么对带宽不同诉求的组件也可以分开部署在多个服务器上
  • 总之按用例解耦有利于系统的运行(其实这就是微服务)

开发和部署的独立性:

当你依据用例和水平分层解耦后,自然就支持了独立的开发互不干扰

消除重复的代码前要分清真假重复:

  • 真重复:每次变更都必须应用到所有副本
  • 假重复:不同的演进路径,包括变更理由,迭代节奏

因此当我们打算合并看似相同的用例时,一定要谨慎否则将来拆分会更难。总之不要因为为了减少重复代码而合并用例。同理,当水平分层时可能看到数据库结构或者API接口类似就要合并。一定要考虑演进路径

再谈解耦模式:

  • 用例分层的方式很多,比如
    • 源码解耦(单体架构):模块依赖关系,一个模块变更不会导致其他模块变更
  • 二进制解耦(部署):可能是jar,ddl,Gem,共享库,只是可独立部署的单元
  • 执行单元解耦(微服务架构):网络通信
  • 项目初期难以确认哪种适合自己,甚至随着项目的成熟,所谓最适合的模式会出现变更
  • 将系统解耦推行到“一旦有需要就可以随时转变为服务的程度即可”,这让系统尽量长时间地保持单体结构,以便尽可能保留可选项
  • 因此做到源码解耦就够了,随着项目发展可以随时快速拆分。
  • 设计良好的架构能允许从单体架构开始,逐渐演进为独立的单元,甚至微服务,也允许回退到单体架构。

可悲的故事

  1. 从纯客户端转型BS架构,技术满脑子的如何构建大规模服务器集群,选型了三层的“架构”(不是真正的架构,只是一种三层部署拓扑,这也是灾难的根因),那么UI,中间件,数据库都可以分别部署了,假设要添加一个字段,每个层都要改。结果是开发期根本没有大型服务器可用,也没能销售一个需要大规模服务器的系统。所有文件都跑在一台服务器上,维护成本却很高。—草率的决定无谓的将开发成本放大数倍
  2. 一个管理租赁车队的本地业务,找来的新架构师认为运作这个小小的业务需要企业级的面向服务的“架构”。如果想在销售记录添加一个联系人要经过复杂的处理过程,而且了测试这个复杂的过程,要运行消息总线等一些列基础服务。— 太草率的采用SOA体系的工具,大量人力耗费在实现SOA架构本身

成功的故事

坚信产品不应该让用户下载超过一个jar的文件,称为“下载即可执行”这一条规则就指导了之后的很多决策。

  • 决策1: 自研web服务器,没有使用开源的,因为编写一个基本功能的web服务器非常简单,且延迟了技术决策
  • 决策2: 避免考虑数据库,采用数据库无关的设计,只需要接口屏蔽。实现内存数据存储哈希表。当系统需要持久化,再次考虑是否用mysql,最后认为哈希表写入文件更简单,精力继续放在开发新功能上。三个月后得出了一个结论,文件存储就足够好了,完全不需要mysql(减少mysql的引入这就减少了大量的维护成本,表结构,三方件,密码管理,查询问题,数据库服务器,可靠性等与业务价值没有直接关系的成本)。直到有一天一个客户自己需要将数据写入mysql,他用了一天就实现了mysql存储。软件包分发后,没人实际用到mysql,连写这个mysql实现的客户都没有。

在早期,他们在业务逻辑和数据库间画了一条边界线,防止了业务逻辑对数据库产生依赖,使用文件系统做实验,反倒发现是更好的方案,而这也不会造成使用mysql的障碍。即通过划清边界,推迟和延后细节性的决策。以节省大量时间、避免大量问题。这就是助益

架构设计的主题:

A use case driven approach中的观点:系统架构应该为用例提供支持。架构的设计图应该凸显用例。

架构设计和技术手段,框架无关,他们都是手段。而不是架构设计中包含的内容。

架构设计的核心目标:

围绕用例展开设计,脱离框架,执行环境等因素描述用例。在确保用例需要的前提下,尽可能保留自由的技术选型。

框架不是信条:

选择框架要思考如何保护自己(就是用例,团队等等,不要绑定到框架上),保持对用例关注,不要被框架主导设计

用例对单元测试的价值:

针对用例进行单元测试


总结

可以看到用例可以成为你后续很多架构决策的重要依据。是否应该用SOA架构,还是微服务架构还是单体架构?

用例的另一个价值

新来的程序员是否能从设计中一眼就看出来系统名称?新人也应该先了解系统的用例,而不是技术实现。先不要考虑技术细节,以后再决定应该怎么做。

原文链接mp.weixin.qq.com/s?__biz=Mzg…

猜你喜欢

转载自juejin.im/post/7112392117200093198