Netty 的包结构很棒。
每个程序员都应该学习它;每个系统都应该模仿它;每个项目经理都应该把它打印出来,拍在墙上,然后对开发人员说,“那个。”
Netty 是一个“……一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能协议服务器和客户端”,但这在这里并不重要,因为我们没有分析它的行为。相反,请看图 1。
图 1:Netty 的包结构在 7 年内不断发展。
图 1 显示了 Netty 不断发展的包结构的 spoiklin 图(圆圈是包;直线是页面下的依赖关系;曲线是页面上的依赖关系),如果您不能立即看出它的结构有多好是,然后看看 Junit、Struts 或 Ant。
也不仅仅是“旁观者眼中有好的结构”。 结构混乱提供了一个程序结构糟糕程度的客观衡量标准:结构混乱程度越低,结构越好。 Netty 的混乱程度远低于几乎所有其他情况,请参见表 1。
程序 | 包结构紊乱 |
蚂蚁 | 81% |
联合 | 76% |
Struts | 74% |
Lucene | 73% |
健身 | 61% |
Spring | 35% |
网络 | 26% |
表 1:本系列中审查的所有项目的结构紊乱。
更重要的是,图 2 显示了这种最终的结构紊乱并非偶然。 Netty 的结构紊乱在其七年的生命周期中一直很低。
图 2:Netty 在 11 个版本中的结构混乱(与其他版本进行比较)。
那么:为什么这个包结构这么好?
给定如图 1 所示的图表,我们可以提出两个快速问题来评估(粗略地)所描述结构的优点。
在商业软件开发中,“良好的结构”简单意味着“更新便宜”。此外,证据 建议每个了解连锁反应的程序员都知道:X 依赖的东西越多,受到影响的可能性就越大通过连锁反应,因此 X 的成本可能更高。
因此,选择一个严重依赖于其他包的包并询问(A)我们能否轻松识别依赖的包以及(B)这些依赖包的整体子集有多大?
结构不良的程序会掩盖这些依赖关系,而仔细检查通常会揭示对几乎整个系统的依赖关系。然而,结构良好的程序清楚地显示了所依赖的包,而且它们很少。
让我们首先针对结构不良的程序提出这两个问题。
图 3 显示了 Jenkins 可怕的 90% 的结构混乱,然后显示了五个包(工具提示)中最依赖于其他包的突出显示的传递依赖性。
图 3:詹金斯,哦詹金斯。
清楚地跟踪 Jenkins 中的依赖关系……是一个挑战,许多包依赖于系统其余部分的 75% 以上。
图 4 重复了该实验,但显示了五个最依赖于其他包的 Netty 包的传递依赖性:epoll、spdy、websocketx、http 和 nio。
图 4:突出显示(蓝色)Netty 中最差的传递依赖。
与Jenkins形成鲜明对比的是,我们可以看到依赖的Netty包是多么的少。 Netty 有 55 个包,但任何其他包所依赖的最多只有 12 个,也就是系统的 22%。
Netty 的包结构是否完美?当然不是。特别是 internal 和 concurrent 之间的循环依赖在核心 internal/concurrent/channel/buffer/util 包集群中产生了令人遗憾的强耦合。
从表面看,Netty 的类结构确实很糟糕。 Netty 的设计者在构建其类级 时显然放弃了一些优秀的结构原则。丢人现眼。
但是看看那个包结构……哇。
最后,不是分析 Netty 的关键版本,而是架构观察本身。 Netty 的架构师似乎已经决定了一个相当出色的部署策略。下载 Netty 不仅可以为您提供一个一体化的 jar 文件,还可以为您提供 13 个包含系统独立部分的 jar 文件。大概您可以加载所有 Netty 或只加载您想要的部分。
一个 jar 文件,“通用”jar,包含 internal/concurrent/channel/buffer/util 包集群,而其他文件包含,例如,“codec”、“tcnactive”、“transport”、等等,这表明后面这些 jar 是公共 jar 的客户端,但不是彼此的客户端,因此彼此之间没有依赖关系。因此,在他们的部署中,Netty 的设计者可能已经将他们的子系统的分离和封装奉为神明,这导致了这种行业领先的包结构。
剩下的唯一问题是:为什么没有更多项目效仿 Netty?为什么 Jenkins 有 90% 的结构紊乱?为什么 Jenkins 的设计者没有正确地划分他们的系统以减少包间耦合?为什么软件开发领域如此愿意接受这些糟糕的结构所产生的成本?
我们不是比这更好吗?
如果每年颁发一次当今使用的最佳 Java 包结构的奖项,Netty 将连续七年获奖。
标签2: Java教程地址:https://www.cundage.com/article/jcg-the-structure-of-netty.html