FinOps有望降低企业50%+的云成本! 了解详情
写点什么

架构重构:通过以任务为中心的视角看软件的进化

A Task-Centric View on Software Evolution

  • 2015-08-12
  • 本文字数:4286 字

    阅读完需:约 14 分钟

本文最初 __ 发表在 IEEE__ 软件杂志上, IEEE__ 软件杂志致力于发表严谨的、经过互相审校的文章,专注于当今世界的战略科技。为了满足运行可靠且灵活企业所面临的挑战,IT 经理和技术管理者依赖 IT Pro 获取最先进的解决方案。

软件密集型的系统经常会因为各种各样的原因而必须进行重新设计,例如某个不可预知的业务变动或是技术上的创新。许多重新设计活动会对这些系统的软件架构产生影响,代码重构就是一种流行的重新设计实践。考虑到代码成功这一实践的巨大成功,这使人们对于架构重构(AR)这种实践的沉默感到有些吃惊。为了纠正这一情形,我将在本文中为读者展示,作为一种软件进化技术,AR 如何重新审视架构决策,并确认相关的设计、实现及文档任务。

介绍架构重构

重构的目的是在改善某部分质量的同时保持其它部分不变,举例来说,代码重构实践对代码的结构进行了重新调整,以增强代码的可维护性,同时又保持它的可观察行为不变。代码重构实践是与机器可读的实体进行打交道,例如包、类以及方法,让这些实体能够在编译器构造阶段利用各种数据结构,例如抽象语法树 1。而 AR 则是与架构文档和架构知识在代码与运行时产品中所表现出的行为打交道。因此,不存在一种单一的架构语法树。AR 的范畴包括:

  • 组件与连接器(经过建模、描绘或在代码中隐式地表现出来),
  • 设计决策的记录(以结构化和非结构化的文本表现),以及
  • 计划阶段的产物,例如项目管理工具中的工作项。

AR 能够找出架构中的坏味道,这种坏味道暗示着架构中的某部分对于目前的需求与约定来说已经不再适用,而这些需求比起从前可能已经产生了某种变化。从这一层意义上说,AR 是一种将经过深思熟虑的架构活动进行整理后的集合,它能够去除某种特定的架构坏味道,能够在不影响系统的范围与功能的情况下,对系统中至少一方面的质量特性加以改进。而由于矛盾的需求与权衡因素的存在,AR 也可能会对其它质量特性带来负面的影响。

在我看来,AR 的过程就是对某个架构决策进行重新审视 2,并为某些设计问题的集合提供一种不同的解决方案。决策的执行牵涉到多个相关的工程任务,它们可以被归类为以下几种:

  • 认识到某个设计中的结构性变化的任务。这种变化的范围比起代码重构更大,它需要与组件、子系统以及系统的系统(和它们的接口)打交道。
  • 在开发与运维过程中的实现与配置任务(取决于 AR 的视角)。
  • 文档与交流任务,例如建模活动、技术写作工作、或技术研讨会的准备与促进。

AR**** 名称

如何能够轻易地认出某个 AR 并进行引用?

SQL

背景

该 AR 适用于的场景(以及所处的条件)是什么?

从功能性的观点与信息的观点这两者的角度对概念级别(数据库范式)以及资产级别(MySQL 与 MongoDB)进行抽象。

项目干系人的关注点

该 AR 会影响到哪些非功能性需求以及约束(包括质量特性及设计外力)?

灵活性(从数据模型变更的角度)、数据完整性,以及迁移时间。

架构坏味道

在何时,以及为什么要考虑该 AR?

当数据模型(数据库架构)产生变动时,将现有的数据库内容进行迁移所需的时间太长。

需要重新审视的架构决策

与该 AR 相关的设计问题有哪些,目前采取了哪些设计方式以处理这些问题?

  • 数据建模的范式的选择(目前的决定是关系型数据)
  • 元模型及查询语言的选择 (目前的决定是 SQL)
  • 数据库管理系统的选择 (目前的决定是 MySQL)

