借降本增效之名,探索开闭原则架构设计
Tech导读
软件设计的优劣,很大程度上决定了该软件后期的运维和迭代的成本高低与风险大小,而对于互联网业务场景下迭代频率比较高的软件系统尤为明显。本文尝试借降本增效之名,来探索软件的开闭原则架构设计的实践对降低程序员认知负载的意义与价值。
导读
软件设计的优劣,很大程度上决定了该软件后期的运维和迭代的成本高低与风险大小,而对于互联网业务场景下迭代频率比较高的软件系统尤为明显。本文尝试借降本增效之名,来探索软件的开闭原则架构设计的实践对降低程序员认知负载的意义与价值。01 引语
在今年的敏捷团队建设中,我通过Suite执行器实现了一键自动化单元测试。Juint除了Suite执行器还有哪些执行器呢?由此我的Runner探索之旅开始了!
在研发生产活动中,经常会遇到如下类似的疑惑:
业务和技术在公司组织活动中,究竟应该各扮演什么样的角色?
技术的目的是什么?
研发生产活动中,如何提高生产事故发生的下限?
如何充分提高isv或者外协人员价值最大化?
《人月神话》说优秀程序员是普通程序员研发效率10倍,如何可以提高研发效率水位线呢?
如何避免《人月神话》指出的“焦油坑”?
如何更好的对老系统进行ddd升级?
这些疑惑单独看都可以有很多的解决思路,或者从制度层面解决,或者从技术层面解决,或者业务层面解决,等等,甚至也有可能出现某些解决思路按下葫芦浮起瓢。但如果将这些问题统一起来看,是否能找到他们对应的共性,尝试从最底层的逻辑找到问题解决的切入点呢?
02
疫情启发
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
新冠疫情持续了三年时间,让生活发生了很多与之前不一样的改变,比较典型的一个现象就是在公共场所的椅子上会被要求进行隔位相坐。经过长期的观察,发现很多场所这样的要求和提示如同虚设。不讨论政治和经济,单纯从实现设计的维度来思考如何让这个要求能落到实处,实实在在的帮助实现更好的科学防疫。以下是几个场合的隔位相坐实现方式:
03
系统实现反思
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
为了得到高质量的软件产品,是应该把精力更多地集中在提升其中每一个人员、过程、产出物的能力和质量上,还是该把更多精力放在整体流程和架构上?—— 《凤凰架构》 系统的行为价值 和 架构价值 到底哪个更重要?——《架构整洁之道》 系统是演化发展的,根据疫情隔位相坐实现方式的启发,系统是否可以以巨人肩膀为起点开始演化发展?
对于以上反思,下面尝试从一种切面来和大家一起探讨。
04 统一沟通语言
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目
有很多的方案的讨论最终达不成一致,很大程度在于双方沟通语言不统一,即双方讨论问题最基本的基石基础并不是一致的,所以怎么讨论都不可能达到一致的结论和目标,所以要首先统一一下沟通语言。只有统一语言才能更好地降低认知负载。
一个商业公司,最底层的逻辑肯定是商业盈利,那么作为其中的一员,每个人有以下三个角色(注:以程序员岗位进行分析),每个角色的职责价值尝试做如下解析:公司职员角色曾有企业家有言:一个企业的边界取决于其创始人的认知边界,其实对个人也是如此,一个人的价值大小也是由其认知边界决定的。个人角色短期来看,对咱们解决方案讨论意义并不是那么重要。这个也不是能很快改变的。暂且忽略影响。
程序员角色员工的任何公司任何活动都应该朝着有利于公司市场竞争优势的方向进行的。甚至可能还关注公司第二曲线,在一些公司文化里面还倡导第三曲线;
认为技术的最终目的更应该是降本增效,具体体现为业务初创期低成本快速迭代,业务成长期快速低成本规模化,以及将以上低成本能力抽象成能力光环,从而实现助力业务快速迭代,以及释放创造力助力管理。
05
两个概念
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
回到本文主题,本文主要是尝试通过探索开闭原则架构设计来实现降低认知负载,从而达到降本增效的目的。因为在研发活动中,关注点越发散,越会容易降低研发效率,所以本文的目的是想通过系统遵循开闭原则架构进行设计,保证系统的职责的清晰和单一化,以收敛研发的关注,保证程序员能集中精力将事情做好。主要从加强系统纯洁度维度来尝试进行阐释。
开闭原则,耳熟能详的原则,其比较关键的特点在于,系统或者模块的只读性,以及和 职责单一原则的一体两面;如此在研发活动过程中,可以将稳定的需求和常变的需求,通过组合的方式将不同的模块进行扩展。而稳定的需求其实是可以进行产品化封装的。
06
凤凰架构的逻辑
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
凤凰架构的思想是参考生命系统的可靠性和稳定性,希望通过一系列不稳定的子系统来打造一个稳定可靠的大系统;而其实生命系统的可靠性也不是一蹴而就的,并且也只是一个稳定且发展的文明系统的载体;这个文明系统的演化过程非常类似咱们需求交付的过程;
通常比较主流的观点对于文明的演化理论是进化论,进化论来源于达尔文的《物种起源》的进化树,而进化论其实存在未能解释的空缺,即为什么进化树是由单细胞向多细胞进化和低等生物向高等生物进化而不是相反,以及进化与熵增定律和质能方程E=mc²冲突,即进化来源于什么?有学者提出一套演化理论即“递弱代偿”理论(不讨论其争议性,只分析客观逻辑),解释了以上空缺。即从30亿年前单细胞到软体生物到脊柱生物到人类,物种伴随的文明越发达,而物种的存在度空间会越小,因为单细胞是全能的,从吸收到排泄,以及繁殖都能实现,而人类的组织,已不再是单细胞而是多细胞高度分化成不同功能的独立的组织,而某个组织也只有某个功能,放弃了单细胞其他大部分的功能。因此随着文明的愈发达,而文明当前的载体分化程度越高以至于产生了新的物种。而分化的程度越高,诞生出来的新物种的存在度会越低,如同上图右公式图,即物种的存在度与系统的文明发达程度成递弱关系。(参考著作《物演通论》)
这极其类似需求交付过程,即单个系统不再是万能的,而是分化成不同的小型子系统,而通过每个系统继续高度的分化和升级,使得整个大系统的能力越来越丰富和强大。
而系统分化的原则就应该是上述的开闭原则和单一职责原则,这才能保证每个系统能独立的分化和演进,保证了在需求迭代的过程中,整个系统可以不断地进化为新的业务物种形态,并且进化过程中依然可靠。在一个系统内,进化的本质是替换部分组件使之成为新的物种,而不是当前物种的升级;而系统最终升级演化的趋势就是系统内所有组件都能敏捷替换,修改一下路由,很低成本替换组件,这样优化系统的成本会越来越低。
07
软件系统的逻辑
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
图5.软件系统架构示意
再来分析软件系统的结构,主要分两部分,一部分是基础设施,一部分是业务部分;而基础设施主要是冯诺依曼体系;而在讨论开闭原则时,最典型的案例就是冯诺依曼体系;
冯诺依曼体系可以简化为cpu,存储,输入输出;正是这套扩展性非常强的体系支撑着在计算机世界的发展。cpu通过元指令和指令流的分离,数据与计算的分离,并且提供中断回调,来落地了开闭原则,保证了多么复杂的需求的实现都不再需要修改cpu了;而将变化的业务交给输入输出;上面的操作系统则将冯诺依曼体系进行了封装,提供了方便的操作方式。
试想:能否将上层的页面模式的设计思路也复用底层的基础设施的设计思路呢?在最外层再提供一层“操作系统”提供使用呢?
再反观现在行业的各种服务化,SAAS,PAAS,IAAS 其实也就是这种思路的体现和落地。
08 星链的逻辑
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目
图6.货、人、场示意
09
业务垂直拓展思考
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
图7.对不同复杂度的系统的一个简单概括总结
这是对不同复杂度的系统的一个简单概括总结,系统可能处于高级别分布式系统的层次,那再思考一下业务系统,进行垂直拓展的颗粒度能达到什么级别呢?
图8.ddd分层思路示意
10
架构探索
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
图9.将冯诺依曼的设计模式上移到业务系统结构示意
通过以上分析,如果尝试将冯诺依曼的设计模式上移到业务系统,,让系统职责和业务角色收敛关系更清晰,同时保证业务子系统做到尽可能只读,如果有新的业务就去分化重开系统;可以尝试用星链来实现业务操作系统,梳理各业务系统的职责,梳理出稳定系统,周边业务系统,以及公共功能系统,并且可以将比较稳定的业务系统进行产品化。去尝试探索一种新的商业模式。另外,其实在推行ddd的过程中,通常会比较严格的按照战略战术的模式,重建领域模型,但是在实际生产中,很多老系统都背负很重的业务量,轻易重构数据结构,风险会非常大,其实可以尝试按照开闭原则,先试图对老系统进行分化出新的系统,将系统的api进行收敛到同一个领域内,等这第一步完成后,可以在考虑在当前领域内实现领域模型的梳理。或许这可能是开闭原则下比较理想的架构模式,复用京东bigboss文化的宣传语:积木式组织—探索未来式,人人是boss;
积木式系统—探索未来式, 职责要清晰;
而积木式系统,必然是比较整洁的系统了,自然当关注某一个模块的业务的时候,就只需要将认知主要集中在当前模块即可。而对于一些重复通用的功能,研发可能甚至只需要关注输入和输出即可,这样相当于通过职责的抽象将对应的能力打造成了能力光环,只要涉及到相关的研发的同事,天然就具有了这方面的能力。
11
扩展思考
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
在业务系统中,常常通过异步消息来实现通信的处理,可能会存在一种方式,就是将mq的监听和业务处理混合在一起,当mq的监听比较少的时候,或许系统还算整洁;但当系统监听非常多的时候,这个系统似乎就成了大杂烩了,什么业务都可能会有。这样导致这个系统的职责非常的不清晰。而业务监听本来就应只是一个系统的共用功能,是可以将其抽象为平台功能,所以按照以上开闭原则设计,提供监听后对应业务的处理接口,在监听之后自动调用接口即可。该系统只负责做mq监听的处理。系统角色草图如下:
12
写在最后
理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。
在我们生活中,发现问题的时候,大部分人只是看到了当前现象,而少数人看到了这个现象背后的原因,而只有极少数的人能全面看到这个现象的底层根源,从全局的视角寻找解决方案。而第三者应该是我们追求的一种境界,这应该是工程师文化/工匠文化的体现所在。此所谓:
众生畏果,菩萨畏因,佛畏系统
求分享
求点赞
求在看