返回介绍

第 41 章 软件架构和编码

发布于 2024-08-18 00:06:35 字数 5168 浏览 0 评论 0 收藏 0

尽管有很多软件团队都发现可视化他们的软件系统的架构很棘手,还是让我们假设情况并非如此,你在为一些想法绘制草图,这些想法跟你负责构建的新系统的软件架构有关。对于恰如其分的软件架构,一个重要方面是理解软件系统的重要元素如何结合在一起。

职责驱动设计和组件分解

对我来说,这意味着深入组件、服务或模块的层次,它们各自都有一组特定的职责。值得强调的是,这不是理解底层实现细节,而是进行初步的分解。基于组件开发的维基百科页面1有一个很好的总结,“组件”可能是像风险计算器、审计记录器、报表生成器、数据导入器等一样的东西。考虑一个组件最简单的方式就是,它是接口背后的一组相关行为,可以用一个或多个协作类实现(当然,假设是面向对象的语言)。好的组件和好的类有一些共性,应该高内聚、低耦合,有良好定义的公共接口、良好的封、装等。

1http://en.wikipedia.org/wiki/Component-based_software_engineering

根据组件来考虑一个软件系统有很多好处,但本质上它让我们可以把软件看作少数高层次的抽象,而不是组成大多数企业系统中成百上千个类,来考虑和谈论。下面的照片展示了在我们举办的培训班上产生的一张典型的组件图。各组都要设计一个简单的金融风险系统,该系统需要拉取一些数据,执行一些计算,并生成一个Excel报表作为输出。

我们往往以组件为单位来思考

这张草图包含了你期望在一个导入数据、执行风险计算和生成报表的系统中看到的主要组件。这些组件为我们提供了一个区分我们系统内部行为的框架,这样在其中跟踪主要用例/用户故事就应该相对容易。这是软件开发过程中一个非常有用的起点,有助于建立团队能够为之努力的共同愿景。

但这同时也非常危险。没有技术选择(或选项),这张图看起来就像那种闭门造车的架构师的作品,对很多拥有技术背景的人来说,它显得非常“概念化”(或者“肤浅”,取决于你的观点)。

我们谈论组件但编写类

人们一般都理解把软件当作少量高层次结构单元来考虑的益处。毕竟,这是在一个软件系统中划分职责的好方法,当人们讨论架构时,你会经常听到他们谈论组件。这就是基于组件的开发2,尽管很多人以组件来谈论他们的软件系统,然而代码通常并未反映出这种结构。这就是软件架构和依据原则编码之间会脱节的原因之一:墙上的架构图说的是一回事,代码说的却是另一回事。

2http://en.wikipedia.org/wiki/Component-based_software_engineering

当你打开一个代码库,由于代码的组织,它往往会反映出另外的结构。软件系统的架构视图和代码之间的映射往往有巨大差异。这就是为什么有时候你会看到人们忽视架构图(或文档),说“代码是唯一的真相”。乔治·菲尔班克斯(George Fairbanks)在《恰如其分的软件架构:风险驱动的设计方法》(Just Enough Software Architecture)3一书中称之为“模范代码的差距”。代码库的组织真的能帮助或阻碍对架构的理解。

3http://rhinoresearch.com/book

用层封装代码

很多软件团队用分层来结构化他们的代码。换句话说,如果你打开一个代码库,就会看到域类包、UI素材包、“业务服务”包、数据访问包、集成包等。这里我用了“包”这个Java术语,但同样适用于C#的命名空间,等等。

原因很简单。我们知道,架构分层一般都是“好事”,很多教程都把这种封装风格作为结构化代码的方法来教授。举个例子,如果你用谷歌搜索Spring或ASP.NET MVC的相关教程,就会在示例代码中看到这一点。我的职业生涯大都花在用Java构建软件系统上,在参与过的大多数项目中,我也用同样的封装方法。

