来自软件架构大师的 4 个真理

Posted 禅与计算机程序设计艺术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了来自软件架构大师的 4 个真理相关的知识,希望对你有一定的参考价值。

1. 软件开发是一门科学

科学与数学的根本区别在于,它不可能证明科学理论和规律的正确性。

我无法从数学上证明牛顿第二定律是正确的。对于我可以进行多少实验以及我可以收集多少经验证据,总是有可能一些实验向我证明我的定律是错误的。

科学不是通过证明声称是真实的,而是通过证明它们是错误的来起作用。如果有一些陈述尽管我们付出了所有努力,但仍不能证明是错误的,那么我们就我们的所有目的都认为它们是正确的。

“数学是一门旨在证明陈述真实性的学科。相反,科学是一门在于证明陈述的虚假性的学科“

Dijkstra 是计算科学创始一代中最有影响力的人物之一,他说:“测试表明存在错误,而不是不存在错误”。换句话说:

可以通过测试来证明一个程序是错误的,而不是它是正确的。

这一事实的影响是非凡的。软件开发不是数学活动,即使它似乎在操纵数学结构。相反,软件更像是一门科学。

一个架构影响:Dijkstra 发现使用“goto”指令(在早期的编程语言中使用)阻止了模块的递归分解,损害了能够做出合理证明所必需的“ divide et impera”方法的使用。

另一方面,结构化编程迫使我们通过测试创建小的“科学证明”功能。这就是为什么现代语言不支持无限使用“goto”以及为什么我们仍然认为函数分解是我们最好的技术之一。

作为一名软件架构师,您必须尝试定义容易证明错误的模块(即接受测试),这要归功于您很快就会发现的学科。

2.什么是软件架构

首先,让我们揭穿软件架构师不编码的神话。软件架构师是优秀的程序员,并继续参与编程,但与此同时,他们通过建立一个最大化生产力和促进开发的项目来领导团队的其他成员。

“这种便利化背后的策略是尽可能多地留出选择余地,时间越长越好。”

因此,对于系统的正确运行,架构仅起到被动作用。糟糕的架构不是在运行过程中出现,而是在 部署、维护和扩展过程中出现。

发明该软件是因为它需要一种快速轻松地增加机器行为的方法。如果我们不能使系统灵活地改变,我们就完全错过了我们的目的。

一个所有的软件系统都可以分解为两大元素:

  • 政策:所有业务规则和程序。系统的真正价值在这里存在;

  • 详细信息:与策略通信所必需的东西,但根本不影响策略的行为(I/O 设备、数据库、框架、协议……);

因此,我们可以将软件架构的定义总结为:

“软件架构是帮助我们设计政策的学科,以便可以尽可能长时间地延迟和推迟有关细节的决策”

3. 什么是面向对象编程(OOP)

这个问题的一个常见答案是“一种模拟现实世界的方法。” 但这充其量只是一个回避的答案……。

另一个普遍的答案依赖于 3 个神奇的词来解释 OO 的本质:“封装”、“继承”和“多态”

……这些都是 OOP 范式的真正特点吗?

  • 完美 的封装也出现在像C这样的非 OO 语言中,这要归功于头文件 ( .h ) 的明智使用:我们预先在头文件中声明数据结构和函数,然后在实现文件中实现它们。我们的用户永远无法访问这些实现文件中的元素;

  • 借助一个技巧,继承也可以在 C 中获得:

非面向对象语言的继承

在这里,您可以看到NamedPoint可以伪装成Point数据结构,因为NamedPointPoint的纯超集,并维护与Point对应的成员的顺序。
事实上,这种诡计就是 C++ 实现单个Inheritance的方式。

因此,公平地说,虽然 OO 语言没有发明继承,但它们使数据结构的伪装变得更加方便,简化了程序员的生活。

  • 那么多态呢?这次是面向对象的特性……或者不是?
    事实上,我们本可以在 OOP 出现之前就实现多态行为。让我们看看这段代码:

非面向对象语言中的多态行为

例如, getchar()是一个多态函数,因为它的行为取决于 STDIN 的类型:UNIX 要求每个 I/O 设备驱动程序为每个驱动程序提供(实现)具有相同签名的标准函数。

函数getchar()可以这样实现:

换句话说,getchar( ) 只是调用由STDIN指向的FILE数据结构的指针所指向的函数。

所以我们通过小心使用指针得到了多态性。
显式使用指向函数的指针来创建多态行为的问题在于指向函数的指针是危险的:您必须记住使用这些指针初始化和调用函数的约定,否则,由此产生的错误可能很难找到和消除!

那么 OOP 真正添加了什么?

OOP 通过赋予我们控制权来消除这些约定,从而消除这些危险。它使多态性的使用变得非常简单,并赋予了我们巨大的力量。