改进轮廓 (解决方案的简介)

现在应当选择哪些设计选项?

解决方案的目标看起来是怎样的?

  • 使用面向文档的数据库,例如 MongoDB 以取代关系型数据库,例如 MySQL。
  • 对事务管理与数据库管理进行重新设计。

受影响的架构元素

哪些设计模型元素必须进行改动(例如被显式建模的组件与连接器)?

  • 数据库层(包括服务器进程、备份与恢复功能)。
  • 数据访问层 (例如命令与查询的模式,以及连接池)。

执行任务

如何应用并验证该 AR?

  • 设计文档布局 (需要机器可读的 SQL 数据定义语言)。
  • 编写一个新的数据访问层,并在应用中实现类 SQL 的查询功能。
  • 决定事务边界(如果存在的话)。
  • 对数据库管理变更进行文档化(例如命令行查询、更新脚本以及备份过程)。
  • 根据成功标准(例如迁移时间与数据访问层的性能),对新旧两套方案进行对比。

表 1. 某个架构重构(AR)的结构化表现。

我所设计的以决策和任务为中心的 AR 视图是对 Michael Stal 的观点的一种补充与扩展,他在 2007 年发表了关于 AR 的第一份目录 3。为了对他的 AR 进行文档化,Stal 使用了一种简单的模式格式,其中包括三个部分:背景、问题与一般方案意见。他所描述的 AR 包括“打破依赖循环”以及“切分子系统”,分别对应了“依赖循环”与“功能切分不充分”这两种架构上的坏味道 4。

以任务为中心的模板的示例

Doodle.com 的首席技术官在他们的博客上解释了他们为什么要从 MySQL 迁移到 MongoDB 的原因,这是在他们的协作型在线日程设定服务上线使用多年后所做出的一个决定。在这个案例中的架构坏味道在于,一旦 SQL 架构产生变化(例如在某张表中加入新的一列),对大型的生产环境中的数据库进行迁移的过程耗时极长。受到影响的质量特性包括开发与运维的生产力,以及数据库和数据访问层的性能与可伸缩性。而这种坏味道的症结在于,关系型数据库管理系统本身就不是为了应对这种使用场景而设计的,虽然它们能够勉强处理这种需求,但并非最佳选择。

他们所采用的方案是对架构方面的决策进行重新审视,这些决策包括数据库范式、查询 API 以及数据库 provider。技术官最终决定使用面向文档的范式,这也是无架构的 NoSQL 技术中的其中一种,并使用 MongoDB 作为文档数据库的实现。这一变化改进了迁移管理的同时,也带来了管理与代码方面的成本,他们需要为此编写新的数据访问、事务以及备份管理方面的新方案。

Doodle 的示例体现了一次成功的 AR,因为它通过对某个架构决策进行重新审视,改善了某方面的质量特性,而并不包括代码的重构。表 1 以结构化的方式展现了这个 AR 过程,使它更容易理解,并能够应用到类似的项目中。这一示例也提供了一个 AR 文档模板的建议,表 1 中的每一行都是模板中的一个条目。图 1 展示了模板结构的结果。

在使用表 1 中展现的模板对你自己的 AR 进行文档化时,要注意 AR 名称应当具有表达性,例如某种隐喻。与通常使用名词的模式名称不同,AR 名称应当是动词,例如在代码重构过程中所使用的名称。背景部分可以包含软件工程方法中的抽象级别信息,或者是企业架构管理框架中的观点。由于 AR 描述了一种设计上的变化,因此可以提供两种方案的简介,即应用 AR 前的设计以及应用 AR 之后的设计。架构元素与结构化设计之间建立了一种链接,这种链接可以被显式地建模、非正式的描述或在代码中进行隐式的表述。任务描述这部分可以引述敏捷计划工具或软件工程活动中的工作项。某些执行任务是可以被自动化的(正如在许多代码重构过程中的执行一样),但并非所有任务都可以,因为 AR 是在一个更高的抽象层面的过程,它的范围已超过了代码重构。

