论软件架构
An Introduction to Software Architecture
kemin:本文为粗略翻译,并且相当一部分根据人个的理解来译,不够严谨和专业。如有不妥的地方,或者有更好的翻译建议,欢迎高手提点。
KEY:软件工程 软件体系结构 设计
Abstract
As the size of software systems increases, the algorithms and data structures of the computation no longer constitute the major design problems. When systems are constructed from many components, the organization of the overall system-the software architecture-presents a new set of design problems. This level of design has been addressed in a number of ways including informal diagrams and descriptive terms, module interconnection languages, templates and frameworks for systems that serve the needs of specific domains, and formal models of component integration mechanisms.
随着软件系统规模的增长,算法和数据结构不再是软件设计的主要问题了。当系统由大量的组件组成,整个系统的组织问题成了新的设计问题--软件架构设计。目前已经有相当的解决软件架构设计的方法,像非形式图表、模块交互语言、模板、专用系统框架和组件集成机制的形式模型。
In this paper we provide an introduction to the emerging field of software architecture. We begin by considering a number of common architectural styles upon which many systems are currently based and show how different styles can be combined in a single design. Then we present six case studies to illustrate how architectural representations can improve our understanding of complex software systems. Finally, we survey some of the outstanding problems in the field, and consider a few of the promising research directions.
在这里我们提供一些有关软件架构方面的内容。我们首先引进一些目前很多系统正在使用的软件构架风格,并展示在单一的设计下如何混合不同的风格。接着我们举六个例子,看看架构图(architectural representations )如何能够提高我们对复杂软件系统的把握。最后,我们小结一下目前这一领域的一些突出问题,并指出它的研究方向。
- 1. Introduction ..................................................................................................... 2
- 2. From Programming Languages to Software Architecture..................... 3
- 2.1. High-level Programming Languages ................................................................... 3
- 2.2. Abstract Data Types........................................................................................... 4
- 2.3. Software Architecture........................................................................................ 4
- 3. Common Architectural Styles...................................................................... 5
- 3.1. Pipes and Filters ................................................................................................ 6
- 3.2. Data Abstraction and Object-Oriented Organization ........................................... 8
- 3.3. Event-based, Implicit Invocation ........................................................................ 9
- 3.4. Layered Systems ................................................................................................ 11
- 3.5. Repositories ....................................................................................................... 12
- 3.6. Table Driven Interpreters ................................................................................... 13
- 3.7. Other Familiar Architectures............................................................................. 14
- 3.8. Heterogeneous Architectures............................................................................... 15
- 4. Case Studies...................................................................................................... 16
- 4.1. Case Study 1: Key Word in Context ..................................................................... 16
- 4.2. Case Study 2: Instrumentation Software .............................................................. 22
- 4.3. Case 3: A Fresh View of Compilers..................................................................... 26
- 4.4. Case 4: A Layered Design with Different Styles for the Layers ........................... 28
- 4.5. Case 5: An Interpreter Using Different Idioms for the Components........................ 30
- 4.6. Case 6: A Blackboard Globally Recast as Interpreter ........................................... 33
- 5. Past, Present, and Future ............................................................................... 36
1. Introduction
As the size and complexity of software systems increases, the design problem goes beyond the algorithms and data structures of the computation: designing and specifying the overall system structure emerges as a new kind of problem. Structural issues include
- gross organization and global control structure;
- protocols for communication, synchronization, and data access;
- assignment of functionality to design elements;
- physical distribution;
- composition of design elements;
- scaling and performance;
- and selection among design alternatives.
This is the software architecture level of design. There is a considerable body of work on this topic, including module interconnection languages, templates and frameworks for systems that serve the needs of specific domains, and formal models of component integration mechanisms. In addition, an implicit body of work exists in the form of descriptive terms used informally to describe systems. And while there is not currently a well-defined terminology or notation to characterize architectural structures, good software engineers make common use of architectural principles when designing complex software. Many of the principles represent rules of thumb or idiomatic patterns that have emerged informally over time. Others are more carefully documented as industry and scientific standards.
以上几点是软件架构级的设计问题(相对于数据结构与算法设计级别)。
It is increasingly clear that effective software engineering requires facility in architectural software design. First, it is important to be able to recognize common paradigms so that high-level relationships among systems can be understood and so that new systems can be built as variations on old systems.
Second, getting the right architecture is often crucial to the success of a software system design; the wrong one can lead to disastrous results. Third, detailed understanding of software architectures allows the engineer to make principled choices among design alternatives. Fourth, an architectural system representation is often essential to the analysis and description of the high-level properties of a complex system.
对软件架构设计的工具(facility )的需求变得越来越清晰和迫切。第一,它有助于对识别系统中各部分的高层的关系,从而将系统中的通用模式应用于新系统;第二,一个软件的架构设计的正确与否决定它的成功与失败;第三,对软件架构的深刻理解有助于工程人员在为设计选择可选方案时作出正确的决策;第四,系统构架图常常是分析和描述复杂系统的高层属性的关键。
In this paper we provide an introduction to the field of software architecture. The purpose is to illustrate the current state of the discipline and examine the ways in which architectural design can impact software design.
The material presented here is selected from a semester course, Architectures for Software Systems, taught at CMU by the authors [1]. Naturally, a short paper such as this can only briefly highlight the main features of the terrain.
This selection emphasizes informal descriptions omitting much of the course’s material on specification, evaluation, and selection among design alternatives.
We hope, nonetheless, that this will serve to illuminate the nature and significance of this emerging field.
In the following section we outline a number of common architectural styles upon which many systems are currently based, and show how heterogeneous styles can be combined in a single design. Next we use six case studies to illustrate how architectural representations of a software system can improve our understanding of complex systems. Finally, we survey some of the outstanding problems in the field, and consider a few of the promising research directions.
The text that makes up the bulk of this article has been drawn from numerous other publications by the authors. The taxonomy of architectural styles and the case studies have incorporated parts of several published papers [1, 2, 3, 4]. To a lesser extent material has been drawn from other articles by the authors [5, 6, 7].
2. From Programming Languages to Software Architecture
One characterization of progress in programming languages and tools has been regular increases in abstraction level-or the conceptual size of software designers building blocks. To place the field of Software Architecture into perspective let us begin by looking at the historical development of abstraction techniques in computer science.
编程工具和编程语言发展的一个特性就是它的抽象度的不断提高。抽象度也可理解为软件开发建造块的概念的尺寸。为了深入软件架构的领域,我们得先回顾一下计算机科学中抽象技术的发展史。
2.1. High-level Programming Languages
When digital computers emerged in the 1950s, software was written in machine language; programmers placed instructions and data individually and explicitly in the computer's memory. Insertion of a new instruction in a program might require hand-checking of the entire program to update references to data and instructions that moved as a result of the insertion.
Eventually it was recognized that the memory layout and update of references could be automated, and also that symbolic names could be used for operation codes, and memory addresses. Symbolic assemblers were the result. They were soon followed by macro processors, which allowed a single symbol to stand for a commonly-used sequence of instructions. The substitution of simple symbols for machine operation codes, machine addresses yet to be defined, and sequences of instructions was perhaps the earliest form of abstraction in software.
计算机早期,程序员用机器语言开发软件。他们直接在计算机的内存中安排程序的数据和指令。为程序添加一条新的指令时,程序员必须重整整个程序内存布局,比如更新所有数据和指令的地址引用,很麻烦。
尔后,科学家发现内存布局和引用的更新可以被自动的处理,而且指令操作码和内存地址也可以用符号来代替。这就是符号汇编了。接着很快也有了宏处理器,用以将一个单一的符号来代替一联串常用指令。符号指令、符号地址和宏机制算是软件开发最早的抽象技术。
In the latter part of the 1950s, it became clear that certain patterns of execution were commonly useful-indeed, they were so well understood that it was possible to create them automatically from a notation more like mathematics than machine language. The first of these patterns were for evaluation of arithmetic expressions, for procedure invocation, and for loops and conditional statements. These insights were captured in a series of early high-level languages, of which Fortran was the main survivor.
五十年代后期,常用的代码执行的模式被逐渐的发现。第一个被发现的模式就是算术求值表达式;接着是子过程、循环和条件语句。这些洞见被后来的高级语言所取用。Fortran 就是其中到目前还活的一种。
Higher-level languages allowed more sophisticated programs to be developed, and patterns in the use of data emerged. Whereas in Fortran data types served primarily as cues for selecting the proper machine instructions, data types in Algol and it successors serve to state the programmer’s intentions about how data should be used. The compilers for these languages could build on experience with Fortran and tackle more sophisticated compilation problems. Among other things, they checked adherence to these intentions, thereby providing incentives for the programmers to use the type mechanism.
Progress in language design continued with the introduction of modules to provide protection for related procedures and data structures, with the separation of a module’s specification from its implementation, and with the introduction of abstract data types.
高级语言的出现使开发复杂的程序成为了可能,数据使用的模式开始出现。Fortran 的数据类型只是代表不同的机器指令,到Algol和它的后续者的数据类型已经表达程序员有关如何使用数据的意图了。各种数据类型的抽象问题都交给了编译器来解决,程序员渐渐远离具体的硬件实现机制。
语言的继续发展,出现了模块思想。模块将相关的过程代码和数据结构保护起来,隐藏具体实现和只通过接口与外界交互。抽象数据类型(abstract data types)也是一种模块。
2.2. Abstract Data Types
In the late 1960s, good programmers shared an intuition直觉 about software development: If you get the data structures right, the effort will make development of the rest of the program much easier. The abstract data type work of the 1970s can be viewed as a development effort that converted this intuition into a real theory. The conversion from an intuition to a theory involved understanding
- • the software structure (which included a representation packaged with its primitive operators),
- • specifications (mathematically expressed as abstract models or algebraic axioms),
- • language issues (modules, scope, user-defined types),
- • integrity of the result (invariants of data structures and protection from other manipulation),
- • rules for combining types (declarations),
- • information hiding (protection of properties not explicitly included in specifications).
六十年代后期,程序员们对软件开发已经有相当的感性认识,并得到了一个共识--正确数据结构的选择使开发工作更容易。“抽象数据类型”便是从对软件开发的感性认识上升到理性认识的结果。要获得这种质的飞跃,必须理解以下几点:
- 软件结构(包括带有原始操作符的表述方法)
- 规格标准(数学化地表达成抽象模型或代数公理)
- 语言问题(模块、作用域、用户定义类型)
- 结果的完整性(数据结构的不变性和确保其不被非法更改)
- 类型合成的规则(声明)
- 信息隐藏()
The effect of this work was to raise the design level of certain elements of software systems, namely abstract data types, above the level of programming language statements or individual algorithms. This form of abstraction led to an understanding of a good organization for an entire module that serves one particular purpose. This involved combining representations, algorithms, specifications, and functional interfaces in uniform ways. Certain support was required from the programming language, of course, but the abstract data type paradigm allowed some parts of systems to be developed from a vocabulary of data types rather than from a vocabulary of programming-language constructs.
程序员们的这些工作最终提升了软件系统组成元素的设计层级,它的名字叫做抽象数据类型。这个层级高于前面所讲述的编程语句和单独算法的层级。这种形式的抽象使人们明白了写特定功能的模块时需要“良好的组织”,包括一致的复合表征方法、算法、规范和功能接口。当然,这些都需要编程语言的支持,但可以确定的是,抽象数据类型使软件开发使用上了数据类型词汇,而不再只是使用编程语言概念的基本词汇。
(kemin:在这里我们要问语言的这种层级的提升给了我们什么?要回答这个问题,得先回答另一个问题--语言与软件之关系如何?软件及其构件都是有机无生命体(说它是无生命是因为其与生命体有本质的区别,不过它的确是有机体),而语言则是构造这些有机体的工具或手段。语言层级的提升使用我们用同样的设计水平构造出更复杂的有机体。)
(kemin:既然都是有机体,那么一只小麻雀与一个MP3播放器之问有那些共同点和不同点呢?有机体都是时间演化的结果,我们先撇开演化的历史,从其中的一个相对稳定和静态时间段抽取一个实例来研究。)由于软件程序并非生命,所以MP3播放器与麻雀只有有机体方面的可比性。生命有机体大略具有以下七个“活着”生命现象:1 。体内平衡、组织性、新陈代谢、生长、适应、对刺激作出反应和繁殖(http://zh.wikipedia.org/wiki/%E7%94%9F%E5%91%BD )。
2.3. Software Architecture
Just as good programmers recognized useful data structures in the late 1960s, good software system designers now recognize useful system organizations. One of these is based on the theory of abstract data types. But this is not the only way to organize a software system.
Many other organizations have developed informally over time, and are now part of the vocabulary of software system designers. For example, typical descriptions of software architectures include synopses概要 such as (italics ours):
- •“Camelot is based on the client-server model and uses remote procedure calls both locally and remotely to provide communication among
applications and servers.”[8] - •“Abstraction layering and system decomposition provide the appearance of system uniformity to clients, yet allow Helix to accommodate a
- diversity of autonomous devices. The architecture encourages a client-server model for the structuring of applications.”[9]
- •“We have chosen a distributed, object-oriented approach to managing information.” [10]
- •“The easiest way to make the canonical标准的 sequential compiler into a concurrent compiler is to pipeline the execution of the compiler phases over a number of processors. . . . A more effective way [is to] split the source code into many segments, which are concurrently processed through the various phases of compilation [by multiple compiler processes] before a final, merging pass recombines the object code into a single program.”[11]
就像六十年代后期优秀的程序员发现了数据结构模式一样,当今优秀的软件设计师也发现了系统组织模式。其中就有基于抽象数据类型理论的。不过这还不是组织软件系统的唯一方法。大量组织方法被逐渐非形式地提出,并且已经被很多软件系统设计师用来交流。比如以下的一些例子:
- Camelot 是基于客户端-服务器模式并且使用本地的和远程的远程过程调用来提供在应用与服务器间的通信。
- 抽象的分层和系统分解为客户提供了一致系统外观,这样使Helix能适应多种不同的独立设备。
- 我们已经选用一种分布的、面向对象的方法来管理信息。
- 改造标准的串行编译器为并行编译的最简单方法就是流水线化在数个处理器下的编译执行阶段……更有效的方法便是把代码分为很多段,这些段在编译的不同阶段被并行地处理,最后合并成单一程序。
Other software architectures are carefully documented and often widely disseminated传播. Examples include the International Standard Organization's Open Systems Interconnection Reference Model (a layered network architecture) [12], the NIST/ECMA Reference Model (a generic software engineering environment architecture based on layered communication substrates) [13, 14], and the X Window System (a distributed windowed user interface architecture based on event triggering and callbacks) [15].
We are still far from having a well-accepted taxonomy分类法 of such architectural paradigms, let alone a fully-developed theory of software architecture. But we can now clearly identify a number of architectural patterns, or styles, that currently form the basic repertoire全部剧目 of a software architect.
其它的软件架构被仔细的引证并广泛的流传,像ISO网络互联的七层模型、NIST/ECMA Reference Model(一种通用的基于通信底层分层的工程环境架构)、X Window System(一种基于事件触发和回调的分布式窗口用户界面架构)。
到目前为止,我们还没有一个被广泛接受的架构模式的分类法,但是我们已经清楚的掌握相当的构架模式和设计风格了。
3. Common Architectural Styles
We now examine some of these representative, broadly-used architectural styles. Our purpose is to illustrate the rich space of architectural choices, and indicate what are some of the tradeoffs in choosing one style over another.
To make sense of the differences between styles, it helps to have a common framework from which to view them. The framework we will adopt is to treat an architecture of a specific system as a collection of computational components-or simply components--together with a description of the interactions between these components-the connectors. Graphically speaking, this leads to a view of an abstract architectural description as a graph in which the nodes represent the components and the arcs represent the connectors. As we will see, connectors can represent interactions as varied as procedure call, event broadcast, database queries, and pipes.
我们现在看看这些被广泛使用的构架风格。我们的目的是展示架构设计中可选空间的丰富性和指出在选择不同设计方案的折衷根据。 要区分两种不同的架构风格则必须要有一个通用的分类框架。我们设定这个框架把架构看成是计算组件和描述组件交互的连接器的集合。从图形上看,框架被描述成用结点代表组件,而弧线代表连接器。就我们目前的了解,连接器可以是过程调用、事件广播、数据库查询和管道连接等。
An architectural style, then, defines a family of such systems in terms of a pattern of structural organization. More specifically, an architectural style determines the vocabulary of components and connectors that can be used in instances of that style, together with a set of constraints on how they can be combined. These can include topological constraints on architectural descriptions (e.g., no cycles). Other constraints-say, having to do with execution semantics-might also be part of the style definition.
Given this framework, we can understand what a style is by answering the following questions: What is the structural pattern-the components, connectors, and constraints? What is the underlying computational model? What are the essential invariants of the style? What are some common examples of its use? What are the advantages and disadvantages of using that style? What are some of the common specializations?
一种架构风格定义一系列系统结构组织模式。特别地,架构风格决定实例设计使用什么样的组件和连接器的词汇,并且还有一系列的组件和连接器使用的限制。这些限制包括对架构描述的拓扑限制(如不能循环描述)。其它的限制(像执行语义的考虑)还应该是构架风格的一个组成部分。
有了这框架标准,我们就可以通过回答以下的问题来确定架构风格是什么了:
- 结构化组成元素--组件、连接器和限制各是什么?
- 根本的计算模型是什么?
- 风格本质不变性是什么?
- 架构的常用的场合有哪些?
- 架构风格的优点和缺点各是什么?
- 常见的特性有哪些?
kemin:要类比两类事物,从而深刻的理解事物,需要有一个类比的框架、标准或参数。这很深刻!
3.1. Pipes and Filters管道和过滤器
In a pipe and filter style each component has a set of inputs and a set of outputs. A component reads streams of data on its inputs and produces streams of data on its outputs, delivering a complete instance of the result in a standard order. This is usually accomplished by applying a local transformation to the input streams and computing incrementally so output begins before input is consumed. Hence components are termed “filters”. The connectors of this style serve as conduits导管 for the streams, transmitting outputs of one filter to inputs of another. Hence the connectors are termed “pipes”.
在管道和过虑器风格中,每一个组件都有一个输入和一个输出。组件从它的输入读取流式数据,经处理后的结果从输出口传递给下一个组件,结果是按一个固定的顺序被传递的。输入数据必须要完全在本地被增量处理完才会被输出。因此,这些组件也被称为“过滤器”。这种风格的连接器是把一个过滤器的输出传送到另一个过滤器的输入的导管,因此名之“管道”。
Among the important invariants of the style, filters must be independent entities: in particular, they should not share state with other filters. Another important invariant is that filters do not know the identity of their upstream and downstream filters. Their specifications might restrict what appears on the input pipes or make guarantees about what appears on the output pipes, but they may not identify the components at the ends of those pipes. Furthermore, the correctness of the output of a pipe and filter network should not depend on the order in which the filters perform their incremental processing-although fair scheduling can be assumed. (See [5] for an in-depth discussion of this style and its formal properties.) Figure 1 illustrates this style.
这种风格的架构的一个很重要不变量规则是,过滤器必须是独立的实体,也就是说过滤器间不能共享状态信息。另一个重要的不变量规则是过滤器并不知道它的前趋和后继过滤器的标识。规范限定了管道的输入端能接什么和保证输出端输出什么,但不为管道限定特定的组件。此外,管道输出和过滤网络的正确性不依赖于过滤器进行增量处理的顺序,尽管公正的调度被假定。
Common specializations of this style include pipelines, which restrict the topologies to linear sequences of filters; bounded pipes, which restrict the amount of data that can reside on a pipe; and typed pipes, which require that the data passed between two filters have a well-defined type.
这种风格有以下三种特性:
- 管道:限制过滤器的组成拓扑为线性序列;
- 有界的导管:限制通过管道的数据的量;
- 类型导管:限制在过滤器间传递的数据必须是定义良好的类型。
A degenerate case of a pipeline architecture occurs when each filter processes all of its input data as a single entity.1 In this case the architecture becomes a “batch sequential” system. In these systems pipes no longer serve the function of providing a stream of data, and therefore are largely vestigial. Hence such systems are best treated as instances of a separate architectural style.
The best known examples of pipe and filter architectures are programs written in the Unix shell [16]. Unix supports this style by providing a notation for connecting components (represented as Unix processes) and by providing run time mechanisms for implementing pipes. As another well-known example, traditionally compilers have been viewed as a pipeline systems (though the phases are often not incremental). The stages in the pipeline include lexical analysis, parsing, semantic analysis, code generation. (We return to this example in the case studies.) Other examples of pipes and filters occur in signal processing domains [17], functional programming [18], and distributed systems [19].
一个典型的管道/过滤器体系结构的例子是以Unix shell编写的程序。Unix既提供一种符号,以连接各组成部分(Unix的进程),又提供某种进程运行时机制以实现管道。另一个著名的例子是传统的编译器。传统的编译器一直被认为是一种管道系统,在该系统中,一个阶段(包括词法分析、语法分析、语义分析和代码生成)的输出是另一个阶段的输入。
Pipe and filter systems have a number of nice properties. First, they allow the designer to understand the overall input/output behavior of a system as a simple composition of the behaviors of the individual filters. Second, they support reuse: any two filters can be hooked together, provided they agree on the data that is being transmitted between them. Third, systems can be easily maintained and enhanced: new filters can be added to existing systems and old filters can be replaced by improved ones. Fourth, they permit certain kinds of specialized analysis, such as throughput and deadlock analysis. Finally, they naturally support concurrent execution. Each filter can be implemented as a separate task and potentially executed in parallel with other filters.
But these systems also have their disadvantages.2 First, pipe and filter systems often lead to a batch organization of processing. Although filters can
--------------
1In general, we find that the boundaries of styles can overlap. This should not deter us from identifying the main features of a style with its central examples of use.
2This is true in spite of the fact that pipes and filters, like every style, has a set of devout religious followers-people who believe that all problems worth solving can best be solved using that particular style.
process data incrementally, since filters are inherently independent, the designer is forced to think of each filter as providing a complete
transformation of input data to output data. In particular, because of their transformational character, pipe and filter systems are typically not good at handling interactive applications. This problem is most severe when incremental display updates are required, because the output pattern for incremental updates is radically different from the pattern for filter output.
Second, they may be hampered by having to maintain correspondences between two separate, but related streams. Third, depending on the
implementation, they may force a lowest common denominator on data transmission, resulting in added work for each filter to parse and unparse its data. This, in turn, can lead both to loss of performance and to increased complexity in writing the filters themselves.