你做架构设计了吗?你认为要不要做架构设计?你的公司有没有做架构设计?互联网公司的架构设计又要怎么做?我不知道你是怎么想的,在我得到的答复中,大部分人认为要做架构设计,但自己却很少做,自己经历的公司也少有做架构设计。这里是矛盾的,难道大部分人和公司都犯错了吗?应该不是这样。专职的架构师越来越少,架构部门也大都解散,为什么会是这样,我们该怎么办?
一、初识架构设计
软件工程一般可分为需求、设计、编码、测试、部署、维护。既然架构设计是一个过程,那么就有输入和输出。架构设计输入的是PRD产品说明书,输出的是架构设计文档,中间是处理过程和工具,具体如下:
- 输入:功能需求和非功能需求,从PRD中提取;
- 过程和工具:
- 设计的目标和思路
- 功能设计:用例视图、用例活动图
- 应用:边界、逻辑架构、接口、领域图
- 数据存储
- 物理架构、安装部署
- 非功能设计
- 输出:设计说明书,表述工具有Word、Visio、UML等
需求是我要什么即What,而架构设计是我要怎么做即How。架构设计为施工阶段提供了指导,有利于接下来的编码、测试、部署和维护,包括项目排期、人员分工、配合、单元测试、物理部署、系统修改和升级。设计是施工的计划,没有计划就没有管理,计划可节约施工的成本和时间。如果没有架构设计就开始写代码,会导致很多的问题,干着干着就干不下去了,或干到一半必须得改等等现象。
二、应用架构设计案例
以下是一个真实的应用架构设计案例,《国内航班查询引擎项目》的架构设计过程如下:
2.1 功能清单
产品经理提供的PRD文档做得怎么样,第一眼就看它有没有功能清单。下图的功能清单表格主要有两个核心功能,一个是查询航班数据模块,另一个是清理缓存模块。
2.2 用例图与用例活动图
上图是用例图和用例活动图,用例图有查询航班数据和清理缓存,这与功能清单有对应关系。每一个用例都可以展开为用例活动图,产品经理的活动图关注的是业务的逻辑,我们的用例活动图关注是程序的业务逻辑,有更多的技术视角。如图所示,前台网站或Mobile发起查询请求后,经过参数验证,然后分别获取政策、获取贴点、获取价格、获取航班数据,再合并计算数据,最后构建返回数据。
2.3 领域图
上图是领域图,它从用例活动图演化而来,图中的行为与活动图有对应关系。如图所示,平台或Mobile触发查询引擎后,然后多线程获取政策数据、贴点数据、价格数据和航班数据,然后进行合并计算。领域图是应用程序的业务逻辑模型,它的每一个框有可能是一个类,也可能是一个类库,或是一个应用、一个子系统,它是可大可小、可伸缩、可扩展的。
2.4 接口设计
什么是接口?接口是契约、连接和交互,它是应用与外部世界的联系者。有一位资深架构师说过,“我只需要设计好一套接口,让整个业务流转起来,我的工作就做完了,至于怎么实现我可以不知道”,这话有一定道理。以上契约遵循统一的Request/Response实现模式设计规范。
2.5 分层设计
2.6 代码实现
左上图是第一个版本的代码实现,例如SearchVerify实现验证查询参数、CaculateBusiness实现合并计算、PolicyBusiness实现政策相关逻辑、PriceBusiness实现价格相关逻辑、DiscountBusiness实现贴点相关逻辑、CacheBusiness实现缓存逻辑、UserBusiness实现用户逻辑。右上图是第二个版本,相对第一个版本的实现要复杂些:ValidateBusiness对应验证查询参数、CaculateBusiness对应合并计算、PolicyBusiness对应政策、PriceBusiness对应价格、TiedianBusiness对应贴点、FilterPolicy对应政策过滤。可能你已经发现,不管代码怎么升级改造,只要领域模型没有发生变化,业务模块也就不会发生大的变化。
架构设计会改变编码方式,在架构设计阶段如果做好了领域模型,你就可以在编码施工阶段,先写业务逻辑层再写数据访问层。先定义好业务服务和数据接口定义,再根据数据定义来实现数据访问。这与表驱动的传统方式有所不同。先写数据层再写业务逻辑层,是先写好数据表的增删改查,然后业务逻辑层只是简单地调用一下数据层,便提供给界面层使用。它只是一个简单代理,完全没有发挥业务逻辑层应有的价值。
2.7 其它设计项
除了以上设计项,还有数据库设计、物理架构设计、非功能性设计。数据库设计有E-R图和表设计,物理架构设计有应用集群、应用部署图、域名等,非功能性设计有性能、可用性、伸缩性、扩展性、安全性等。最后是总结和表述,输出一份架构设计文档,详见下图和附档链接。
2.8 演化
以上是架构设计的关键过程,上一环是功能需求,下一环是代码实施,从功能需求到用例图,到用例活动图,到领域图、架构分层和核心代码,以领域模型为中心去构建业务逻辑代码,然后再实现数据库的访问。它们之间环环相扣,做不好领域图可能源自没有做好用例活动图,因为用例活动图是领域图的上一环。从功能到图纸到代码,从代码到图纸到功能,这是一个可演化可追溯的过程。架构设计如同施工图纸,能直接指导工程代码的实施,以及编码施工次序的改变。
三、更多知识探讨
什么是探讨,什么是培训?培训是我有知识和经验,然后教给大家,我是正确的,大家照着干就可以了。而探讨是我有一个很好的问题,来问大家,来请教大家,以启发你我的思维。接下来,与你一起探讨以下架构知识:
3.1 设计表述探讨
- 一定要有架构设计文档吗?按教科书是需要的,但真实的情况可能并不是这样,没有设计文档的情况并不少见。
- 架构设计文档要不要保存?项目做完后,它要保存多久呢?你待过的公司有保存吗?我们要沉下心来问问自己,追求真实比书本更为重要。
- 设计文档到底在为谁服务?为自己还是为别人?为半年后的自己,还是为公司或同事?
- 设计可以省掉吗?在没有设计文档的前提下,是否可以编写高质量的代码?如果文档可以省掉,那么架构设计过程呢?
架构设计文档的编写并不简单,可能要花一周或一个月的时间,成本较高。设计表述方式有多种,具体如下:
- 架构设计文档:它相当于造房子用的施工图纸,是相对比较正式的方式;
- 需求分析设计或项目排期会议:PRD出来后,研发成员一起开需求分析设计会,分析讨论的过程也是设计的过程。或者通过项目排期,在估算项目难易程度和排期时,也有设计分析的成分;
- 设计邮件:一份简单的设计邮件,内容大约有:问题描述、原因分析、技术方案、架构建议等;
- 非正式讨论:几个人站在白板前,讨论和画画,会议结束后再把它拍下发给参与人员。
3.2 关于UML
UML是Unified Modeling Language缩写,又称统一建模语言,是始于1997年一个OMG标准。它是一个支持模型化和软件系统开发的图形化语言,为软件开发的所有阶段提供模型化和可视化支持。它不仅统一了Booch、Rumbaugh和Jacobson的表示方法,而且对其作了进一步的发展,并最终统一为标准建模语言。UML图型主要有用例图、时序图、活动图、类图、状态图、组件图和部署图。
UML是设计表述和建模工具,虽然它的愿景是全生命周期,甚至用UML直接生成可执行软件。实际上这是很难的,不到真正写代码,不可能明确所有细节。当然,UML在设计过程中还是有一定作用的,例如时序图、类图、状态图,这些如果不用UML图来表示而用文字来描述的话,大家很难达成一致理解。
UML是理想建模工具吗?那什么是理想的建模工具呢?船泊业3D建模,在未生产前就在电脑里把整个船构建起来。塑胶建模工具ProE、商品房售楼部的沙盘,在未见实物前就可通过模型知道很多信息。理想建模工具应该是3D的、动态的、简单而形象的。UML只是一种表述你头脑中思想的工具,相对而言你头脑中的思想才重要,所选用的表述工具要根据双方的实际情况,简单清晰、利于沟通才是目的,并不一定就是UML。
3.3 关于设计模式
设计模式是一套被反复使用的、多数人知晓的、经过分类的、代码设计经验的总结。使用设计模式是为了重用代码,让代码更容易被他人理解。 设计模式于己于他于系统都是多赢的,设计模式使代码编制进一步工程化。每种模式都描述了一个不断重复发生的问题,以及该问题的核心解决方案,项目中合理地运用设计模式可以很好地解决很多问题。GoF的设计模式共有23种,理解意图是运用设计模式的关键,一图胜万言,下面是图解23种设计模式。
设计模式是代码的形状,是代码结构设计的招式,是练功的套路,如同书是人类进步的阶梯。但练功是练功,打架是打架,真正的功夫要在大规模实战中所得。从设计模式到代码,再从代码重构到设计模式。设计模式不仅是设计出来的,也是重构「长」出来的。虽然重构并非一定会得到与设计模式完全相同的抽象结果,但重构是设计模式的迭代补充。设计模式如果使用得过早过多或不恰当,会给代码增加不必要的结构复杂度。重构和模式设计的良好结合,使代码更趋于品质和实用。GoF设计模式是始于1995年的经典,主要解决当时软件的重用性、扩展性和可维护性问题。而在20多年后互联网时代的今天,版本迭代快、可随时在线更新,使用环境、语言和框架都已发生变化,许多模式是否还合时宜?设计模式在面试的时候用得多,还是在实际开发中用得多?可能每个人答案都不一样,但每个工具都有其适用场景、收益和成本,思考这些有利于我们更好地使用它。
3.4 关于设计原则SOLID
设计原则是设计模式的关键所在,原则和方法是决策的思想指南,设计原则SOLID具体如下:
- 单一职责原则SRP:一个类只做一种类型的责任,一次只做一件事;
- 开闭原则OCP:对扩展开放,对修改关闭。开闭原则具有理想主义的色彩,它是面向对象设计的终极目标;
- 里氏代换原则LSP:任何基类可以出现的地方,子类一定可以出现,它是一个建议或约定;
- 接口隔离原则ISP:不能强迫用户去依赖那些他们不使用的接口;
- 依赖倒置原则DIP:高层模块不应该依赖低层模块,但它们都应该依赖抽象,客户第一。
3.5 关于DDD
DDD是Domain Driven Design的缩写,翻译为领域驱动设计,它的核心是领域模型。什么是模型?装修人员从来没看过你的房子,但看过以下模型后,就能知道你要装修成什么样。它的价值在于导航、精炼、统一表述。它能够帮助施工方和客户,全方面和多角度地去看待问题,而不是盲人摸象。它是利于沟通、实现、维护和扩展。
什么是领域?领是领地的意思,域是边界的意思。领域是一个专业科目,是人为的划分,一个领域一个边界一个框,领域会随着规模、角度和时代的变更而发生变化。例如,公司规模很小的时候,没有财务部,一个人既当会计又当出纳。当公司规模变大一些时,可以一位做会计,一位做出纳,可划分两个领域。当公司规模变得更大的时候,领域又变了,成立财务部,财务部里有N位,每人干的事情都不一样。业务在变,认知在变,领域的划分也要变。领域是主观的,它是对客观世界的阶段性认知。
领域模型处于业务问题与技术解决之间,先将业务对象抽象成领域模型,然后根据领域模型来实现技术对象。从对象到类再到对象,从具体到抽象再到具体,我们对抽象和具体再做进一步引申。请问,是先有鸡还是先有蛋?这个问题不好回答,给你一只具体的鸡和一个具体的蛋,你便能知道它们是父子关系、子父关系或没有关系,但是如果给你一只抽象的鸡和一个抽象的蛋,你是不知道它们是什么关系的。再请问,是先有类还是先有对象?这个问题也不好回答。在设计阶段,是先有对象再有类,在编码阶段,是先有类然后再有对象。整个过程是:架构师在设计阶段根据业务对象抽象出类,然后程序员在编码阶段,先编写类然后再New出一个对象。从对象到类再到对象,从业务问题到领域模型再到技术解决方案,从问题域到领域模型再到代码实施,这是领域驱动的核心所在。领域驱动设计=从问题域驱动领域模型构建+从领域模型驱动代码实施。
以上是DDD的分层架构,包括仓储层Repository Layer、领域层Domain Layer、应用层Application Layer、表现层Presentation Layer、基础设施层Infrastructure Layer。从仓库中取出原材料,然后流水线将人、材料、工具组织起来,最后输出给表现层。上图中,领域层不依赖于仓储层,而是仓储层依赖于领域层。这相当于传统三层中业务逻辑层不依赖于数据层,而是数据层依赖于业务逻辑层。为什么要这样呢?这是因为上层需要什么下层就提供什么,而不是下层有什么就提供什么,客户第一、按需生产都是这个道理。在技术的具体实现上即依赖倒置DIP,把接口放在上层,然后下层实现,最后使用IoC工具绑定即可。
3.6 设计不足与过度设计
什么是设计不足,什么是过度设计?不能解决当前问题的就是设计不足;只能解决当前问题的是恰当设计;能解决当前问题,且又能解决未来一段时间问题的是良好设计;能解决当前问题,但面向未来设计过多,且成本较大,预测错误又不能解决未来问题的是过度设计。我们要追求恰当设计或良好设计,特别是互联网项目,变化大、迭代快,很难预测未来发生的事项。
那什么是好的设计呢?好的设计是实用的、易于理解的,是谨慎克制的、简单的,是能够落地的、考虑施工成本的。好的设计要解决业务的问题,你的设计再牛逼,但不能解决业务的问题,那么这个设计就是不好的设计。好的设计是谨慎克制的,不能为Show技术或个人意愿而过多使用复杂的技术。好的设计是能够落地的,如果你的设计在落地上出现很多问题,那么就是有问题的设计。没有人在设计时失败,只有实施时失败。
3.7 架构设计是艺术
以上架构知识非常重要,但并不是知道了这些,就能做好架构设计了。这如同很多人都会画圆和直线,但并不会画画;很多人会使用钉板和菜刀,但并不能做一桌美味的佳肴。
我们探讨一个具体的问题,“能异步的尽量异步”,互联网公司程序员经常说的这句话,是否正确?首先,程序员喜欢同步还是异步?用户喜欢同步还是异步?程序员为了并发量,会选择异步。用户不要等待,要求系统立即返回,会选择同步。那么在什么情况下使用同步,什么情况下使用异步呢?有几个考虑因子,第一个是复杂度,同步=异步+轮询/通知,同步相对简单,异步则相对复杂。第二个是可靠度,如果是2/5/8秒概率较大,那么最好选用同步。第三个是用户体验,当使用异步后,用户体验也需要改进,可立即返回给用户一个单号和进度条。第四个是业务成熟度,业务成熟度分萌芽期、发展期、成熟期、衰退期这四个阶段。对于新业务,能同步就同步,当业务变得越来越成熟,访问量越来越大的时候,容易出现高并发量导致用户排队,这时异步是挺好的选择。
在实际问题面前,选择同步还是异步?要看情况,需经过分析、思考,你需要知道每一种选择的利弊。分析的过程往往比决策更为重要,当你知道了每一种选择的利弊,这时你喜欢就好,因为你只有喜欢了才能把事情办得更好。你的架构设计=你+架构设计,架构设计是科学,你是主观意识,最后的决策一定包含了你的个性和情感。科学到最后是艺术,架构设计是艺术。
四、互联网公司的架构设计要怎么落地
互联网公司的架构设计是怎么做的呢?专职的架构师越来越少,架构部门也大都解散,为什么会是这样,我们该怎么办?
4.1 要不要做架构设计
哪些项目需要做架构设计呢?越大的项目越需要做架构设计,开发时间越长的项目越需要做架构设计,参与人员越多、内部越复杂、外部依赖越多、影响面越大、维护成本越高的项目越需要做架构设计。那互联网的项目呢?它有以下特征:
- 时间:开发的周期整体很长,可能维护10年、20年,但单个应用的开发周期短,多半以天和周为单位;
- 规模:互联网项目整体很大,但单个应用规模小,会被拆分为多个小应用;
- 业务知识:为自己做系统,行业知识不缺,长期为一个系统服务,有些自己也是客户;
- 复杂度:研发人员多,内部关系复杂,外部依赖多,变化大迭代快,在不断地演化,24小时不间断运行。
4.2 MVP与架构设计
MVP的英文全称是Minimum Viable Product,是最小可行性产品的意思。如上图所示,用户需要一个交通工具,有两种实现方式,第一种做法是分多个阶段设计与制造,第一步是造一个轮子,第二步是造两个轮子,第三步是造一个盖子,第四步是一辆可用的轿车。第二种做法是每一阶段都要满足用户从A地到B地的需求,第一步先造个滑板,第二步是造个自行车,第三步是造辆摩托车,第四步是造辆轿车。第一个版本到第三个版本输出的产品都可以满足用户的基本需求,虽不完善但可以解决用户的问题,并且越来越好,到了第四个版本的产品才是客户预期。
MVP对架构设计提出更高的要求。如果单纯从研发内部的角度,第一种是施工成本较低的方案,但我们需要以客户为中心,需要不断地满足客户的需求,所以在做设计时,不仅要考虑施工的成本,还有客户需求、扩展性、继承性等,如上图第三种设计方案。
4.3 互联网公司是怎么做的
互联网公司的架构设计是怎么做的,当前主流做法有:
- 分工:将技术研发和业务研发相分离,下层是云平台部或基础架构部,提供IaaS、PaaS中间件等云服务,上层是各业务线的产品研发部,专注于业务场景的应用研发;
- 敏捷:业务研发敏捷化,产品与研发、测试实时沟通,以减少行业知识的缺乏;
- 整体:技术委员会,负责技术总体规划和技术成长;
- 未来:研究院,解决未来的技术问题,如阿里达摩院、百度研究院;
- 应用架构:主要负责技术与业务的结合,由应用架构师、技术经理或高级程序员担当。
4.4 应用架构要怎么落地
应用的架构设计要怎么落地,常见如下:
- 总体架构规划:手握地图,才能明确自己所处的位置,以便于配合。总体架构规划可以让每个研发人员了解整体,它如同房子的地基框架图纸,可长期保存和更新维护。具体参考TOGAF开放组体系结构。
- 单个项目架构设计:重点项目一定要做架构设计,参与架构评审,非重点项目可简化设计表述。
- 应用架构评审:以流程的方式来保证应用架构设计的质量,例如重构项目、跨部门项目、业务核心项目需要经过应用架构评审之后,才能申请服务器、数据库、域名等。
- 其它工作:如果有应用架构师专职人员,除以上工作外,还包括统一公司应用分层、制定代码规范、组织技术培训、中间件推广、应用性能调优等。
五、你给技术打个分
以上,首先是一个启发性的问题,然后是初识架构设计,接着是一个真实的应用架构设计案例,并探讨了更多架构设计知识,包括设计表述、UML、设计模式、设计原则SOLID以及DDD,最后是互联网公司要怎么落地。这些知识点都是工具,这些工具到底怎么样呢?如果它是一个新知识,我们不好妄加评价,但这些工具已经出来很多年了,我们也工作了这么多年。它好不好用,实不实用,我们都应该知道些。现在,大家也当回老板,请你给技术打个分,以下二维码是链接,欢迎绩效考评 🙂
六、案例参考
- AppArchDemo案例参考地址:https://github.com/das2017/AppArchDemo
--------------------------------------------------------------------
这些工具到底怎么样呢?欢迎在评论处说说你的真实想法,质疑一下权威。