1、抽象思惟程序员 若是要问软件研发/系统架构中最重要的能力是什么,我会绝不犹豫回答是抽象能力。抽象(abstraction)这个词你们常常听到,可是真正理解和能讲清楚什么是抽象的人少之又少。抽象实际上是这样定义的:面试 对某种事物进行简化表示或描述的过程,抽象让咱们关注要素,隐藏额外细节。算法 举一个例子,见下图:编程  你看到什么?你看到的是一扇门,对不对?你看到的不是木头,也不是碳原子,这个门就是抽象,而木头或者碳原子是细节。另外你能够看到门上有个门把手,你看到的不是铁,也不是铁原子,门把手就是抽象,铁和铁原子是细节。数据结构 在系统架构和设计中,抽象帮助咱们从大处着眼(get our mind about big picture),隐藏细节(temporarily hide details)。抽象能力的强弱,直接决定咱们所能解决问题的复杂性和规模大小。架构 下图是咱们小时候玩的积木,我发现小时候喜欢玩搭积木的,而且搭得快和好的小朋友,通常抽象能力都比较强。框架  上图右边的积木城堡就是抽象,这个城堡若是你细看的话,它其实仍是由若干个子模块组成,这些模块是子抽象单元,左边的各类形状的积木是细节。搭积木的时候,小朋友脑壳里头先有一个城堡的大图(抽象),而后他/她大脑里头会有一个初步的子模块分解(潜意识中完成),然用利用积木搭建每个子模块,最终拼装出最后的城堡。这里头有一个自顶向下的分治设计,而后自底向上的组合过程,这个分治思惟很是重要,咱们后面会讲。数据结构和算法 我认为软件系统架构设计和小朋友搭积木无本质差别,只是解决的问题域和规模不一样罢了。架构师先要在大脑中造成抽象概念,而后是子模块分解,而后是依次实现子模块,最后将子模块拼装组合起来,造成最后系统。因此我常说编程和架构设计就是搭积木,优秀的架构师受职业习惯影响,眼睛里看到的世界都是模块化拼装组合式的。ide 抽象能力不只对软件系统架构设计重要,对建筑、商业、管理等人类其它领域活动一样很是重要。其实能够这样认为,咱们生存的世界都是在抽象的基础上构建起来的,离开抽象人类将步履维艰。模块化 这里顺便提一下抽象层次跳跃问题,这个在开发中是蛮广泛的。有经验的程序员写代码会保持抽象层次的一致性,代码读起来像讲故事,比较清晰易于理解;而没有经验的程序员会有明显的抽象层次跳跃问题,代码读起来就比较累,这个是抽象能力不足形成。举个例子:  一个电商网站在处理订单时,通常会走这样一个流程: 1.更新库存(InventoryUpdate) 2.打折计算(Discounting) 3.支付卡校验(PaycardVerification) 4.支付(Pay) 5.送货(Shipping) 上述流程中的抽象是在同一个层次上的,比较清晰易于理解,可是没有经验的程序员在实现这个流程的时候,代码层次会跳,比方说主流程到支付卡校验一块,他的代码会忽然跳出一行某银行API远程调用,这个就是抽象跳跃,银行API调用是细节,应该封装在PaycardVerification这个抽象里头。 2、分层思惟 除了抽象,分层也是咱们应对和管理复杂性的基本思惟武器,以下图,为了构建一套复杂系统,咱们把整个系统划分红若干个层次,每一层专一解决某个领域的问题,并向上提供服务。有些层次是纵向的,它贯穿全部其它层次,称为共享层。分层也能够认为是抽象的一种方式,将系统抽象分解成若干层次化的模块。  分层架构的案例不少,一个中小型的Spring Web应用程序,咱们通常会设计成三层架构:  操做系统是经典的分层架构,以下图:  TCP/IP协议栈也是经典的分层架构,以下图:  若是你关注人类文明演化史,你会发现今天的人类世界也是以分层方式一层层搭建和演化出来的。今天的互联网系统能够认为是现代文明的一个层次,其上是基于互联网的现代商业,其下是现代电子工业基础设施,诸如此类。 3、分治思惟 分而治之(divide and combine或者split and merge)也是应对和管理复杂性的通常性方法,下图展现一个分治的思惟流程:  对于一个没法一次解决的大问题,咱们会先把大问题分解成若干个子问题,若是子问题还没法直接解决,则继续分解成子子问题,直到能够直接解决的程度,这个是分解(divide)的过程;而后将子子问题的解组合拼装成子问题的解,再将子问题的解组合拼装成原问题的解,这个是组合(combine)的过程。 面试时为了考察候选人的分治思惟,我常常会面一个分治题:给你一台8G内存/500G磁盘空间的普通电脑,如何对一个100G的大文件进行排序?假定文件中都是字符串记录,一行约100个字符。 这是一个典型的分治问题,100G的大文件确定没法一次加载到内存直接排序,因此须要先切分红若干小问题来解决。那么8G内存的计算机一次大概能排多大的数据量,能够在有限的时间内排完呢?也就是100G的大文件要怎么切法,切成多少份比较合适?这个是考察候选人的时间空间复杂度估算能力,须要必定的计算机组织和算法功底,也须要必定实战经验和sense。实际上8G内存的话,操做系统要用掉一部分,若是用Java开发排序程序,大体JVM可用2~4G内存,基于通常的经验值,一次排1G左右的数据应该没有问题(我实际在计算机上干过1G数据的排序,是OK的)。因此100G的文件须要先切分红100份,每份1G,这样每一个子文件能够直接加载到内存进行排序。对于1G数据量的字符串排序,采用Java里头提供的快速排序算法是比较合适的。 好,通过有限时间的排序(取决于计算机性能,快的一天内能排完),假定100个1G的文件都已经排好了,至关于如今硬盘上有100个已经排好序的文件,可是咱们最终须要的是一个排好序的文件,下面该怎么作?这个时候咱们须要把已经解决的子问题组合起来,合并成咱们须要的最终结果文件。这个时候该采用什么算法呢?这里考察候选人对外排序和归并排序算法的掌握程度,咱们能够将100个排好序的文件进行两两归并排序,这样不断重复,咱们就会获得50个排好序的文件,每一个大小是2G。而后再两两归并,不断重复,直到最后两个文件归并成目标文件,这个文件就是100G而且是排好序的。由于是外排序+归并排序,每次只须要读取当前索引指向的文件记录到内存,进行比较,小的那个输出到目标文件,内存占用极少。另外,上面的算法是两路归并,也能够采用多路归并,甚至是采用堆排序进行优化,可是整体分治思路没有变化。 整体上这是一个很是好的面试题,除了考察候选人的分治思惟以外,还考察对各类排序算法(快排,外排序,归并排序,堆排序)的理解,计算的时间空间复杂度估算,计算机的内外存特性和组织,文件操做等等。实际上能彻底回答清楚这个问题的候选人极少,若是有幸被我面到一个,我会如获至宝,由于这我的有成长为优秀架构师的潜质。 另外,递归也是一种特殊的分治技术,掌握递归技术的开发人员,至关于掌握了一种强大的编程武器,能够解决一些通常开发人员没法解决的问题。比方说最近个人团队在研发一款新的服务框架,其中包括契约解析器(parser),代码生产器(code generator),序列化器(serializer)等组件,里头大量须要用到递归的思惟和技术,没有这个思惟的开发人员就干不了这个事情。因此我在面试候选人的时候,通常都会出递归相关的编程题,考察候选人的递归思惟。 大天然中递归结构比比皆是,以下图,你们有兴趣不妨思考,大天然经过递归给咱们人类何种启示?   4、演化思惟 社区里头常常有人在讨论:架构是设计出来的?仍是演化出来的?我我的基于十多年的经验认为,架构既是设计出来的,同时也是演化出来的,对于互联网系统,基本上能够说是三分设计,七分演化,并且是在设计中演化,在演化中设计,一个不断迭代的过程。 在互联网软件系统的整个生命周期过程当中,前期的设计和开发大体只占三分,在后面的七分时间里,架构师须要根据用户的反馈对架构进行不断的调整。我认为架构师除了要利用自身的架构设计能力,同时也要学会借助用户反馈和进化的力量,推进架构的持续演进,这个就是演化式架构思惟。 固然一开始的架构设计很是重要,架构定系统基本就成型了,不容马虎。同时,优秀的架构师深知,可以不断应对环境变化的系统,才是有生命力的系统,架构的好坏,很大部分取决于它应对变化的灵活性。因此具备演化式思惟的架构师,可以在一开始设计时就考虑到后续架构的演化特性,而且将灵活应对变化的能力做为架构设计的主要考量。 当前,社区正在兴起一种新的架构方法学~演化式架构,微服务架构就是一种典型的演化式架构,它可以快速响应市场用户需求的变化,而单块架构就缺少这种灵活性。马丁·福乐曾经在其博客上给出过一张微服务架构的演化路线图[附录8.2],能够用来解释设计式思惟和演化式思惟的差别,以下图所示:  上面的路线是一开始就直奔微服务架构,其实背后体现的是设计式架构的思惟,认为架构师能够彻底设计整个系统和它的演化方向。马丁认为这种作法风险很是高,一个是成本高昂,另一个是刚开始架构师对业务域理解不深,没法清晰划分领域边界,开发出来的系统极可能没法知足用户需求。 下面的路线是从单块架构开始,随着架构师对业务域理解的不断深刻,也随着业务和团队规模的不断扩大,渐进式地把单块架构拆分红微服务架构的思路,这就是演化式架构的思惟。若是你观察现实世界中一些互联网公司(例如eBay,阿里,Netflix等等)的系统架构,大部分走得都是演化式架构的路线。 下图是建筑的演化史,在每一个阶段,你能够看到设计的影子,但若是时间线拉得足够长,演化的特性就出来了。  5、如何培养架构设计思惟 良好的架构设计思惟的培养,离不开工做中大量高质量项目的实战锻炼,而后是平时的学习、思考和提炼总结。 另外,基本的架构设计思惟,其实在咱们大学计算机课程(好比数据结构和算法)中能够找到影子,只不过当时以学习为主,问题域比较小和理想化。因此大学教育其实很是重要,基本的架构设计思惟在那个时候就已经埋下种子,后面工程实践中进一步消化和应用,随着经验的积累,咱们可以解决的问题域复杂性和规模逐渐变大,但基本的武器仍是抽象、分层和分治等思惟。 我认为一个架构师的成长高度和他大学期间的思惟习惯的养成关系密切。我所知道世界一流的互联网公司,例如谷歌等,招聘工程师新人时,对数据结构和算法的要求能够用苛刻来形容,这个能够理解,谷歌级别公司要解决的问题都是超级复杂的,基本思惟功底薄弱根本没法应对。 对于工做经验<5年的工程师新手,若是你大学时代是属于荒废型的,建议工做之余把相关课程再好好自学一把。我的推荐参考美国Berkeley大学的数据结构课程CS61B[附录8.1]进行学习,对创建抽象编程思惟很是有帮助,我本人在研究生阶段自学过这门课程,如今回想起来确实受益不浅,注意该课程中的全部Lab/Homework/Project都要实际动手作一遍,才有好的效果。  我当年自学的是CS61B 2006秋季版的课程,上图是课程Logo 对于演化设计思惟,当前的大学教育其实培养不多,相反,当前大学教育大都采用脱离现实场景的简化理想模型,有些仍是固定答案的应试教学,这种方式会形成学生思惟肯定化,不利于培养演化式设计思惟。我我的的体会,演化式设计思惟更多在实际工做中经过实战锻炼和培养。 结论 1.架构的本质是管理复杂性,抽象、分层、分治和演化思惟是架构师征服复杂性的四种根本性武器。 2.掌握了抽象、分层、分治和演化这四种基本的武器,你能够设计小到一个类,一个模块,一个子系统,或者一个中型的系统,也能够大到一个公司的基础平台架构,微服务架构,技术体系架构,甚至是组织架构,业务架构等等。 3.架构设计不是静态的,而是动态演化的。只有可以不断应对环境变化的系统,才是有生命力的系统。因此即便你掌握了抽象、分层和分治这三种基本思惟,仍然须要演化式思惟,在设计的同时,借助反馈和进化的力量推进架构的持续演进。 4.架构师在关注技术,开发应用的同时,须要按期梳理本身的架构设计思惟,积累时间长了,你看待世界事物的方式会发生根本性变化,你会发现咱们生活其中的世界,其实也是在抽象、分层、分治和演化的基础上构建起来的。另外架构设计思惟的造成,会对你的系统架构设计能力产生重大影响。能够说对抽象、分层、分治和演化掌握的深度和灵活应用的水平,直接决定架构师所能解决问题域的复杂性和规模大小,是区分普通应用型架构师和平台型/系统型架构师的一个分水岭。 |