[架构之路-89]:《程序员必读之软件架构》-4-软件架构的可视化
Posted 文火冰糖的硅基工坊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[架构之路-89]:《程序员必读之软件架构》-4-软件架构的可视化相关的知识,希望对你有一定的参考价值。
前言:
这部分是关于用一套轻量但有效的草图对软件架构进行可视化。
第 32 章 沟通障碍
如果你正在一个敏捷软件开发团队中工作,那就看看周围。不管是真实还是虚拟的,可能都有一个故事墙或看板,可视化了将要开始的、进行中的和已完成的工作。
为什么?简单来说,可视化软件开发流程是一个引入透明的奇妙方式,因为任何人都能从一个较高层次一眼看清当前的进度。将它与价值流程图1之类的技术结合起来,就可以开始设计一些复杂看板来体现团队的工作方式。我们这个行业已经变得非常善于可视化软件开发流程。
然而,我们似乎已经忘了如何对正在构架的软件进行可视化。我指的不仅是项目完成后的文档,还包括软件开发过程中的沟通。理解软件架构并不等于能够表达它。你办公室墙上的那些架构图,是反映了正在构建的系统,还是跟代码结构没有任何相似之处的概念抽象而已。可视化一个软件系统的架构是一种只有极少人具备的技能。很多人都可以画图,但那些图往往有太多的想象空间,也几乎没有人使用正规的图表符号来描述他们的解决方案。
32.1 经典的架构图形化表达语言UML
回想一下,结构化流程给软件设计流程和表达最终设计都提供了参考点。
广为人知的例子包括Rational统一过程(RUP)和结构化系统分析与设计方法(SSADM)。
软件开发行业在很多方面已经发生改变,但我们似乎忘了这些老方法留给我们的一些好东西。
作为一个行业,我们有统一建模语言(UML),一种用来表达软件系统设计的正规的标准化符号。
我个人还是非常喜欢用UML语言表达软件系统和软件架构。
在架构设计文档中,使用UML语言的可视化图形是比较常见的做法。
32.2 不推荐的草图
然而,就UML对软件设计沟通是否有效的辩驳,通常是无关紧要的,因为很多团队已经不再使用UML,
甚至,根本不知道它是什么。
这样的团队通常会画些不正规的框线草图,但是这些图往往没有太大意义,除非再劳神费力加上详尽的叙述。下回再有人围绕那些不正规的草图给你展示软件设计时,你就问问你自己,他们展示的东西到底是在草图上的,还是在他们的脑子里的。
框线草图可以工作得很好,但也会为软件架构的沟通带来很多隐患抛弃UML没什么问题,但在敏捷比赛中,很多软件开发团队都失去了视觉化的沟通能力。上图是软件架构草图的例子,说明了一些软件架构沟通的典型方法,都存在如下问题:
颜色标注通常意义不明或不统一;
图表元素(比如,不同样式的框和线)的作用不明;
图表元素之间的重要关系有时是缺失或含混的;
频繁使用如“业务逻辑”之类的术语;
技术选择(或可选项)通常被忽略了;
抽象层次混乱;
图表常常包含过多的细节;
图表常常缺少语境或逻辑起点。
框线草图可以工作得很好,但也会为软件架构的沟通带来很多隐患。我
的方法是用一套简单图表,各自只展示整个故事的一部分,不使用
UML时要密切关注图表元素。
32.3 敏捷需要良好的沟通
可视化沟通为什么这很重要?
身处敏捷交付和精益创业的今天,很多软件团队都失去了对正在构建的东西的沟通能力。这些团队常常缺少技术领导力、方向和一致性,也就不足为奇了。要确保每个人都在为相同的目标付出,就要有效地表达你正在构建的东西是什么样的。想要敏捷,就要高效地表达。
用没有歧义且简单的图形来表达软件系统架构就显得尤为有意义,UML虽然消除了歧义,还是由于沉重和复杂,导致很多研发人员放弃了UML, 甚至根本没有接触过UML, 这是比较遗憾的。
第 33 章 对草图的意义与需要
当我告诉人们,我开始教他人软件架构和如何绘图时,得到的反应通常是怀疑。
平心而论,很多人一听说“大局、架构”,往往会让人想起冗余的、一堆很少有人真正理解的UML图。
毕竟,软件开发行业在过去十年已经有了长足发展,特别是敏捷宣言的影响以及由此催生的大量技术,都没有使用UML图,本文在探讨,软件设计过程中,在没有UML图的情况下,草图多敏捷开发的意义和价值以及其在软件设计中的必要性。
33.1 测试驱动开发与图表
测试驱动开发(TDD)是一个例子,它是那些你要么爱,要么恨的技术之一。
本文不讨论TDD是不是软件设计的“最佳方式”,我们看到很多人确实在使用TDD作为设计软件的方式,虽然它不见得适合每个人,他们推崇先写代码、再测试、再画设计图的方法。我个人更倾向,更喜欢在试图找到解决方案之前,先将问题可视化:
在向他人描述业务流程问题时,我会勾画一个总结出来。在我我谈商业问题,我会画一个高层次领域模型。
对我而言,可视化是我结构化、系统化理清问题领域问题的重要方法。
在设计方案时,我也喜欢把方案画出来,而不是冗长的文字,图形化是能够让一切都公开化、帮助其他人迅速理解、促成双方达成一致理解的一种简便的好方法。其中,简易的图表和草图,而不是专业的UML图,非常适合机会所有人,特别是非程序员。
33.2 为什么人们应该学习如何画“草图”
在敏捷开发中,画草图为什么一项值得人们学习的好技能?
敏捷(快速 行动、快速软件编程)需要良好的沟通。画草图是在相对短的时间里传达大量信息的一
个很好的方式,但这也是一项我们在软件行业中不再经常谈论的技能,容易被程序员忽视的技能,这有几个原因:
(1)UML过于专业和严苛
提到画图,很多团队立刻想到了UML,而不是草图,但由于UML需要花费大量的时间,且主要用于专业人士之间交流信息,或者或者从一开始就没搞明白过UML,或UML显然“不酷,有点单调,因此,他们已经放弃了把它作为一种交流方法。
(2)TDD大行其道
很多团队不再用可视化的方式来设计类,因为他们更倾向于TDD。
因此,从实际可用性、可行性、高效性、普适性的角度,个人更倾向于使用草图,而不是以UML图进行不同干系人之间的沟通。
33.3 对画草图的澄清:草图不是艺术
画草图的重点不是“艺术”,没有学过画画艺术的人一样可以画出有价值的草图。
草图的重要性不是艺术。相反,草图的重要意义上在于:快速深入本质,以其他人能理解的方式总结要点,才是重要的。简单、有效和高效是草图这种沟通方式的价值所在。我没有学过画画,但我会在各种场合使用草图。
33.4 画的草图不是综合模型
需要说明一下,我不是在讨论如何用UML图进行细节建模或利用UML图建立综合模型或模型驱动开发。
这是关于通过一个或多个简单的草图,有效且高效地交流你正在构建的软件的架构。这让你可以:
帮助大家理解正在构建的“大局”即架构;
在开发团队中建立关于构建的共同愿景;
为开发团队提供一个关注的焦点(比如,把草图贴在墙上),让开发团队里每个人都始终关注软件是什么以及如何构建;
为那些新功能应该如何实现的技术对话提供一个关注点;
提供一个软件开发者可以用来浏览源代码的地图;
帮助人们了解他们所构建的代码要如何融入“大局”;
帮助你向开发团队以外的人(比如,运营和支持人员、非技术的利益相关者,等等)解释正在构建的是什么;
让新加入团队的软件开发者快速上手;
为技术提供一个起点,比如风险风暴。
对于软件架构草图,我的目标是确保大家理解高层次结构,而不是沉迷于类的设计细节。创建一个团队中每个人都能理解和做出承诺的愿景。因此,上下文的语境、容器和组件图通常就够了。
33.5 画草图可以是协作活动
最后一点,草图可以用于协作活动,特别适合使用白板或活动挂图而非建模工具。绘制草图是软件开发者必备的技能,因为它为不同团队或个人协作软件开发设计铺平了道路,让代码集体所有制变得更简单,每个软件开发团队都能从几张高层次草图中获益。
第 34 章 无效的草图
草图是捕捉和呈现软件架构的好方法,虽然它们通常缺少UML图的正规和严谨,这未必是一件坏事,图表确实需要能被理解。但在显示中,有很多无效的草图,他们无法真正体现软件的设计方案和愿景的效果。
34.1列表清单式草图
无论这张图是软件架构图还是一套软件架构图中的一张,都没有太多软件解决方案的内容,基本上只是一个技术采购清单。
它有一个UNIX框和一个Windows框,还有一些附加的产品选择,包括JBoss(一个Java EE应用程序服务器)和微软SQL服务器。
问题在于:
我们不知道那些产品做了些什么,
UNIX框和Windows框之间似乎也缺少某种联系。
既然功能职责和模块之间的交互都没有在草图中显示出来,那么这个图的内容可能更适合用列表的word文档或excel文档表示,根本不需要通过草图的形式展示。
草图一个重要的作用是,草图不仅仅能够展示元素或组件的内容,还能够表达组件之间的层次或结构化的关系,更重要的是,草图要能够展示模块与模块之间的相互关系。
34.2 只有框没有线的草图
当人们谈论软件架构,他们往往指的是“框线图”,图表示组件,线表示关系!
下面这个图只有框,却没有线:
这是一个采用微软技术栈的三层解决方案(在我看来)。
顶部是一个ASP.NET的Web层,我认为它被用于某种用户交互,尽管图中没有明示。
底部标有“SQL服务器”,有很多独立的“数据库罐”。老实说,从图中不知道这些是不是独立的数据库服务器、结构或表。
中间是一些框的集合,我觉得像是组件、服务、模块等。从另一个角度来看,能看到整个解决方案的中间层如何分解成更小块,非常好,这肯定是我们在设计软件解决方案中希望看到的。但是,还是没有职责和交互。
软件架构是关于结构的,是事物(框)以及它们如何相互作用(线)。
34.3 “功能列表视图”式草图
这个图跟上一个很相似,也很常见,由于某些原因,在大型组织中尤其常见。
这张图虽然把解决方案进行功能分解,假设他们是组件、服务、模块等,但它也面临着和前一张图相同的问题:没有职责和交互,除此之外,也没有对不同颜色做进一步进一步的解读。
34.4 基本正确的草图
这是一个很有“软件架构入门”风格的图,其中大部分内容都是通用的。
这是一个很有“软件架构入门”风格的图,其中大部分内容都是通用的。
该架构图展示了如下信息:
展示了运输、归档、审计、报表生成、错误处理等业务逻辑的功能框
展示了业务逻辑的关系与交互
展示了业务逻辑外部实体与外部是实体的交互
软件架构草图应该如此。
使用严谨的UML图可以展示架构的充分信息,但现在似乎没有太多人有热情去学习这东西,特别是敏捷团队,他们更喜欢软件架构草图,简单而有效的软件架构草图是每个人都可以完成的,所需的不过是一些简单的建议和一组通用的抽象,如下图所示:
接下来看,我们将更详细地展现如何绘制更加有效的架构草图。
第 35 章 语境、容器、组件和类
在任何软件系统的开发周期内,代码都是最受关注的部分。这很正常,因为最终交付的只有代码。
但如果要向别人解释系统如何工作,使用代码就显得极其不方便。另一封面,代码并非全部。
在缺少文档的情况下,人们通常会在白板或纸上画框线,来解释哪些是主要的结构单元以及它们如何相互连接(互相关系)。
用图片描述软件系统时,有时候我们会倾向于制作一个超级图,尽可能多地把各个抽象层次的细节都塞进去。这可能是我们有点过于关注系统在代码层面的运行细节,这样的图往往乱成一团,既复杂又令人费解。
选择一个Microsoft Visio、Rational Software Architect或SparxEnterprise Architect之类的工具,虽然使得画图更加的简便,工具本身并没有使得展现的内容变得的简单,往往更复杂。
更好的方法是:制作一些不同视角的不同抽象层次的图,比起一张试图讲清所有事情的复杂图,多张简单图可以更有效地描述软件。
35.1 软件系统的通用抽象
如果软件架构是关于软件系统的结构,那就有必要理解哪些是主要结构单元,以及它们如何在不同的抽象层次上相互融合,组成一个有机的软件系统。如下是软件架构结构的简单模型:
假设一个软件使用了面向对象的编程语言(目前,市面上大多数编程语言都是面向对象的编程),我喜欢用如下方式来思考它的结构:软件系统由多个容器构成,容器又由多个组件构成,组件由一个或多个类实现。大多数软件系统都可以用这种简单的逻辑结构单元的层级关系来建模。
类:对我们大多数人来说,在一个面向对象的世界里,类是软件系统的最小结构画单元,当然, 类还可以包含其他子类或成员类。
组件:组件可以想象成一个或多个类组成的功能逻辑群组。比如,其他组件可以使用审计组件或认证服务,来确定对特定资源的请求是否放行。组件通常由多个类在更高层次的约束下组合而成。
容器:容器是指一个在其内部可以执行组件或驻留数据的东西。它可以是从网络或应用服务器直到富客户端应用或数据库的任何东西。作为整个系统的一部分,容器通常是可执行文件,但未必是各自独立的流程。比如,我把每个Java EE网络应用或.NET网站都看作一个独立的容器,不管它们是否运行在同一个物理服务器流程中。从容器的角度理解一个软件系统的关键在于,任何容器间的通信可能都需要一个远程接口,比如SOAP网络服务、RESTful接口、Java RMI、Microsoft WCF、报文,等等。
系统:系统是最高的抽象层次,代表了能够提供价值的东西。一个系统由多个独立的容器构成,例如金融风险管理系统、网络网银行系统、网站等。
通过精确定义各种结构单元并特化它们之间的联系,我们不难看出如何更进一步。但是我们不确定这会特别有用,因为它会限制和复杂化我们的目标:理解软件系统的结构,并建立能描述它的、简单的抽象集合。
35.2 静态视图
1.语境:设定业务场景Senanario的高层次图,包括关键的系统依赖和参与者。
2.容器:容器图显示了高层次的技术选择,容器如何分担职责、如何通 信。
3.组件:组件图可以让你看到每个容器的关键逻辑(不是物理)组件及之间的关系。
4.类:这是一个可选的细节层次,如果想解释某个模式或组件将(或已经)被怎样实现的,少量高层次UML类图将是一个重要的选择,需要画类图的主要原因包括:
软件的复杂性
团队的规模
团队的经验
这里的UML类图通常会是草图,而非综合性、标准化画的UML模型。
35.3 草图的通用标识
画简单草图对大多数团队都是适用的,为了在不同团队之间提供一致性的理解,需要有一些在所有团队之间都适用的通用含义的标识(并非制订标准),以便于不同团队之间能够以有效且高效的方式进行沟通 。
UML提供了一套通用的抽象和用于描述它们的通用标记,很少有团队可以有效而完全遵循UML语法地使用它们,我们期望以更加简单的方式抽象和展现我们的软件系统,而不是绞尽脑汁去理解各种标记元素,以及如何用他们展现的我们期望展现的东西。
必须重申,非正规的框线草图灵活性是以牺牲一致性为代价的,我们创造自己的标记,而不是使用UML标准的标识,为了能够在团队之间更好的交流与沟通,这些标识(如颜色、线条样式、形状)最好能够在团队的不同成员之间达成共识。
35.4 图应该简单且脚踏实地
似乎有一个普遍的误解,“架构图”只能展示高层次的概念视图,所以难怪敏捷开发的软件开发者常常会认为它们毫无意义。
实际上,软件架构图应该脚踏实地,软件架构的流程应该能够指导编码和不同团队之间的合作,而不是象牙塔。一组简单的图让你可以有效地从不同抽象层次展示软件,同时一组简单的图可以让不同人能够容易理解。
第 36 章 Senanario场景图
给软件系统画图和做文档时,场景图是很有用的起点,让你可以客户业务的角度观察大局、展现软件系统的需求与构想。
场景图展示你规划的目标软件系统如何融入整个IT环境。
36.1 意图与业务目标
语境图能帮你回答下面这些问题:
1.我们构建的(或已经构建的)软件系统是什么?
2.谁会用它?
3.如何融入已有的IT环境?
简单讲,就是业务目标。
36.2 场景图的结构
场景图是在图片的中间画一个简单的框图展示你的软件系统,它周围是它的用户和其他与之相互作用的系统。
在场景图中,不关注实现细节细节,因为场景图是用来展示系统全局,重点应该放在整体的人和软件系统之上,而不是内部的实现技术和协议。
(1)用户、演员、角色、人物等
这些是系统的用户,这里包括两大类:
业务用户:与系统软件直接交互的人
管理用户:操作维护管理系统软件的人
(2)IT环境
IT环境是目标软件的执行与交互环境。
根据不同的环境和选择方案,在语境图上展示的IT系统环境包括:
交易数据系统(金融交易数据源);
参考数据系统(参考数据源);
中心监测系统(警报发往的地方);
活动目录或LDAP(认证和授权用户);
微软SharePoint或其他内容/文档管理系统(分发报告);
微软Exchange(向用户发送电子邮件)。
(3)交互
交互反应了用户 <-> 软件系统、软件系统 <->软件系统之间的交互。
(4)动机
动机,用户的业务目标,反应了软件系统要达成的目标。
(5)受众
直接的软件开发团队内部人员,外部的技术和非技术人员。
36.3 场景图实例
让我们看一个例子。
“技术部落”网站1为在泽西岛和格恩西岛(海峡群岛中最大的两个岛屿)寻找与技术、IT和数字领域相关的人、部落(业务、社区、兴趣组等)和内容提供了一个途径。
在最基本的层面上,它是一个本地的微博、新闻、博文、活动、讲座、工作以及更多东西的内容聚合器。这是一个提供可视化总结的语境图。
第 37 章 容器图
37.1 容器图的用途
容器图可以帮助我们回答下面的问题:
1.软件系统的整体形态是什么样的?=》由一个个容器组成。
2.高层次技术决策有哪些? =》 划分哪些容器以及背后的原因。
3.功能职责在整个系统中如何分布?=》不同容器的职责与功能
4.容器之间如何相互交流? =》容器之间的交互
5.为了实现特性,作为一个开发者,我需要在哪里写代码? =》在哪个容器内实现代码。
37.2 什么是容器
“容器”,指的是组成软件系统的逻辑上的可执行文件或程序。不同容器之间的通信是进程间通信。
Web服务器1(比如Apache HTTP服务器、Apache Tomcat、微软IIS、WEBrick等);
应用服务器(如IBM WebSphere、BEA/Oracle WebLogic、JBoss AS等);
企业服务总线和业务流程编排引擎(如Oracle Fusion中间件等);
SQL数据库(如Oracle、Sybase、微软SQL服务器、mysql、PostgreSQL等);
NoSQL数据库(如MongoDB、CouchDB、RavenDB、Redis、Neo4j等);
其他存储系统(如亚马逊S3等);
文件系统(特别是如果你在数据库以外读/写数据);
Windows服务;
独立/控制台应用程序(即“public static void main”风格的应用程序);
Web浏览器和插件;
cron和其他计划的工作容器。
如果多个Java EE Web应用程序或.NET网站是同一个软件系统的部件,通常会在单独的类加载器或应用程序域里被执行。可以用单独的容器来展示它们,因为它们是独立的,要靠进程间通信(比如远程方法调用、SOAP、REST,等)来协同工作。
37.3 容器间的交互
容器间的通信通常是进程间通信。
需要在草图上展现如下的一些交互信息:
交互的目的(如“读/写数据”、“发送报告“等);
通信方法(如Web服务、REST、Java远程方法调用、Windows通信基础、Java消息服务);
通信方式(如同步、异步、批量、两阶段提交等);
协议和端口号(如HTTP、HTTPS、SOAP/HTTP、SMTP、FTP、RMI/IIOP等)。
37.4 系统边界
如果草图中包含不属于你构建范畴的用户和IT系统,最好在适当的容器周围画一个框来明确地标定系统边界,用于表明哪些是用户自己实现,哪些是第三方实现,系统边界对应了场景图上的一个框。
37.5 动机/目的
场景图展示的软件系统是一个黑盒子,容器图则是打开盒子,展示盒子里面的东西。
这样做的好处和目的如下:
让高层次的技术选择更明确;
展示了哪些容器之间有关联,以及它们如何沟通;
提供了一个放置组件的框架(也就是说,所有的组件都有一个家);
展示了高层次的场景图和通常很乱的组件图之间经常缺失的连接,组件图画的是整个软件系统中所有的逻辑组件。
37.6 受众
直接从事软件开发的团队内部和外部技术人员;包括从软件开发者到运营和支持人员的每一个人。
37.7 示例
第 38 章 组件图
在展示了高层次技术决策的容器图之后,我们将开始放大,进一步分解每一个容器。
如何分解你的系统取决于我们自己,组件图把一个软件容器划分为若干不同的组件、服务、子系统、层、工作流等。
38.1 示例
38.2 目的与作用
每当人们被要求绘制“架构图”时,最后通常会绘制一张展示组成软件系统的逻辑组件的图。
组件图可以帮助你回答下面的问题。
1.系统由哪些组件/服务组成?
2.在高层次上,系统如何工作是否清晰?
3.所有组件/服务都有一个家吗(即驻留在一个容器中)?
38.3 组件图的结构
每个容器都有自己的组件图。
对于小型的软件系统而言,通常也可以用一张图展示所有容器中的全部组件。
对于大中型的软件系统,如果这张图开始变杂乱,就可以拆成多张组件图。
38.4 什么是组件
组件是系统的粗粒度结构单元,你应该能理解如何通过一个或多个组件实现一个用例/用户故事/特性。
对于图中绘制的每一个组件,你都可以指定:
名称:组件的名称(如“风险计算器”、“审计组件”等);
技术:对组件的技术选择(如:普通的[Java|C#|Ruby|其他]对象、企业JavaBean、Windows通信基础服务等);
职责:对组件职责的非常高层次的声明(如:要么是重要的操作名称,要么是描述职责的简短句子)。
38.5 交互
交互展现的是组件之间的交互,包括:
交互的目的(如:“使用”、“存留贸易数据”等);
通信的方式(如:同步、异步、批量、两阶段提交等)。
38.6 动机和目的
把软件系统分解成多个组件,这在软件设计中比类和代码的抽象层次略高。组件对于理解系统内部结构是一个很好的方式。
展示了在高层次上将软件系统分解为职责不同的组件;
展示了组件之间的关系和依赖;
为软件开发的高层次的预估和如何分解软件的交付提供了一个框架。
在这个组件这个抽象层次上设计一个软件系统,完全可以在数小时或数天内完成,而无需几周或几个月。
38.7 受众
软件开发团队中的技术人员。
第 39 章 是否包含技术选择
绘制软件架构图的主要原因之一是在软件设计过程中交流思想,就像你会在建筑项目前期看到草拟的蓝图。大部分架构图都会忽略任何有关技术的信息,而是专注于说明功能分解和主要概念元素。
可选择性的在草图上增加如下技术选择的信息:
“这个组件如何与运行在单独进程中的另一个组件沟通?”
“这个组件如何初始化,职责又是什么?”
“为什么这个进程需要和另一个进程沟通?”
“为什么这个组件要用X技术而不是Y技术实现?”
第 40 章 你会那样编码吗?
图应该表达反映现实的抽象,这些草图,应该最终被映射成代码。
如果你的草图无法被映射成代码或者代码压根里没有按照草图去实现,那么这样的草图是没有存的意义的。
第 41 章 软件架构和编码
以上是关于[架构之路-89]:《程序员必读之软件架构》-4-软件架构的可视化的主要内容,如果未能解决你的问题,请参考以下文章
[架构之路-86]:《程序员必读之软件架构》-1-什么是软件架构
[架构之路-87]:《程序员必读之软件架构》-2-软件架构师所需要技能
[架构之路-88]:《程序员必读之软件架构》-3-软件需求与架构设计的关系
[架构之路-88]:《程序员必读之软件架构》-3-软件需求与架构设计的关系