这种封装代码的方法尽管没有什么错,代码结构却从未反映出我们从架构角度看这个系统时考虑的抽象。如果使用一种面向对象的编程语言,你在讨论架构时会谈论“对象”吗?以我的经验来看,答案是否定的。我听到的往往是组件和服务之类的概念,结果架构图中的“组件”实际上是由多个层上的类组合实现的。比如,你可能会发现一个组件有一部分在“服务”包里,其他部分则在“数据访问”包里。

用层封装

为了做到这一点,较底层的代码(比如“数据访问”包)往往是公开可见的,这意味着它也能被架构中的其他层直接调用。

用特性封装

然而用层封装并不是唯一的答案,马克·尼达姆(Mark Needham)有一篇非常好的博文“Coding: Packaging by vertical slice”4,讲到了一种基于功能的垂直切片来组织代码的方法。用谷歌搜索“以特性封装和以层封装”1,会得到很多有关这个话题的讨论。

4http://www.markhneedham.com/blog/2012/02/20/coding-packaging-by-vertical-slice/

用组件封装

用层来组织代码库使得软件的整体结构更易观察,但这也有取舍。举个例子,为了改变特性或用户故事,你需要深入多个层(比如包、命名空间等)探究。同时,考虑到企业系统内有相当标准的分层方法,很多代码库最后看起来都惊人地相似。

鲍勃·马丁大叔在Screaming Architecture5中说,如果你正在看一个代码库,它应该喊出跟业务领域相关的东西。以特性而不是分层来组织代码能够做到这一点,但同样有取舍。我喜欢一点细微的变化,就是明确地以组件来组织代码。举个例子,如果你去GitHub看看je.techtribes.component.tweet这个包2,就会发现它看起来像这样。

5http://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html

用组件封装

这很像以特性来封装,但它更类似于马克·尼达姆在博文6中谈到的“微服务”。je.techtribes.component7的每个子包都安置了一个单独的组件,具有自己内部的层和配置。只要可能,其内部的作用域都在包内。每个组件都可以拿出来,放进它自己的项目或源代码仓库,分别控制版本。如果你在构建有非常明确的松耦合架构的东西,比如由松耦合组件组成的分布式消息系统,可能会对这种方法感到很熟悉。

6http://www.markhneedham.com/blog/2012/02/20/coding-packaging-by-vertical-slice/

7https://github.com/techtribesje/techtribesje/tree/master/techtribes-core/src/je/techtribes/component

尽管大多数人以组件为单位考虑他们的系统,然而他们构建的东西本质上还是更整体化,对此我相当有信心。过去我当然也用类似方法封装过整体化代码库的一部分,但这往往是相当专门化的。老实说,以包来组织代码并不怎么费脑子,特别是考虑到我们所掌握的重构工具。以组件来组织代码让你可以从架构到代码库明确地反映“组件”的概念。如果你的软件架构图喊出了跟业务领域相关的东西(也应如此),这也会反映在你的代码库里。

对齐软件架构和代码

软件架构和编码常常被视为相互排斥的原则,架构和代码之间相互的映射往往非常少。对软件架构有效和高效地可视化有助于在团队内创造一个良好的共同愿景,让项目进行得更快。从架构到代码有一个简单而明确的映射还有进一步的作用,特别是当你开始观察协同设计和集体代码所有制。此外,这还有助于把软件架构坚决地带回到开发团队的领域,也就是它最终所属的地方。但不要忘了,你所用的架构风格需要反映在软件架构图中,不管是层、组件、微观服务或者别的什么东西。

围绕组件设计一个软件系统并不是“唯一正确的方式”,但如果你在构建整体化的软件系统,并认为它们是由一些更小的组件组成,那就确保你的代码库反映出这一点。考虑以组件(而不是层或特性)来组织你的代码,让软件架构和代码之间的映射更明确。如果解释你的软件系统结构很困难,那就改变它。

1https://www.google.com/search?q=package+by+feature+vs+package+by+layer

2https://github.com/techtribesje/techtribesje/tree/master/techtribes-core/src/je/techtribes/component/tweet

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文