图 1. 某个架构重构的解剖图。左边的部分展示了在某个特定上下文(例如视角或抽象级别)中观察到的架构坏味道,这属于某种质量特性(QA)方面的关注点。右边的部分简述了经过重构后的架构,并确认了相关的设计、实现以及文档任务。而需要重新审视的架构决策而扮演了这两部分之间的粘合剂。

架构重构目录

让我们将目光放远一点,来看看一些其它的 AR。表 2 以两个维度列举了基本的 AR,分别是架构的角度与变更的类型。这些 AR 可以被表示为图 1 中的以任务为中心的模板实例。举例来说,“引入缓存”这一任务的具体工作包括决定一个查找键、缓存失效策略、缓存的分布等等。

在今后,还有可能出现特定于某个领域与风格的 AR 目录,可能会用于金融服务软件、游戏开发或云计算。举例来说,对于企业的应用现代化,以下三种 AR 都可以属于这一目录。

将会话状态管理功能转移(例如,从客户端或中间服务器转移至数据库,以改善水平伸缩的能力,并更好地利用云的弹性)。

  • 在某个服务接口契约中,使用数据迁移对象取代标量参数(以减少远程调用的次数)。
  • 简化某个 Web 客户端(以减少客户端的负荷,增加它的处理能力)。
  • 基本的 AR 与特定的 AR 都能够提供一种跨社区的协作方式,协作双方可以包括:
  • 架构与开发。AR的执行可能会包括一次或多次代码重构的实践,这部分工作也必须统一规划。
  • 架构与项目管理。根据 AR 模板所组织的 AR 描述可以作为计划中的任务,对于 AR 的需求就意味着某种技术债的现形。
  • 架构与运维(ArchOps)。从部署的角度来看,可以将 AR 视为一种沟通的方式。

表 2. 视角、AR 类型,以及对应的 AR。

如何高效地共享并执行 AR,这一点还有待观察。模板与目录是否能够有效地承载这些知识,还是说建模与协作工具更适合于这一场景呢?基于 Web 交付的知识具有天然的竞争力,这已经通过 Wikipedia 得到了证明。代码重构任务可以通过阅读书籍及正式的基础着手,而重构工具(例如 Eclipse 中的工具)是在很久之后才开发出来的,此时已经存在了丰富的内容,建立了完整的理论,人们也获得了大量的经验。对于 AR 工具的支持同样需要与建模工具相配合,这些建模工具能够支持 UML 或架构描述语言,但这种支持能力目前还没有看到。

致谢

感谢来自拉珀斯维尔的东瑞士应用科学大学的 Christian Bisig 与 Mirko Stocker,他们对本文的原始版本进行了审校。同样感谢曾出席我在 OOP 2014 与 GI FG SWA 2014 会议上的演讲的听众,在演讲中我介绍了对云服务进行架构重构的方式,他们的反馈对我帮助很大。

引用

  1. M. Fowler 于 2004 年 9 月 1 日所发表的博文“重构的定义”(Definition of Refactoring)。
  2. O. Zimmermann 于 IEEE Software 杂志 2011 年第 28 期第一卷中的 64-69 页中的文章,“将架构决策视为可重用的设计资产” (Architectural Decisions as Reusable Design Assets)。
  3. M. Stal 于 2007 年发表的“软件架构重构”(Software Architecture Refactoring)。
  4. M. Stal 与 M. Babar、A. Brown、I. Mistrik、Morgan Kaufmann 于 2013 年于敏捷软件架构第一期所发表的“重构软件架构”(Refactoring Software Architecture)。
  5. P. Sevinç于 2011 年 4 月 14 日所发表的博文“ Doodle 技术面面观” (Doodle’s Technology Landscape)。

关于作者

Olaf Zimmermann是拉珀斯维尔的东瑞士应用科学大学软件协会的一名教授与合作伙伴,可以通过 ozimmerm@hsr.ch 联系他。

