什么是软件架构师
在现实生活中,具备软件架构师头衔的人,大都是从软件工程师成长出来的,这个出身已经决定了他们的主要关注点是在软件和CS上。而要真正成长为一个架构师,首先需要克服的就是时间困境。为什么软件工程师会对时间有恐惧和压力呢?其原因是他们把按时完成自己的工作当成了自己的最大利益,并且对业务的不了解也会导致他们没有太大的把握。这就要求软件架构师把完成业务的工作当做自己的最大利益,深入到业务中去。随着对业务的熟悉,对时间的恐惧才会慢慢地消失。
生命周期的思考
作为软件架构师,必须时刻把软件的生命周期和业务的生命周期的识别放在第一位,软件生命周期的核心在于软件运行生命周期,以及围绕软件运行生命周期的拆分和组织,业务生命周期的核心在于围绕业务核心生命周期的拆分和组织。在代码层面,要对业务代码和访问代码做好架构拆分。架构师的核心在于架构的执行,软件架构师必须是一个组织的领导人,有权利调动这个组织的架构,才能更好地发挥架构师的作用,才能把软件开发生命周期、软件运行周期和业务生命周期的拆分落实执行。
对待技术的态度区别
技术人员对待不同技术是有区别的,往往是什么技术流行就追什么技术。技术人员也热衷于创造新的技术,以对技术的掌握作为自己的标签。也就是说技术人员对于技术是不平等的,而架构师则不一样,无论是新的还是旧的技术,只要场景合适,他们都会采纳。
架构师思考技术时更多地考虑技术对生命周期拆分的支撑,以及不同技术实现拆分时落地的成本和收益。以最少的成本达到更高的增长,是每个架构师追求的目标。
软件工程师的迷惑和使命
很多软件工程师学了大量的算法和计算机基础,然而在工作中派不上用场,这时非常正常的。在业务领域,大多是如何解决现有的业务在软件中模拟出来的问题,并没有太多高深的数学问题。硬件成本的降低也让我们不需要斤斤计较地抠时间和空间复杂度,这些都导致所学不能致用。
对于传统企业而言,在软件工程师慢慢理解并掌握了业务之后,慢慢就会看到传统企业各种低效的地方,也会尝试着去改变现状。软件和业务最终还是要合体的。当前软件工程师专职于开发服务于业务的形式只是一个过程,经过这个过程的普及,掌握业务的软件工程师未来会更受欢迎。
迭代
迭代应该如何进行呢?迭代的前提是,必须要先确定优先级,而理清楚业务的核心生命周期是最高优先级,首先要实现业务的核心生命周期,刚开始可以简陋一点,效率可以低一点,此时一般也不需要太多人参与,成本也不会太高。当业务人员或者使用用户可以操作软件之后,对软件进行反馈,形成反馈环之后,软件就可以通过一次次的迭代,丰富核心生命周期的功能。
如何写好代码
要让代码容易维护,还要和业务一起长大,使得软件架构容易随着业务长大做出新的拆分,合并,并要保证其正确性。代码主要由两部分组成:
- 表达业务生命周期的代码,也叫做业务逻辑(Domain Logic),或者叫业务模型(Domain Model)。这部分是来源于生活与业务,要和现实生活中业务人员的职责拆分一致,并保持内聚。内聚,是指某个生命周期的变化是累积在一个生命周期主体上的,就是指一个对象。
- 表达用户访问生命周期的代码。为了让用户能够访问到所模拟的业务逻辑,则必须要提供访问的通道。
所以代码又可以分为三部分,业务(Business)部分来实现业务的逻辑,完成对业务生命周期的模拟。业务的状态要靠存储(Repository)来实现存储持久化。那服务(Service)是用来做什么的呢?
首先,由于计算机和软件没有自己的意志,因此其内部生命周期的变化就要由外部的人来推动,这时需要提供一个访问通道给外部的用户,但如果把业务直接给用户访问,那么用户是很难和业务沟通的,因为这些专业术语,不是用户能够理解的。比如客户去银行,接待客户的是更接近用户语言的银行柜员,而不是银行内部的专业业务人员。柜员就是一个服务,以用户听得懂的方式和用户沟通,并把客户的要求转换成业务的语言,再由银行内部的专业人员执行相应的操作,柜员最后把执行的结果转换为用户的语言,为其服务。所以这里服务提供的是一个访问信道,为用户提供一个容易访问专业服务的访问方式。那么服务做为通道的含义是什么呢?通道的意思是只负责调用业务逻辑,但不包含业务逻辑,这也意味着服务代码中是不能包含业务逻辑的。
黏合代码是什么意思呢?业务逻辑属于行为是没有记忆的,而存储属于记忆是没有逻辑的。要把行为和记忆黏合在一起,才能够模拟一个人。黏合代码相当于是一个具备行为和记忆的完整业务人,服务作为通道把黏合代码和用户联系起来。有些人会问,为何不把存储挂在服务上,这样黏合代码就不需要了。但这样相当于是让银行核心业务人员直接接待用户。用户的需求是变化最频繁的,服务的方式可以避免频繁的用户需求变化对内部分工的冲击。没有服务的保护会导致用户的需求直接冲击存储,而存储非常脆弱必须保护起来。
还有人会问,为何不把存储挂在业务上,这也是可以的。但这会让关心业务模型的代码人员,受到存储的影响,必然无法专注于业务生命周期上。因此代码就划分出了以下责任:
1. 服务专注于用户的需求,通过组织黏合代码,也就是虚拟人所提供的生命周期活动完成需求。
2. 黏合代码专注于管理业务中对象的生命周期,并且通过存储保存或加载业务中对象的状态,实现对业务虚拟人的模拟。
3. 业务专注于实现业务的生命周期活动。
4. 存储专注于数据的保存和加载,并让数据和存储设备的村存储粒度一一对应。
分工之后大家需要的知识储备可以减少一些,只要不同部分的开发人员互相商量好接口定义,不同部分的开发就可以并行地进行,不仅提升了开发效率并且缩短了开发时间。
我们可以看到业务中的代码是最重要的,服务与黏合代码中的代码起通道作用,这时为了让用户的请求能够访问到业务代码。访问逻辑的特定是组合代码,即常见的顺序调用,这种代码中既不会有计算也不会有if else等判断,用于组合下一层的节点所提供的功能,方便上一层节点的调用。
业务逻辑分散的危害
如果业务逻辑不是内聚的就会散落到很多其他地方去,那么会造成哪些问题呢?
如果服务代码中混入了业务逻辑,则服务做了两件或者两件以上的事情,服务本身的责任是访问逻辑,这是顺序执行,假如了业务逻辑就表明做了两件或两件以上的事情,可以分为以下两种情况:
- 典型的情况就是两个不同的访问生命周期合并在一个服务中实现。比如两个不同类的用户共享一个服务方法,并在服务中判断区分这两类的访问分别处理,这就是人为造成的不必要逻辑。一旦某个用户访问生命周期发生变动,共享的另一个访问生命周期必定会受到影响。
- 如果是有计算的逻辑的话,比如受益计算、订单金额等,那么这部分应该是业务代码需要完成的,不能交给服务代码实现。这部分代码是需要单元测试的,而服务代码要和用户打交道就会有上下文相关的代码,因此不适合做单元测试。
如果存储代码中混入了业务逻辑,则会导致业务逻辑进入到存储设备中。编写存储访问代码的语言常见的是SQL,如果业务逻辑混入了SQL,会导致SQL写得很复杂,里面会做很多判断和计算。
通过以上分析可以看到,业务逻辑如果不内聚的话,分散到哪里,哪里就会受到限制,并且最后都会导致架构无法快速得横向扩展和拆分,增加修改的难度、不确定性和成本。
下一篇就来到聊聊架构的终结篇聊聊架构(4)