您严格遵守“无依赖性周期”规则(NDepend)


10

背景知识:作为团队负责人,我每周大约使用一次NDepend来检查代码的质量。尤其是测试覆盖率,代码行和循环复杂性指标对我来说非常宝贵。但是,当涉及到平均化和依赖周期时,我有点……非常担心。Patrick Smacchia有一篇不错的博客文章,描述了分级的目标。

需要明确的是:在“依赖周期”下,我了解两个命名空间之间的循环引用。

目前,我正在为嵌入式仪器开发基于Windows CE的GUI框架-仅考虑Android图形平台,但针对非常低端的仪器。该框架是具有约50.000行代码的单个程序集(不包括测试)。该框架分为以下名称空间:

  • 核心导航和菜单子系统
  • 屏幕子系统(呈现器/视图/ ...)
  • 控件/小部件层

今天,我花了半天的时间试图将代码提高到适当的水平(由于Resharper总体上没有问题),但是在所有情况下都存在一些依赖周期。

所以我的问题是:您严格遵守“无依赖周期”规则吗?平整真的那么重要吗?


2
如果“没有依赖循环”意味着没有循环引用,那么-没有任何借口。那些是纯粹的邪恶。
2011年

@ollifant:在编写“无依赖周期”时定义您的确切含义。在层之间还是层中的类之间?
Doc Brown

Answers:


9

我最近写了两本在Simple-Talk上发布的有关架构.NET代码的白皮书(第一本书是关于.NET程序集,第二本书是关于命名空间和级别化的):

通过.NET程序集和Visual Studio项目对代码库进行分区

使用命名空间定义.NET组件

平整真的那么重要吗?

是的!

引用第二本白皮书:

如果组件之间的依赖关系图包含一个循环,则该循环中涉及的组件将无法独立开发和测试。因此,成分的循环代表了一个超成分,其熵高于其所包含成分的熵之和。

(...)

只要持续遵守非循环组件约束,代码库就仍然是高度可学习和可维护的。

  • 在传统的建筑结构中,重力强度给低水平的文物施加了压力。这使它们更加稳定:从某种意义上说,它们很难移动,因此“稳定”。
  • 在软件体系结构中,遵循非循环组件的思想给低级组件带来了压力。从某种意义上说,重构它们很痛苦,这使它们更稳定。从经验上讲,与实现相比,抽象很少要进行重构。因此,低级组件主要包含抽象(接口和枚举)是一个好主意,以避免痛苦的重构。

6

我从不允许类或名称空间之间的循环依赖。在C#,Java和C ++中,您总是可以通过引入接口来打破循环类的依赖关系。

测试优先编码使引入循环依赖性变得困难。


4

这始终是一个折衷方案:您必须了解依赖项的成本,以了解为什么要避免依赖项。同样,如果您了解依赖的成本,则可以更好地确定在特定情况下是否值得。

例如,在控制台视频游戏中,我们通常依赖于需要紧密的信息关系的依赖项,主要是出于性能方面的考虑。只要我们不必像编辑工具那样灵活,就可以了。

如果您了解软件必须运行的约束条件(是硬件,操作系统还是仅是设计(例如“我们可以使用的更简单的用户界面”)),那么应该很容易选择理解不应该依赖的系统,而应该依靠好。

但是,如果您没有充分明确的理由,请避免任何依赖。依赖代码是调试会话的地狱。


2

每当讨论此主题时,参与者通常会失去构建时间和运行时间周期之间区别的位置。前者是约翰·拉科斯(John Lakos)所说的“物理设计”,而后者基本上与讨论无关(不要挂在运行时周期上,例如由回调创建的周期)。

这就是说,约翰·拉科斯(John Lakos)在消除所有(构建时间)周期方面非常严格。但是,鲍勃·马丁(Bob Martin)采取的态度是,只有二进制文件(例如DLL,可执行文件)之间的循环才是重要的,应避免使用。他认为阶级之间的周期二进制不是非常重要。

我个人对此持鲍勃·马丁的观点。但是,我确实还是要注意类之间的循环,因为缺少这种循环会使其他人更容易阅读和学习代码。

但是,应该指出的是,使用Visual Studio生成的任何代码都不能在二进制文件之间(无论是本机代码还是托管代码)具有循环依赖关系。因此,最严重的循环问题已为您解决。:)


0

几乎完全是因为在Haskell中构建类型的依赖周期不方便,而在Agda和Coq中则是不可能的,而这些正是我通常使用的语言。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.