OOP 的真正定义和价值可以概括为:

“OOP 是多态性提供的能力,可以绝对控制系统源代码中存在的每个依赖项。”

所有这一切也意味着任何源代码依赖,无论它在哪里,都可以被反转(通过插入一个接口)。

它允许架构师创建一个插件架构,其中包含高级策略的模块独立于包含低级细节的模块。低级细节被归入插件模块,可以独立于包含高级策略的模块提供和开发。

我们将在下一篇文章中更好地分析上述句子

4. 50 多年来,我们只知道不该做什么

我们刚刚看到 OOP 实际上是关于对间接传输控制的限制,但是其他范式呢?

Curiosity:我们习惯于认为现有的三种主要编程范式是以相同的顺序被发明和采用的。其实没有什么比这更假的了,恰恰相反!

  • 1936 函数式编程:它的发明早于计算机编程本身。这是 Alonzo Church 工作的直接结果,他发明了 Lambda-calculus(LISP 语言的基础,1958 年),同时追求激励 Alan Turing 的相同数学问题;此外,这里的特殊性是一个限制:

“函数式编程是通过将学科强加于变量分配来给出的。”

  • 1966 面向对象编程:这一次是 Ole Johan Dahl 和 Kristen Nygaard 意识到 ALGOL 语言中的函数调用栈帧可以移动到堆中,允许函数声明的局部变量在函数返回后很长时间仍然存在;
    正如我们已经看到的:

“面向对象的编程是通过对控制的间接转移施加纪律而给出的。”

  • 1968 年结构化编程:熟悉的“ if/then/else ”和“ do/while/until ”结构是最后一个设计,这似乎很疯狂!但正如我们已经说过的,我们亲爱的 Dijkstra 明白无限制的跳转(“ goto ”语句)对程序结构有害,我们需要更多的控制,只是在 1968 年;
    此外,在这种情况下,“进化”一直是一个限制:

“结构化规划是通过对控制权的直接转移施加纪律而给出的”

这三种范式中的每一种都从我们身上夺走了一些东西。它们中的每一个都限制了我们编写代码的方式的某些方面。它们都没有增加任何功能或功能。

在过去的半个世纪里,我们学到的是“不该做什么”。

Uncle1 Bob 用一个挑衅的短语结束:

“软件不是一种快速发展的技术。今天的软件规则与 1946 年相同,当时 Alan Turing 编写了第一个可以在电子计算机中执行的代码。工具变了,硬件变了,但软件的本质还是一样。
软件——计算机程序的东西——由序列、选择、迭代和间接组成。而已。一点也不差。”

结论

由于这些关于软件架构世界的启发性真理,我学到的经验教训让我大开眼界,并帮助我为职业生涯奠定了坚实的意识基础。

番外篇:SOLID设计原则

SOLID 是以下 5 个原则的缩写:

  • 单一责任原则 (SRP,Single-responsibility principle):A module should be responsible for one and only one actor

  • 开闭原则(OCP,Open-Closed Principle ):Software entities should be open for extension, but closed for modification

  • Liskov 替换原理 (LSP,Liskov Substitution Principle ):The behaviour on the client module must not depend on the subtypes that the server module uses

  • 接口隔离原则 (ISP,Interface Segregation Principle):No code should be forced to depend on what it does not use

  • 依赖倒置原则(DIP,Dependency Inversion Principle):The maximum flexibility of the systems is obtained when the dependencies in the source code refer only to abstractions

这些原则的共同目标是创建中间级别的软件结构:容忍变化、易于理解并作为可在多个软件系统中使用的组件的基础。

LSP 例子说明:

The main problem here is the incorrect usage of inheritance that violates LSP. To overcome the problem we could (mistakenly) start defining additional mechanisms for the client to understand the actual nature of the shape and act accordingly (if isSquare(r) then …). This has a devastating long-term negative impact and we should see that LSP has been breached.

Solution:
We need to redesign the interaction of the client-server modules creating polymorphic relations compliant with LSP principle, making the client independent from the subtypes of the server module:

In this way, the code in User will never have to be specific to Square or Rectangle to calculate the area and will not be subject to changes and increases in complexity if we introduce new subtypes (e.g. Circle).

以上是关于来自软件架构大师的 4 个真理的主要内容,如果未能解决你的问题,请参考以下文章

MVC还是在CS架构中不变的真理 这句话是啥意思???请IT强人且爱好CS的帮忙解答下 小女子感激不尽

微服务架构的优势与不足-1(转)

安卓手机root后用啥软件可以控制其他应用程序的权限?

赖公风水:四维架构原理及古代代表大师(语音)

Java架构师-十项全能 百度网盘

Java架构师-十项全能 百度网盘