结构之战

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

图 1 显示了结构良好的程序包的 spoiklin 类图

图 1:来自 Lucene 的良好包结构。

它结构良好,因为它使依赖关系跟踪相对容易。如果我们随机选择一个类——比如 ReusableStringReader—— 我们可以很容易地发现对该类的依赖,从而估计对该类所做更改的潜在成本,见图 2。

图 2:跟踪 ReusableStringReader 上的依赖项。

然而,依赖性有两种形式。语法依赖不依赖于连接节点名称的含义。然而,语义依赖性确实如此。图 2 的依赖关系是否也是良好的语义依赖关系?

要回答这个问题,我们必须检查从属类的名称并询问它们是否“有意义”,因为在它们各自的认识论领域内可能期望这些名称之间存在联系。

因此,我们有一个依赖于 ReusableStringReader 的 分析器 。这是有道理的;如果您正在构建功能来分析某些东西,您可能很想读取字符串,而“可重用”字符串读取器听起来像是一种特定类型的字符串读取器,因此这种语义依赖性不足为奇。同样, AnalyzerWrapper 很可能依赖于 Analyzer 。重复这个练习可以揭示出一个合理的语义结构。

结构是一组节点及其互连,那么哪个更重要:句法结构还是语义结构?

让我们更改图 2 以故意降低其语义结构。

纯粹的语法更改涉及更改节点之间的依赖关系。纯粹的语义更改涉及更改节点的名称(添加或删除节点既是句法更改也是语义更改)。因此,让我们通过将 ReusableStringReader 的名称更改为 Banana 来进行最小的语义修改。

图 3:语义失误。

“Banana”是 ReusableStringReader 类的一个可怕的名字。试图理解这个包的程序员看到分析功能依赖于水果(或草本植物,或香蕉是什么)时会哭泣。猴子依赖香蕉,而不是分析功能。这是糟糕的语义结构。

但是,如果我们更改 Banana 中的代码,我们仍然可以预测潜在的连锁反应吗?是的,我们可以,因为涟漪效应通过句法而不是语义依赖传播。即使我们删除所有语义信息(见图 4),我们也可以追踪可能受影响的类。

图 4:无语义图。

或者,我们可以检查语法结构糟糕的包并改进其语义以衡量整体收益。图 5 显示了这种不良封装。

图 5:来自 Lucene 的一个可怕的包。

除非我们不尝试语义改进。

因为即使 Wittgenstein 和 Chomsky 自己将图 5 结对编程到软件工程史上最著名的软件包中,估算变更成本仍然是一场噩梦。

概括

良好的软件结构的主要目的是帮助影响成本估算,并间接地降低实际影响成本。语义是一种重要的理解辅助工具,但与由优秀句法结构支持的语义水果篮相比,在糟糕的句法结构上覆盖语义健全性的更新成本更高。

语法 bitch-slap 语义。

难的。