本文最初 __ 发表在 IEEE__ 软件杂志上, IEEE__ 软件杂志致力于发表严谨的、经过互相审校的文章,专注于当今世界的战略科技。为了满足运行可靠且灵活企业所面临的挑战,IT 经理和技术管理者依赖 IT Pro 获取最先进的解决方案。

查看英文原文: Architectural Refactoring: A Task-Centric View on Software Evolution

2015-08-12 00:362767
用户头像

发布了 428 篇内容, 共 167.0 次阅读, 收获喜欢 35 次。

关注

评论

发布
暂无评论
发现更多内容

Go 专栏|说说方法

AlwaysBeta

Go 语言

在线JSON转JAVA工具

入门小站

工具

升级mysql-connector-java-8.x踩坑纪实

小江

Java MySQL 时间戳 服务器时区 夏令时

祝贺 StreamNative 工程师张勇成功跻身 Apache BookKeeper Committer

Apache Pulsar

bookKeeper Apache Pulsar StreamNative

国产接口管理工具APIPOST中的常见设置项

Proud lion

大前端 后端 Postman 开发工具 接口文档

Go 专栏|复合数据类型:字典 map 和 结构体 struct

AlwaysBeta

Go 语言

【Flutter 专题】58 图解 Flutter 嵌入原生 AndroidView 小尝试

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 9月日更

就靠这一篇文章,我就弄懂了 Python Django 的 django-admin 命令行工具集

梦想橡皮擦

9月日更

【Vue2.x 源码学习】第四十三篇 - 组件部分 - 组件相关流程总结

Brave

源码 vue2 9月日更

多线程知识体系01-线程池源码阅读讲解-Executor

小马哥

多线程 高并发 源码阅读 源码剖析 日更

【LeetCode】 二叉树中和为某一值的路径Java题解

Albert

算法 LeetCode 9月日更

Go 专栏|错误处理:defer,panic 和 recover

AlwaysBeta

Go 语言

Linux之lastlog命令

入门小站

Linux

Java中的变量与常量

IT蜗壳-Tango

9月日更

netty系列之:搭建自己的下载文件服务器

程序那些事

Java Netty io nio 程序那些事

❤️用武侠小说的形式来阅读LinkedList的源码,绝了!

沉默王二

Java

Go 专栏|接口 interface

AlwaysBeta

Go 语言

架构学习模块一

George

柯基数据通过Rainbond完成云原生改造,实现离线持续交付客户

北京好雨科技有限公司

云原生 需求落地 离线部署 可持续交付

如何设计企业特色的数字化转型架构?

博文视点Broadview

【报名】飞桨中国行丨企业零门槛AI创新应用-智能制造专场

百度大脑

人工智能

Go 专栏|流程控制,一网打尽

AlwaysBeta

Go 语言

Go 专栏|函数那些事

AlwaysBeta

Go 语言

模块(二)如何设计架构

我是一只小小鸟

Electron团队为什么要干掉remote模块

刘晓伦

Electron Node

Vue进阶(九十):过滤器

No Silver Bullet

Vue 9月日更

华为云PB级数据库GaussDB(for Redis)揭秘:如何搞定推荐系统存储难题

华为云开发者联盟

数据库 推荐系统 存储 华为云 GaussDB(for Redis)

Go 专栏|复合数据类型:数组和切片 slice

AlwaysBeta

Go 语言

浪潮云说丨上云迁移——快,准,稳!

浪潮云

云计算

深入分析3种线程池执行任务的逻辑方法

华为云开发者联盟

Java 线程 线程池 ThreadPoolExecutor类

从一个并发异常问题引起的想法

卢卡多多

并发编程 9月日更

  • 需要帮助,请添加网站小助手,进入 InfoQ 技术交流群
架构重构:通过以任务为中心的视角看软件的进化_架构_Olaf Zimmermann_InfoQ精选文章