1. 引言

正交性(Orthogonality)这个词源于古希腊语“orthós”(意为垂直)和“gōnía”(意为角度)。它在数学、物理、信号处理、通信、编程等多个领域中都有广泛应用,但在不同领域中含义略有不同。

在计算机科学中,正交性的核心思想是:修改一个部分不会对其他部分产生意料之外的影响。 换句话说,它描述的是系统中各组件之间的独立性。

这篇文章我们将围绕正交性在编程语言、软件设计、数据存储等几个方面展开讲解,并结合实际例子帮助理解。


2. 编程语言中的正交性

我们通过语言内置结构之间组合时是否产生副作用来衡量其正交性。在理想正交的语言中,任意语言结构和特性之间可以自由组合而不互相影响。

根据正交性的程度,编程语言可分为三类:

  1. 完全正交(Fully Orthogonal)
  2. 部分正交 / 准正交(Quasi-Orthogonal)
  3. 非正交(Non-Orthogonal)

下图展示了这三类语言及其代表语言:

orthogonality in programming languages

2.1 完全正交语言

完全正交语言是指其大多数结构之间可以自由组合而不会产生副作用。 Scala 是这类语言的典型代表。

比如在 Scala 中,函数可以像其他对象一样使用:作为局部变量、字段、或作为其他函数的参数传递。在这个过程中不会产生副作用。例如将一个函数作为参数传递时并不会立即调用它。Scala 同时支持面向对象和函数式编程范式,并且这两种范式之间可以自由混用而不会产生副作用。

✅ 优势:灵活性高,代码复用性强
❌ 缺点:语法复杂,学习曲线陡峭

2.2 准正交语言

准正交语言是指其部分基本结构之间可以组合而不产生副作用,但大多数结构之间不能自由组合。 Java 和 Python 属于此类。

在 Python 中,我们可以组合内置数据结构如列表(list)和集合(set)来构建更复杂的数据结构。但构造器 list 没有副作用,而 set 有副作用。例如:

list(set(x)) != set(list(x))

这说明 listset 并不正交。

在 Java 中,访问控制符 publicprivatestatic 是完全正交的。但变量的存储方式取决于其类型,这会产生副作用。例如:

int x; /* x 是栈上的值 */
MyClass y; /* y 是堆上对象的引用 */

✅ 优势:语法清晰,适合大型项目
⚠️ 踩坑点:某些结构之间不兼容,容易踩坑

2.3 非正交语言

非正交语言是指大多数结构之间不能自由组合,修改一个结构可能会影响其他结构。

比如 C++ 被认为是非正交语言。例如下面这段模板声明中,我们不能直接使用 void 类型,必须显式转换:

template<typename T> T f() 
{ 
 ... 
} 
T = void; // 需要显式处理 void 类型

再比如 C 语言中,虽然可以返回结构体(struct),但不能返回数组(array)。结构体成员不能是 void 或同类型结构体,数组也不能是 void 类型。

✅ 优势:性能高,适合底层开发
❌ 缺点:语法不统一,容易产生副作用

2.4 正交性的后果

高度正交的语言通常更简单、更容易学习。但这也意味着语言结构之间组合方式多,导致编译器或解释器实现复杂度上升

此外,语言中需要保持向后兼容的特性也应尽量正交,否则不同版本之间可能会产生兼容性问题,进而增加开发和维护成本。


3. 软件设计中的正交性

正交性是实现“3C 设计”(Complete, Concise, Correct)的关键要素之一。一个设计或架构是正交的,当且仅当它的操作不会产生副作用或后效。

换句话说,每个动作(如 API 调用、回调、后台线程调用或语言操作)只改变一个部分,不影响其他部分。

举个例子:我们有一个认证服务和三个客户端应用。如果每个客户端发送的认证请求由服务端独立处理,彼此之间互不干扰,那么这个系统就是正交的。正交系统中,改变一个子系统的属性只有唯一一种方式。

正交性在软件设计中能显著减少测试和开发时间,因为没有副作用、组件之间不相互依赖的设计更容易验证。

3.1 正交系统的例子

我们考虑一个由三部分组成的系统:

  1. 后端
  2. 数据库
  3. 前端

前端提供用户交互界面,数据库存储数据,后端实现服务逻辑。

Orthogonal Example

在这个系统中:

  • 我们可以修改前端界面而不影响后端服务和数据库
  • 可以将数据库从 Oracle 切换到 MySQL,只需少量接口代码调整
  • 可以后端修改搜索算法而不影响前端和数据库

✅ 优势:模块清晰,易于维护和扩展
⚠️ 踩坑点:接口设计需严谨,否则破坏正交性

3.2 非正交系统的例子

同样是上述系统,但后端使用数据库的存储过程来执行高级搜索操作。后端服务只是对数据库存储过程的一个封装。

Non-orthogonal Example

在这种情况下:

  • 无法更换数据库而不影响后端
  • 没有清晰的接口隔离
  • 数据库的任何变化都会影响整个系统

❌ 缺点:耦合度高,维护成本大


4. 数据存储中的正交性

从数据存储的角度来看,我们通常希望系统具备持久性和容错性。数据在存储系统中保持完整的时间长度称为持久性(persistence)。

在存储领域,正交持久性指的是:开发者在获取和处理数据时,不需要关心数据的存储时间。换句话说:

在正交存储中,数据存储时间的长短不会影响我们对它的处理方式。

✅ 优势:开发更简单,数据处理逻辑统一
⚠️ 踩坑点:实现正交持久性需要良好的抽象层支持


5. 总结

正交性是编程中一个非常重要的概念,它强调组件之间的独立性,确保修改一个部分不会对其他部分造成副作用。

正交系统的优势:

  • 易于维护和扩展
  • 减少测试和开发时间
  • 接口清晰,系统结构稳定

⚠️ 正交系统的挑战:

  • 实现复杂度高
  • 接口设计要求高
  • 需要权衡语言特性的正交性和实用性

正交性不是绝对的,而是一个设计目标。我们在设计语言、系统架构或数据结构时,应尽可能提高其正交性,以提升系统的可维护性和可扩展性。


原始标题:Orthogonality in Computer Programming