王概凯架构漫谈学习笔记
一,什么是架构-架构实际上解决的是人的问题
架构产生源于每个人不能自己完成所有哦生活必须品的生产。
为了解决人类的延续的问题,自然而然就有男女群居出现,这个时候就出现了分工了,男性和女性所做的事情就会有一定的分工,可是人每天生活的基本需求没有发生变化,还是衣食住行等生活必须品。
但是一旦多人分工配合作为生存的整体,力量就显得强大多了,所以也自然的形成了族群,自然的形成人的分群-每个人的生产力提高,做自己擅长事情。
随之使得整个人群的生产力和抵抗环境的能力增强。-》每个人能力,时间有限,只能一段时间专心做好一件事。
一旦产生的分工,就把所有的事情,切分成由不同角色的人来完成,最后再通过交易,使得每个个体都拥有生活必须品,而不需要每个个体做所有的事情,只需要每个个体做好自己擅长的事情,并具备一定的交易能力即可。使得形成社会的架构。
把一个整体(完成人类生存的所有工作)切分成不同的部分(分工),由不同角色来完成这些分工,并通过建立不同部分相互沟通的机制,使得这些部分能够有机的结合为一个整体,并完成这个整体所需要的所有活动,这就是架构。
架构产生的动力:1必须由人执行的工作。2每个人能力,时间有限。3人对目标系统有更高要求。4目标的复杂性使得单个人能完成这个系统,符合2,3.
总结为:
- 根据要解决的问题,对目标系统的边界进行界定。
- 并对目标系统按某个原则的进行切分。切分的原则,要便于不同的角色,对切分出来的部分,并行或串行开展工作,一般并行才能减少时间。
- 并对这些切分出来的部分,设立沟通机制。
- 根据 3,使得这些部分之间能够进行有机的联系,合并组装成为一个整体,完成目标系统的所有工作。
二。认识概念是理解架构的基础-概念是人认识这个世界的基础,了解其所解决的问题,学习速度提升。
在古代,不叫“概念”,称之为“名相”。
具体东西是“相”,指代叫它的是“名”。
实际上“相“表达的不是一个具体的东西,如上面所提的一个瓷器杯子,并不是指这个瓷器,而是这个瓷器所起的一个作用:一手可握,敞口(一般不超过底的大小,太大口就叫碗了),并且内部有一个空间可乘东西的这么一个作用。
为何需要这个作用?
这个作用其实是为了解决“人需要一个可单手持握,但是希望避免直接接触所盛物体”这个问题。
—》每个概念实际上所解决的,还是人遇到的某个特定的问题,我们把解决问题的解决方案,给定了一个名字,这个名字就是对应的某个特定的概念。
同理,为何我们可以在不同的语言间进行翻译,是因为虽然语言不同,但是人类所面临的的问题是一样的,所使用的名不同而已。对于不同的动物之间的翻译也是同理。
关于抽象
抽象这个词代表的含义,实际上是把不同的概念的相似的部分合并在一起,形成一个新的概念。举一个例子,杯子和容器,很多人认为容器是杯子的抽象,但是实际上杯子是杯子,容器是容器,它们所解决的问题是不一样的。当我们需要解决装东西的问题的时候,会说容器;当我们需要解决单手持握要装东西的时候,会说要一个杯子。
回过头来,根据架构的定义,要做好架构所首先必须具备的能力,就是能够正确的认识概念,能够发现概念背后所代表的问题,进而才能够认识目标领域所需要解决的问题,这样才能够为做好架构打好基础。
三:如何做好架构之识别问题 -》这是谁的问题?有什么问题?
面对问题有哪些困难呢?
女主人公:老公,把袋子里的土豆切一半下锅。结果老公是把袋子里的每个土豆都削了一半,然后下锅。
出现这个现象是由于我们大部分时候过于关注解决问题,急于完成自己的工作,而不关心“真正的问题是什么”而造成的。当我们去解决一个问题的时候,一定要先把问题搞清楚。
看看软件开发工作者的时间分配也可以看出,大家大部分时间花在讨论解决方案和实现的细节上,基本都不会花时间去想“问题是什么”。或者即使想了一点点,也是一闪而过,凭自己的直觉下判断。只有真正投入思考问题是什么的工程师,才可能会真正的成长为架构师
处理问题容易犯错:
- 被告知要处理一个问题,但是交过来的实际上是一个解决方案,不是问题本身
- 被告知要处理一个问题,直接通过直觉就有了一个解决方案,马上考虑解决方案如何落地,或者有几种解决方案,选哪个合适
如何识别问题呢?
所有的概念基本都有一个很大的问题,就是缺乏主语。识别问题的一个最大的前提就是要搞清楚:是谁的问题。这个搞清楚了,问题的边界也就跟着确定了,再去讨论问题才有意义。
以上面切土豆的例子来分析:
- 女主人提出一个问题,要切土豆下锅煮。
- 男主人有一个问题,女主人交代了自己必须要完成的一个任务。
每个人都是优先处理自己的问题,自然就选择了 2,完成了这个任务。这也是大部分软件工程师处理的方式,以自己认为对的方式完成自己的问题,没什么不对啊,也难怪能得到我们的共鸣。这个里面犯的错误是什么呢?
- 女主人公提出的实际上是解决方案,而不是烧土豆这个问题本身。女主人当时执行这个解决方案可能有困难,就把执行解决方案作为一个任务,委托给了男主人。
- 男主人得到了一个任务,尽心尽职地把这个任务完成了。
最后的结果是什么呢,每个人都做了很多工作,每个人都认为自己做的是对的,因此没有一个人对结果满意。因为真正的问题没有被发现,自然也就没有被解决,那么后续还得收拾残局,还要继续解决问题。事实上自己的工作并没有完成,反而更多了。把原因归结为沟通问题也是可以的,但对于解决问题似乎并没有太多的帮助。因为要改进沟通,这也是一个大问题。搞明白目标问题“是谁的问题,是什么问题”,当然也是需要沟通的。为了帮助自己更快的搞明白,首先要做的事是问正确的问题。架构师应该问的第一个正确的问题就是:目标问题是谁的问题。
当我们处理问题的时候,如果发现自己正在致力于把自己的工作完成,要马上警惕起来,因为这样下去会演变成没有 ownership 的工作态度。在面对概念的时候,也会不求甚解,最终会导致没有真正的理解概念。
作为软件工程师或者架构师,我们大部分时候是要去解决别人的问题,“别人”是谁,是值得好好思考的。在这个故事里面,男主人要解决的,实际上是这个家庭晚餐需要吃土豆的问题,目标问题的主体实际上是这个家庭的成员。
明白了问题的主体,这个主体就自然会带来很多边界约束,比如土豆是要吃的,要给人吃的,而且还是要给自己的家人吃的。“切土豆下锅”这个问题,因为识别了问题的主体,自然而然的就附带了这么多的信息。
-》找出问题的主体,是做架构的首要问题。这也是我一再强调的,我们要解决的问题,一定都是人的问题。更进一步,架构师要解决的,基本都是别人的问题,不是自己的问题。再进一步,我们一定要明白,任何找上架构师的问题,绝对都不是真正的问题。为什么呢? 因为如果是真正的问题的话,提问题过来的人肯定都能够自己解决了,不需要找架构师。架构师都要有这个自觉:发现问题永远都比解决问题来的更加重要。
当问题的主体离架构师越远,就会让找出问题主体的过程越加困难,我们再举一个软件行业比较熟悉的例子:用户给产品经理提出要求,想要一把锤子。这是典型的拿解决方案作为问题的。真正的问题的主体是谁,是用户还是设计师还是施工队? 如果产品经理当成是自己的问题,那么毫无疑问就给了锤子了。
我们需要识别:用户究竟是二传手,还是问题的真正主体。如果是设计师,那么问题的边界就变成了设计师的问题,如果是施工队,那么问题就变成了施工队的问题,如果是用户,那么就要看看用户到底有什么困难,绝对不是要一个锤子这么简单。这也说明了,问题的主体对问题的边界确定有多么的重要。
当明白了问题的主体,我们才可能真正的认识问题是什么。因为问题的主体是问题的隐含边界,边界不确定下来,问题就是不确定的。
一般来说,从问题暴露的点,一点点去溯源查找,一定会找出来谁的问题,以及是什么问题。最坏情况就是当我们时间或者能力有限,实在是无法定位出是谁的问题的时候,比如系统出故障,也就意味着我们无法根本解决问题。这时最好的办法就是去降低问题发生所带来的成本,尽量去隔离问题影响的范围。给我留出时间和空间去识别真正的问题。
四:如何做好架构之架构切分
- 架构的切分的导火索是人的负载太重。
- 架构的切分实际就是对 stakeholder 的利益进行切分或合并,使得每个 stakeholder 的权责是对等的,每个 stakeholder 可以为自己的利益负责。
- 架构切分的最终结果都会体现在组织架构上,只有这样才能够让架构落地并推进。
- 架构切分的结果一定是一个树状,这也是为什么会产生分层。层数越多沟通越多,效率越低,分层要越少越好。尽可能变成一颗平衡树,才能让整个系统的效率最大化。
切分就是利益的调整。
随着社会的发展,分工是必然的,为什么呢? 这个背后的动力就是每个人自己的利益。每个人都希望能够把自己的利益最大化,比如:生活的更舒适,更轻松,更安全,占用并享有更多的东西。但是每个人的能力和时间都非常的有限,不可能什么都懂,所以自然需要舍掉一些自己不擅长的东西,用自己擅长的东西去换取别人擅长的东西。
对比一个人干所有的事情,结果就是大家都能够得到更多,当然也产生了一个互相依赖的社会,互相谁都离不开谁。这就是自然而然而产生的架构切分,背后的原动力就是人们对自己利益的渴望。人们对自己利益的渴望也是推动社会物质发展的原动力
-〉每个人必须要舍掉自己的东西,才能够得到更多的东西。有些人不愿意和别人进行交换,不想去依赖于别人,这些人的生活就很明显的差很多,也辛苦很多,自然而然的就被社会淘汰了。如果需要在这个社会上立足,判断标准就变成了:如何给这个社会提供更好更有质量的服务。提供的更好更多的服务,自然就能够换取更多更好的生活必需品。实际上这就是我们做人的道理。
为什么需要切分?
当人们认识到要主动的去切分一个系统的时候,毫无疑问,我们不能忘掉利益这个原动力。所有的切分决策都不能够违背这一点,这是大方向。
一旦确定了问题的主体,那么系统的利益相关人(用现代管理学语言叫:stockholder)就确定了下来。所发现的问题,会有几种情况:
- 某个或者某些利益相关人负载太重。
- 时间上的负载太重。
- 空间上的负载太重,本质上还是时间上的负载太重。
- 某个或者某些利益相关人的权利和义务不对等。
切分的原则
情况 1 是切分的原因,情况 2 是切分不合理而导致的新的问题,最终还是要回到情况 1。对于情况 1,本质上都是时间上的负载。因为每个人的时间是有限的,怎么在有限的时间内做出更多的事情?那么只有把时间上连续的动作,切分成时间上可以并行的动作,在空间上横向扩展。
所以切分就要有几个原则:
- 必须在连续时间内发生的一个活动,不能切分。比如孕妇怀孕,必须要 10 月怀胎,不能够切成 10 个人一个月完成。
- 切分出来的部分的负责人,对这个部分的权利和义务必须是对等的。比方说妈妈 10 月怀胎,妈妈有权利处置小孩的出生和抚养,同样也对小孩的出生和抚养负责。为什么必须是这样呢? 因为如果权利和义务是不对等的话,会伤害每个个体的利益,分出来执行的效率会比没有分出来还要低,实际上也损害了整体的利益,这违背了提升整体利益的初衷。
- 切分出来的部分,不应该超出一个自然人的负载。当然对于每个人的能力不同,负载能力也不一样,需要不断的根据实际情况调整,这实际上就是运营。
- 切分是内部活动,内部无任怎么切,对整个系统的外部应该是透明的。如果因为切分导致整个系统解决的问题发生了变化,那么这个变化不属于架构的活动。当然很多时候当我们把问题分析的比较清楚的时候,整个系统的边界会进一步的完善,这就会形成螺旋式的进化。但这不属于架构所应该解决的问题。进化的发生,也会导致新的架构的切分。
原则 2 是确保我们不能违反人性,因为维护自己的利益,是每个人的本性。只有权利和义务对等才能做到这一点。从原则 2 的也可以推理,所有的架构分拆,都应该是形成树状的结果,不应该变成有向图,更不应该是无向图。很多人一谈架构,必谈分层,但是基本上都没意识到,是因为把一个整体分拆为了一棵树,因为有了树,才有层。
同样我们看一个组织架构,也可以做一个粗略的判断,如果一个企业的组织架构出现了“图”,比方说多线汇报,一定是对 stakeholder 的利益分析出现了问题,这就会导致问题 2 的发生。问题 2 一旦出现,我们必须马上要意识到,如果这个问题持续时间长,会极大的降低企业的运作效率,对相关 stakeholder 的利益都是非常不利的,同样对于企业的利益也是不利的。必须快速调整相关 stakeholder 的职责,使得企业的组织架构成为一个完美的树状,并且使得数的层数达到尽可能的低。只有平衡数可以比较好的达到这个效果。
切分与建模
实际上切分的过程就是建模的过程,每次对大问题的切分都会生成很多小问题,每个小问题就形成了不同的概念。这也是系列第二篇文章尝试表达的。这些不同的概念大部分时候人们自发的已经建好了,架构师更多的是要去理解这些概念,识别概念背后所代表的的人的利益。比如人类社会按照家庭进行延续,形成了家族,由于共享一片土地资源,慢慢形成了村庄,村庄联合体,不同地域结合,形成了国家。由于利益分配的原因,形成了政权。每次政权的更迭,都是利益重新分配的动力所决定的。
切分的输出和组织架构
架构切分的输出实际上就是一个系统的模型,对于一个整体问题,有多少的相关方,每个相关方需要承担哪些权利和义务,不同的相关方是如何结合起来完成系统的整体任务的。有的时候是从上往下切(企业),有的时候是从下往上合并,有的时候两者皆有之(人类社会的发展)。而切分的结果最终都会体现在组织架构上,因为我们切分的实际上就是人的利益。
从这方面也可以看出,任何架构调整都会涉及到组织架构,千万不可轻视。同样,如果对于 stakeholder 的利益分析不够透彻,也会导致架构无法落地,因为没有入愿意去损坏自己的利益。一旦强制去执行,人心就开始溃散。这个也不一定是坏事,只要满足原则 2 就能够很好的建立一个新的次序和新的利益关系,保持组织的良性发展,长久来看是对所有人的利益都有益的,虽然短期内有对某些既得利益者会有损害。
五:什么是软件
总结:软件的本质,其实就是通过把人类的日常工作生活虚拟化,减少成本,提升单个人员的生产力,提升人类自己的利益。软件工程师的职责在这个浪潮中,不堪重负,自然而然就分拆为不同的角色,形成了一个独特的架构体系。这一切的背后,仍然是为了提升人类自己的利益,解决人类自己的问题。
软件的历史,实际上可以说是用机器模拟人的历史。不管大家(包括在这个历史过程中的参与者)有没有意识到,我们都有意无意的在计算机上模仿人类的行为。
从冯诺依曼结构开始,程序逻辑开始脱离硬件,采用二进制编码。加上存储,配合输入输出,一个简化的大脑就出现了。图灵机则是模拟大脑的计算,用数学的方式把计算的过程定义了出来,著名的邱奇 - 图灵论题:一切直觉上能行可计算的函数都可用图灵机计算,反之亦然。软硬件两者一结合,一个可编程的大脑出现了,这也是现在为什么我们把计算机叫做电脑。在硬件上编写出的程序,就是软件,是用来控制硬件的行为的。
成本为王:
人们越来越愿意把原来只有人才能做的事情,交给计算机来做。结果就导致软件越来越丰富,能够做的事情也越来越多,成本也越来越低。可以这么说,成本是我们为什么采用软件的主要动力,可以节省大量的人员培训,减少雇员的数目。随着互联网的发展,人类社会也开始软件化了。原来必须实体店来进行售卖的,搬到互联网上,开店成本更低,并且能够接触到更多的人。想象一下,一个门店每天的人流达到百万级别是很恐怖的,由实体空间大小来决定。但是在互联网上,访问量千万级别都不算什么。最终的结果就变成,每个人能够负担的工作越来越多,成本越来越低。这也是为什么软件这么热的原因。
软件扮演的角色:
早期的程序员写程序,主要是为了帮助自己研究课题。这些程序员熟练了之后,提高了自己的生产力,并发现还可以帮助别人写程序,慢慢软件就变成了一个独立的行业。程序从早期由一个人完成,也逐渐变成了由很多不同角色的人共同合作来完成。
有了软件之后,实际上,我们是把我们日常生活中所做的事情,包括我们自己本人都一起虚拟化到了计算机中。而人则演化成了,通过计算机的输入输出设备,控制计算机中的自己,来完成日常的工作,以及与其他人的沟通。也就是说,软件一直以来的动力,始终都是来模拟人和这个社会的。比如模拟大气运动(天气预报),模拟人类社会(互联网社交),模拟交易,包括现在正在流行的 VR,人工智能等等。模拟的对象越来越高级,难度越来越大。
不管如何发展,模拟人的所有行为都是一个大的趋势。也就是说,软件的主要目的,还是把人类的生活模拟化,提供更低成本,高效率的新的生活。从这个角度来看,软件主要依赖的还是人类的生活知识。软件更多的是扮演一个 cost center,这也是为什么会出现很多的软件代工。
软件开发的架构演变
软件工程师是实现这个模拟过程的关键人物,他必须先理解人是怎么在日常生活中完成工作的,才能够很好的把这些工作在计算机中模拟出来。可是软件工程师需要学习大量的计算机语言和计算机知识,还需要学习各行各业的专业知识。软件工程师本身的培养就比较难,同时行业知识也要靠时间的积累,这样就远远超出了软件工程师的能力了。所以软件开发就开始有分工了,行业知识和业务的识别,会交给BA,系统的设计会交给架构师,设计的实现交给架构师,实现的检验交给测试,还有很多其他角色的配合。为了组织这些角色的工作,还有项目经理。这就把原来一个人的连续工作,拆分成了不同角色的人的连续配合,演化成了不同的软件开发的模式。然后慢慢演变出专门为别人开发软件的软件公司。
软件架构的出现
如同前面描述的架构的定义,软件架构的出现也是同样的。一开始是懵懵懂懂的去写软件,后来慢慢的就有意识的去切分,演变成了不同的架构。这个背后的动力也是一样的,就是提升参与的人的利益,降低成本。导火索也是软件工程师的任务太重,我们需要把很多工作拆分出来。拆分的原则也是一样的,如何让权责一致。同样,这个拆分也是需要组织架构的调整,来保证架构的落地。
六:软件架构包括:代码架构,以及承载代码运行的硬件部署架构。
实际上,硬件部署架构最终还是由代码的架构来决定。因为代码架构不合理,是无法把一个运行单元分拆出多个来的,那么硬件架构能分拆的就非常的有限,整个系统最终很难长的更大。
所以我们经常会听说,重写代码,推翻原有架构,重新设计等等说法,来说明架构的进化。这实际上就是当初为了完成任务,没有充分思考所带来的后果。这也并不是架构进化的事情,而是个人对问题领域的逐渐深入理解的过程。所以有必要再讨论一下,代码的架构应该是怎样的。
七:不要空设架构师这个职位,给他实权
架构师必须是一个组织的领导人,有权利调动这个组织的架构,才能够更好的发挥架构师的作用,更好的把利益的调整落到实处。
架构师的前提条件:按时解决别人的问题
-〉超越对时间压力的恐惧,要成为架构师,必须要超越这个恐惧才能够看清楚,我们要解决的是别人的问题,不是自己完成工作的问题。因为仅仅是完成了自己的工作,也并不一定就解决了别人的问题。如果别人的问题没有解决–即使我们认为自己的工作完成了–我们的工作实际也没完成,因为我们工作是否完成,是别人说的算的,不是我们自己。
对时间的恐惧和压力原因:
1 完成自己的工作当成我们的最大利益。如果别人的问题没有真正的解决,必然会觉得付出的报酬不值得,我们的利益实际上是受损失了。这和我们所以为的恰恰相反,因为我们所能得到的工作只会越来越少,别人会越来越不愿意依赖于我们。
2 我们对自己所从事的工作,还没有足够的自信,我们解决自己的问题还有困难,才会这么在意,并恐惧。如果我们把完成别人工作当成自己的最大利益,这个对时间的恐惧自然就会消失,这个时候就自然而然的开窍了,就知道怎么去发现问题了。只有做到这一点,才能在自己所服务的领域建立起自信,成为一个合格的架构师。
其实刚开始一般是硬着头皮去克服对时间的恐惧和压力的,一点自信都没有。但只要做成功了一次(只要真的舍得这么去做了,想不成功也很难!),自信就开始慢慢建立起来了,这个时候就是我们开始慢慢变成架构师的时候。大家就当着上当一回,试试看。
如何发现“是谁的问题”
当我们真正专注于别人的问题的时候,我们自己的理想,抱负,对技术的追求都不算什么了。这些理想,抱负,对技术的最求,不就是要达到自己的利益吗? 只有帮助别人解决了问题,这些理想,抱负,对技术的追求才可能实现,否则这些理想,抱负,对技术的追求有什么意义,能得到什么利益?
这个时候就会真正的开始思考,别人究竟有什么问题。其实也很简单,和我们自己面临的问题一样,别人的问题也都是如何获取更好更多的利益。我们自己想明白了这一点,自然也就能想明白别人的问题。这个时候就能够问出正确的问题:如果问题不解决,究竟谁会有利益的损失? 如果问题解决了,究竟谁会有收益,谁的收益最大? 回答了这两个问题就找到了问题的主体。
只回答一个是没有用的,因为很多时候这个世界的事情,权责是不对等的。
架构师的权利和义务
架构师是要去平衡别人的利益,甚至会调整别人的利益的。一旦架构师是全心全意的为别人的利益服务,自然而然的架构师就拥有了强有力的影响力,肯定会是一个 leader。但是只是民意上的 leader 是没有用的,不能完全发挥架构师的能量。
架构师必须是一个组织的领导人,有权利调动这个组织的架构,才能够更好的发挥架构师的作用,更好的把利益的调整落到实处。
反过来,具备架构师能力的组织领导人,一定是一个很好的领导,这个组织一定是很健康向上的,因为每个人的权利和义务就是比较均等的。并且这类领导对于组织成员权利和义务的对等状况会非常的敏感,会及时的调整组织架构,在问题发生之前就解决了。这样这个组织就会具备更好的抗压能力,能够更好的为这个组织的客户服务,这个组织的成员内心一定都是比较平衡的,每个人的能力都能够得到比较好的发展。当然读者可能又会说,这不是管理学的东西吗? 是的,但也是架构的问题。所有架构的核心就是组织架构。或者也可以这样说,一个合格的组织领导人,一定必须是一个合格的架构师。
架构师必须能够超越对时间的恐惧 -- 也就是说必须具备了一定程度的自信,哪怕是装的,去真正的发现问题的主体,识别真正的问题,并把这个行为变成为自己面对问题的第一反应。架构师还必须要明白,所给出的解决方案 – 架构的分拆、合并方案,只有让问题的主体的权责对等,才能够真正的解决别人的问题。一般明白了问题的主体,以及主体的利益所在,做到这一点也没有问题。
架构师和技术
很多人会问,特别是做软件行业的,架构师是不是需要学习技术,甚至是学习语言? 如果一个架构师还有这个困扰—就如问这个问题的人,说明目前还不具备做架构师的能力,或者说还不具备对自己领域–哪怕是技术领域–的自信,更别谈业务领域了。
因为技术和语言,都是用来识别和解决所服务的主体的权责,保护并提升所服务的主体的权利的。特别对于软件领域来说,必须明白软件本身是怎么回事,解决什么问题,还要解决软件所服务的对象的领域本身是怎么回事,解决什么问题,这就要求更高了。语言和技术应该是随手拈来才对,对于架构师这些都是工具。学习技术和语言,如果明白了这些技术和语言要解决的是谁的问题,什么问题,学起来是非常快,非常容易的。
同样,采用哪个技术或者语言,只要某个技术或语言所解决的问题的主体,以及所解决的问题,和自己所面对的问题的主体和这个主体要解决的问题,这两者是匹配的,那么这个方案是成本是最低的,所采用的技术或者语言就是靠谱的。没有趁手的工具或语言的情况下,自己设计一个也不难,因为很清楚自己要什么。要不要自己做,无非是一个成本问题,也就是利益问题。并且从这个思路下去,选择的工具和语言肯定都是最简单的,成本是最低的。因为架构毕竟解决的还是人的利益问题,成本越低越好,这个成本当然是长期总体成本,不是眼前的短期成本。
八:从架构的角度看如何写好代码
软件实际上是对现实生活的模拟,虚拟化。这是一个非常重要的前提,直接决定了我们的代码应该分为几部分。结合每个部署单元所承担的责任,可以明确的拆分为两个不同的责任:
- 表达业务逻辑的代码。很多人把这部分叫做 Domain Logic,或者叫 Domain Model。这部分实际是来源于生活的,必须保持和现实生活中的切分一致,并非人为的抽象而成。
- 对用户提供访问并保存业务逻辑运行结果的代码。计算机的状态保存有一个缺陷,本机保留业务运行结果有很大的问题,一般都在外存储设备上保存,也便于扩展。
所以单个部署单元的代码可以分为两个部分,如下图所示:
软件代码的相关利益人为运行时的访问人员和存储设备。而service 的代码是最复杂的,需要服务于三方,代码人员的负担是最重的。为了把这三方的变化对service 的影响降到最低,对于service 还必须进一步的分拆为三个部分,让每一个部分都能够独立的变化,这样这三方的变化就不会产生连锁响应,降低成本。如下图所示:
这样,就划分成了几个责任:
- Service 就专注于 user 的需求,并组合 Glue Code 提供的服务完成需求。
- Glue Code 专注于组合 business 的调用,管理 Business 里面对象的生命周期,并且通过 Repository 保存或加载 Business 的状态
- Business 专注于实现业务的核心模型。
- Repository 专注于数据的保存,并和存储设备一一对应。
大家注意看,还是树形架构。并且左侧的主要需要计算机的相关理论知识,并且要直接面对用户的需求。右侧的更多的需要面对业务的核心。只要这几块的开发人员互相商量好了接口定义,这几个部分的开发就可以并行的进行,极大的提升开发的效率,缩短开发的时间。要做好这几部分,还需要注意,逻辑只允许存在于 Business 中,Service、Glue Code、Repository 都不允许存在业务逻辑。
为什么呢?首先我们来看看什么叫业务逻辑。
什么叫业务逻辑?
首先这个定义的前提是指软件代码中的逻辑,不是现实生活中的逻辑。在软件代码中,不需缩进和计算的顺序调用,包括缩进的代码目的是 catch exception 的,都不算逻辑,除此以外都是逻辑。
为什么说除了 Business 代码中有逻辑以外,其他地方不能有逻辑呢? 我们每个部分分别分析:
- 如果 service 里面不是严格的顺序调用,有很多分支,那么说明这个 service 做了两件或者两件以上的事情。必须把这个 service 分拆,确保每个 service 只做一件事情。因为如果不这么分拆的话,一旦这个 service 中的某各部分发生变动,其他的部分的执行必定会受影响。而确定到底有哪些影响的沟通成本非常高,其他相关利益方没有动力去配合,我们往往不会投入精力仔细评估。最后上线会出很多不可预料的问题,最终会导致损失用户的利益,并且肯定会导致返工,损坏自己的利益。如果是有计算的逻辑的话,比如受益计算,订单金额计算等,那么这部分应该是 Business 代码需要完成的,不能交给 service 代码来实现。
- Glue Code 里面如果不是严格的顺序调用,同理会和 service 一样遇到同样的问题。
- Repository 里面如果不是严格的顺序调用,包括存储访问的代码里面(比如 SQL),会导致逻辑进入到存储设备中。存储设备的主要目的是拿来存储的,一旦变成了逻辑计算的主体,就会导致存储设备无法通过增加机器的方式横向扩展长大。这个时候就没有架构了,只能换性能更好的机器,这个叫 scale up。只有 scale out 才能算架构。
以上都会导致架构无法快速的横向扩展和分拆,并且增加了修改的成本,这些是不符合开发人员以及业务的利益的。
这么做的好处有哪些呢?
- Service、Glue Code、Repository 里面的代码是严格的顺序调用,那么这些代码只要做连通性测试即可,不需要单元测试。因为这些代码都需要和很多上下文打交道,很难做单元测试。这样才算是真正的组合。
- Business 不访问任何上下文,不访问任何具体的设备,所以这部分代码是非常容易些单元测试的,并且单元测试必须 100% 覆盖。因为其他地方没有业务逻辑,所以一旦有问题,就可以断定是 Model 的问题,单元测试肯定可以发现。如果单元测试没有发现问题,那么单元测试一定有问题。线上问题的模拟也就变得非常的简单,单元测试也能够得到进一步的补充。
- Repository 很容易按照存储设备本身的最小访问粒度来完成工作,比如 DB,完全可以做到单表访问。因为这个时候存储设备只关心存取数据,完全和业务没有关系。做表的分拆也是非常容易的事情,存储设备通过增加机器就可以横向扩展长大。很多人会担心说,没有了 join,访问 DB 的次数是不是更多了,会导致性能下降? 按照现在网络的条件,网络访问和 Disk IO 访问的差距已经不大了,合理的设计下,多访问几次 DB 并不会导致这个问题。另外如果多台 DB 的话,还能通过并行加速访问。
- 由于 Service、Glue Code、Repository 代码简单了,才可以让我们的开发人员投入更多的时间研究业务,毕竟这部分才是软件所真正服务的对象。
实际的例子:
Manager 类实际就是 Glue Code。有几个注意点需要说明一下:
- 不能把 Business Model 当做数据对象来处理,Model 关心的实际上是业务行为,数据只是是这些行为的结果。所以 Glue Code 需要把 Model 转换为 Entity,Entity 和存储设备里面的存储粒度一一对应。比如在 DB 中,每个 Entity 对应一张表,并且跟着表的变化而变化,这样就保证存储的变更不会影响 Model。同样 Service 和用户之间的数据交互,也是不会和 Model 之间相关的,确保用户的需求变化,不会影响到 Model。因为用户的需求变化是最频繁的,没有逻辑,可以让我快速的满足业务的需求。
- 在 Service 这里,最好不要考虑代码重用。因为当多个不同的角色访问同一个接口,一旦某个角色的需求发生了变化,就会要求开发人员去修改。而这个修改往往会影响到其他的角色,需要这些角色一起配合来确定是否受影响,但是这些角色因为没有需求,往往不会配合。这样就给开发人员造成了很多不必要的沟通,成本是非常高的。最终都会导致线上 Bug,影响最终的用户。所以尽量给不同的角色不同的 Service,避免重用,降低沟通成本。很多人会说这样 Service 不就太多了吗? 这样 Service 注册,查找等管理需求就出现了,Service 治理中心就是来解决这个问题的。因为 Service 里面没有逻辑,所以开发和管理非常的简单,可以快速应对业务的变化。我们只有更快地变,更容易的变,才能更好地应对变。
- Business Model 是必须要重用的,一旦发现重用出现问题,那么说明 Business Model 的识别出现了问题,这是一个我们要重新思考 Model 的信号。Business Model 必须是一个完美的树状,如果不是,也说明 Model 的识别出了问题。
在实际操作中,Service、Glue Code、Repository 不能有逻辑,实际上和很多人的观念是冲突的,认为这个根本做不到。做到这一点需要很多的学习成本,但是一定可以做得到。当发现做不到的时候,可以断定是业务的分析出了问题。比如不该合并的合并了,不该计算的计算了。这个问题一定有办法解决的,做不到都是理由,无非是想早点把自己的工作结束罢了。虽然刚开始会比较困难,一旦把这个观念变成自觉,开发的质量和效率马上就能高好几个级别。
“业余选手,越想从水里浮起来,就越想把头抬起来,身体反而沉下去。只有克服恐惧,把头往水里压下去,身体才能够从水里浮起来。真正专业的习惯往往是和我们日常的行为相反的”
我们真正想快速的完成代码工作,就要克服自己对时间的恐惧,真正的去研究业务的问题,相关 stakeholder 的利益,把这个变成我们的习惯。写代码的时候让该出现逻辑的地方出现逻辑,让不该出现的地方不能出现。一旦不该出现的地方出现了逻辑,那么要马上意识到,这个地方是一个坑,这个问题一定和业务的分析不透彻有关系。
以上只是针对单一的 Service 部署单元的分析,扩展开去,对于其他的部署单元也是类似的。每个单元的下一级都可以认为是 Repository,每个单元的上一级都可以认为是 User。这些实践在作者自己的项目中都有用到,非常的有效,迭代的速度非常的快。很多人担心 Business Model 建不好,其实没关系,刚开始可以粗糙一点,后续可以慢慢的完善。这个架构已经隔离好了每个部分的变化对其他部分的影响,变化成本都在可控的范围之内。
九:理清技术、业务和架构的关系
作为架构师或者做技术的人,在开发软件时,基本上就是在扮演上帝的角色:不但要创建出一个个的程序,还要让这些程序能够脱离我们在硬件上独立运行,以便为这个程序所服务的群体提供服务。当这个程序出现问题甚至 bug 的时候,我们还得扮演牧师的角色去修复这些问题。这不正是一个程序的社会吗? 和人类社会的演变何其相似!那么我们自然也能够拿人类演变的历史来指导软件开发工作,以避免再经历一次像人类演变发展那么痛苦的过程了。由此我们也可以看出,架构师和程序员们都在扮演着多么重要的角色,如果还在解决自己的问题,怎么扮演好上帝这个角色?
在软件设计开发的过程中经常会看到,很多所谓的架构讨论实际上只是在讨论某种技术。在很多人的概念里面,架构和技术实际上是等同的。学会了几种技术,就认为自己是架构师了,甚至是学习的技术越多,就觉得自己的水平越高。这样实际上是对自己很不负责任的。要知道任何技术都是为了解决某种问题而存在的,学会了技术,并不代表自己能够解决问题,这一点非常的重要。学会的技术的多少,所带来的差别只是自己解决问题的手段多了罢了。
还有另一种很普遍的观点:技术人普遍看不起业务,认为技术更高端,而业务太低端,并且业务往往喜欢给技术挖坑。业务则觉得技术眼光高,但是实际解决不了问题,总是理解有偏差,但是又无可奈何,因为自己不会。
本篇文章尝试从这里入手,分析一下这三个概念到底有什么关系,我们应该怎么处理业务、技术还有架构的关系。
什么是技术
当我们一无所有,或者什么都不会的时候,这个时候实际上是没有技术的。就好比人类在最早期,什么都得用自己的双手来干活。一旦我们在日常生活中无意间发现某些规律的时候,我们就可以通过创造条件,让这个规律重复的发生。通过人为创造条件,让指定的规律按照人类的意愿发生,这就是技术。
比如取火,最早人类只能靠打雷等自然现象产生火。取火其实就是一个业务目标,要解决的是人类自己的问题,这就是业务,实际就是人类的利益。
双手快速转动取火-〉弓弦来提升木棍转动的速度取火:
- 业务目标是为了取火,钻木取火这个技术的出现解决了这个问题。
- 钻木取火的效率不高,影响了业务(取火)的效率,就有了进一步改进的动机,改进转动木棍的方式,产生了弓弦转动木棍的技术。
技术与架构,以及与业务之间的关系
技术总是在人类解决对业务的要求不断提高的情况下产生,目的也是为了获取更大更好的利益。所以:
- 技术是为了解决业务的问题而产生的,没有了业务,技术就没有了存在的前提。
- 有了更好的技术,效率更差的技术,就会慢慢的被淘汰,消失,一切都遵从人类的利益诉求–也就是业务。有人会问,不用钻木取火了,但是弓弦加速转动木棍还可以用啊? 没错,因为弓弦转动木棍这个技术,不是来生火的,是用来加速木棍转动的,所解决的问题不一样。但是两种不同的技术,合理结合起来,会更好更有效率的解决业务问题。
所以技术与技术之间,有两种关系:
3. 在解决同一个业务问题的前提下,更高效,更低成本的技术,会淘汰低效,高成本的技术。这是人类利益诉求所决定的。
4. 一般刚开始解决根本问题的技术(钻木取火)的效率是比较低的,只是把不可能变成了可能(从这一点上来说,技术才是业务的 enabler)。然后就会有提高效率的需求出现,要求改进这个技术。这个技术的低效率部分就会被其他人(或者技术发明人自己)加以改进,这部分就会形成新的技术。
当关系 2 发生的时候,这个地方必定会形成一个切分,新技术会通过某种方式和原有的技术连接在一起形成一个整体,让这个新的技术可以和原有技术共同工作,使得原有的技术可以用更高的效率解决问题。因为要解决的主要问题(生火)并没有发生改变,分拆所形成的是一个树状的结构。
按照前面的架构定义,这个时候其实已经产生了架构。也就是说,一般是先有技术,才会有架构。这些其他技术(弓弦拉动木棍),是从直接解决问题的初始主要技术中分拆出来形成的,并通过树状结构和主要技术(钻木取火)组合在一起。在解决主要问题(生火)之后,再开始逐渐的分拆为更为细粒度的技术(弓弦转木棍)。
而这个细粒度的技术(弓弦转动木棍)往往不会和业务的主要目标(生火)发生直接的关系。不同的技术,通过树状结构,组合在一起,形成了一个完整的架构解决方案,共同完成业务的目标。这就是技术,业务和架构之间的关系。很多人把这个过程称为架构的进化,我更愿意把这个过程称为技术的进步所导致的新的架构分拆,因为这个过程内在的动力,更多的是来自技术对解决业务问题的解决。
技术人员和业务人员的关系
为什么技术人员总是和业务人员发生冲突呢? 这是因为技术人员很多时候关心的技术,和业务的主要目标往往不是直接对应的,业务也是负责某一部分的业务,也不是和业务的主要目标直接对应的,都是树的分支节点(上文已经解释了为何会发生这种情况)。只有直接解决业务问题的那个技术(或业务)–树的根节点–会和业务直接相关。所以一旦产生冲突,一般必须两个根节点(一般都是领导)碰面才能解决问题,就是这个原因–他们都知道业务主要目标。这也是为什么下层无法理解上层,而上层都喜欢下军令状,要求下层执行。人只有尽量去理解上层的问题才能做下层的分拆。
在软件行业,这个根节点技术就是软件。这也是为什么架构师要认识什么叫软件,软件解决谁的问题,什么问题,软件本身又是怎么分拆的,才能够更好的组合不同的技术,完成业务的目标。而软件里面和业务直接相关的,只有 Business Domain 这一部分。
用人来打比方,Business Domain 相当于人的大脑,而 Service,Repository,Glue Code 等部分所采用的技术,全部都是计算机自己领域的技术,都是为了能够让程序跑起来,相当于人的四肢。我们大部分开发人员的工作主要专注于四肢部分。我们真正应该投入的是大脑部分。因为大脑能够决定四肢长什么样,而不是反过来。很多架构师、技术人员主要专注于计算机相关的技术,忽略了业务本身,甚至看不起业务,这也是为什么技术总是和业务冲突的原因。
架构师应该承担起解决业务问题的这个角色来,专注于 Business Domain 和软件本身的架构,让技术人员致力于为业务在计算机中跑起来而努力。只有把这两者很好的结合起来,才能更好地完成业务的目标,才会让软件更好地服务于大家。最终一定会得到一个很好的软件架构,令软件开发团队和业务部门都能够很好地开展工作并降低成本。
重新发明轮子
当现有已经存在很多技术,而这些技术却和我们所要解决的问题并不是那么直接对应的时候,我们就需要有意识的组织和识别不同的技术,来实现业务的目标。这个时候组织的方式有很多种,其中成本最低的方法就是按照要达成的目的和当前的问题,从上到下进行架构分拆。分拆出来的更细粒度的问题,分解到不同的人来进行解决,就形成了业务架构和组织架构。解决这些问题就需要组合很多不同的技术,那么应该采用哪些技术?还是自己重头实现一个? 自己实现一个—这就是很多人所谓的重新发明轮子。以下试着分析一下:
- 当技术所解决的问题和分拆出来要解决的问题,完全匹配的时候,这是最完美的。比如需要提供 web 要访问的 service,很多 MVC 的 framework 就可以很好的满足这一点。而这个时候如果非要自己实现一个,很有可能就是重新发明轮子。
- 当技术所提供的能力远远超过需要解决的问题时,往往掌握技术和维护技术会成为瓶颈。因为越复杂的技术,成本越高。如果自己实现一个仅仅是解决当前问题的方案,可能成本反而更低。这也是为什么很多大型的互联网公司不断地开源出来自己的技术的原因。而这些技术对于我们来说是否适用?他们原本是用来解决谁的问题的?什么问题?如果不清楚这些,就冒然采用,可能会导致更高的成本。
- 当技术所提供的能力和我们所要解决的问题部分匹配时,还是要看成本。比如当我们需要一个锤子的时候,手边正好没有,但是却有一只高跟鞋,勉强也可以替代锤子。但是长期来看,这么用不划算,因为高跟鞋的价格比锤子高很多,耐用性差很多,维护成本也高很多。
所以,准确识别采用什么技术的能力,也是架构师所要具备的能力之一。考虑的主要因素也是长期的成本和收益。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架