“所有模型都是错误的,有些模型是有用的”——GeorgeBox没有放之四海而皆准的好坏标准。以下是我衡量软件架构质量的AAA原则:负责:良好的软件架构允许每个团队都有自己的业务目标。Autonomous:一个好的软件架构可以让每个团队都有一定的Autonomy可以独立前行,不会总是被其他团队挡住Amortized:好的软件架构可以鼓励对未来的投资,这样基础设施的成本就可以摊销。评估>>自主性>可重用性使用。在20世纪90年代,代码重用是面向对象社区的热门话题。那么SOA和DDD就来告诉我们,“自治”才是最重要的。但是我发现在实践中,究竟是“自治”还是“可重用”,是很模糊的。很难用这两个原则来说服别人用X方式分解问题比用Y方式分解问题要好。但是如果说这样的分解可以让每个团队更容易被审计,就显得很自然了。开发者无法预估工作量“问责制”是一切的关键。我认为“缺乏可审计性”是当前软件开发模式最大的危机,这个问题比“无法管理所谓的复杂性”更为严重。开发人员无法估算工作量在业界已经不是什么秘密了。这就带来了很多根本性的问题:由于我们无从知道真正需要多少人才,中层管理人员总是比招聘上限尽可能多地加人。他们为什么这样做呢?很简单,他们的薪酬与他们管理的负责人数量成正比。将软件重构为“更易于维护”没有商业价值。什么是可维护性?解决不了的问题,投入更多的人总能解决。软件工程不是造火箭,能有多难?无法证明重构可以节省多少人力,因为重构之前没有可比的人力。要解决这个问题,我认为不是弄清楚开发工作量评估的魔力。相反,如果我们和业务领导团队合作,根本就不需要预估工作量。每个软件开发团队都有对应的业务团队,应该是“唯一”。业务团队背什么样的OKR,技术团队背什么样的OKR。要使团队可考核,最重要的是只负责一项业务。以上是典型的组织结构图。每个小团队的OKR必须与其上层团队的OKR保持一致。只有当OKR中的关键产出是可衡量的时,每个团队才能真正对某件事负责。一个典型的糟糕的软件架构是这样的:有大量的微服务团队。企业主总是需要直接去多个微服务团队来实现他的目标。每个需求都需要与多个不同的软件团队反复沟通。每个技术团队都无法清楚地阐明他们和他们的微服务负责的业务目标。正因为如此,技术人员无法判断他们对业务有什么价值。让我们再说一遍:软件架构的“首要目标”应该是让每个分散的团队对业务目标负责。BoundedContext在大范围上,架构就是对BoundedContexts进行分解(见领域驱动开发,DDD)。这是为了将业务组织结构图反映到软件世界中:以电子商务领域为例,将业务分解为上述限界上下文。没有技术团队可以涵盖跨这些限界上下文的业务流程。这不是一件坏事,大问题被分解成小问题,业务和技术在限界上下文的范围内朝着共同的目标共同努力。虚拟空间和智能体ABoundedContext对于一个团队来说还是太大了。至少在微服务思维中。你如何将它分解成更易于管理的块?我的模型是“虚拟空间和代理”。我们作为程序员所做的事情,简单来说就是两件事:虚拟空间中的智能“机器人”与虚拟空间中的我们人类进行交互。是基于因果关系。支配这些因果关系的规律有两种:自然规律:自然界本身的内在规律社会规律:一种人为的制度,人们通过模仿自然规律来建立类似稳定的规则体系,以建立稳定的社会秩序例如,引力是自然法则。而“借钱必还”是社会规律。两者的工作方式相似,给定特定的前因,根据法律,必然有特定的后果。我们用C/C++/Java/GO/…等来描述这些规律。从光线追踪算法到word文本编辑器再到电商交易平台,从构建规则的角度来看几乎是一样的。“法则”必须是静态的和可预测的,就像构成我们现实世界的水泥一样。在我们构建的IQ虚拟空间中,我们作为人类彼此进行交互,例如社交网络和交易。人类扮演的角色正逐渐被我们简称为人工智能的“机器人”所取代。比如,以前是人工编辑选内容,现在机器人可能会生成新闻,准备首页让你每天打开。“机器人”越来越精良,总有一天他们会从虚拟空间中走出来,直奔物理空间。“虚拟空间”和“机器人”这两种软件代码的工作方式有很大的不同。“虚拟空间”从因推演效果,维护自然和社会秩序。“机器人”反向工作,收集事实并推导模型以优化其目标。将智能部分与系统的其余部分清楚地区分开来至关重要。作为人类,我们希望规则是静态的,以便构建稳定的期望。如果“规律”总是在变化,那么“虚拟空间”就像一个“魔幻空间”,与我们从现实空间中得到的生活体验就大不相同了。软件开发中的模型、视图、控制器(MVC)的概念可以用来解释“虚拟空间”。人类和“机器人”是所谓的智能生物。模型根据自然和社会法则定义的因果关系维护数据完整性。View和Controller为人类和“机器人”进行交互提供了一个方便的接口。所有权==版权“虚拟空间”部分还是太大了。业务流程可能有很多步骤,例如:不同限界上下文的业务流程也有集成关系:可审计性问题的根源在于编程语言缺乏对完整因果链的直接描述。我们可以在白板上画出清晰的业务流程图,但是在编写代码的时候,我们不需要将其分成很多细粒度的服务和功能来表达。之所以一直关注工作流引擎,是因为它的描述能力与所要解决的问题有很好的映射关系。但是BPMN不是一种编程语言。步骤之间存在很强的因果关系。产品详情页面上显示的促销活动也应反映在购物车、结帐页面和最终收据中。我们使用的“函数”这个概念最多只能用来描述500ms以内发生的事情之间的因果关系。对于上面提到的业务流程,我们把它分成了很多步骤,同时根据不同的用户,把它分成了很多面向用户的服务。因此,因果关系隐藏在这些复杂的实现细节中。软件的运行就像一场接力赛。一个服务接管了责任,做完之后,再交给另一个服务。理想情况下,代码本身应该包含一个流程图并且读起来像流程图。更糟糕的是,目前的分割方法并没有明确的划线原则。这经常导致团队之间争论谁应该对什么负责。高度政治化的组织氛围导致开发人员情绪低落。同时,具有讽刺意味的是,大家在各自为战的同时,由于职责过于分散,没有一个团队能够包揽大局。要解决这个问题,目前能做的“最佳实践”就是在一堆微服务团队上架设一个门面团队。“所有权==版权”,我们只愿意为自己写的东西负责。这种人性是无法改变的。为了给这些可怜的家伙一种主人翁感,我们必须允许一个薄的代理层,或者所谓的调度服务,来“屏蔽”后面的微服务。但是这种代理层方法通常会导致团队自主权非常低。理想的编程语言应该能够提供类似“函数”的东西来直接描述业务流程。并发的并发业务流程应该用消息传递的方式来描述,就像多线程编程一样。这样,我们就可以指定一个独立的软件团队来负责每一个可以端到端切分的业务流程。他们可以对自己负责的事情负起100%的责任。这些人、业务经营者和编程的“机器人”作为同一个团队一起工作,共同负责这个业务流程的盈亏。它不再单独提取技术,而是成为共享成本中心。协作单元除此之外,还有一个问题。以前编程语言提供的模块化单元,比如assembly/package/class,是我们团队相互协作的单元。这已不再是这种情况。现在越来越多的人要求软件模块有独立的版本,能够独立部署。因为它支持多个团队的独立性。这导致了大量的微服务实践。但是我们“总是”需要使用不同的编程语言和不同的工具来实现微服务吗?语言差异和单独的工具使跨团队沟通更加困难。你可以拥有你的流程,拥有你的服务,但这并不妨碍你与你的合作伙伴说同一种语言。一个编程同时扮演三个角色:连接机器,连接开发者,同时连接团队。今天的编程语言更多的是一种连接机器和个体开发者的工具,团队在宏观上是相互分离的。解决办法应该是把软件作为一个整体来考虑,而不是被“操作系统进程”的狭隘视角所局限。构建一个新的微服务的成本应该与在后台启动一个带有函数的线程相差无几。在一个理想的编程语言中,我们有各种各样的功能,只是执行机制不同而已。
