紧急需求的设计问题

    技术2024-03-29  13

    紧急设计的困难之一在于找到惯用模式和隐藏在代码中的其他设计元素。 指标和可视化帮助您识别代码的重要部分,使您可以将它们提取为一流的设计元素。 我在本文中关注的两个指标是圈复杂度和传入耦合 。 圈复杂度是一种方法相对于另一种方法的相对复杂度的度量。 传入耦合表示使用当前类的其他类数。 您将学习一些用于可视化和理解这两个指标的工具,以及结合指标如何帮助您揭示设计特征。

    关于本系列

    本系列文章旨在为人们经常讨论但难以捉摸的软件体系结构和设计概念提供新的视角。 通过具体的示例,尼尔·福特为您提供了进化架构和紧急设计的敏捷实践的坚实基础。 通过将重要的架构和设计决策推迟到最后一个负责任的时刻,可以防止不必要的复杂性破坏您的软件项目。

    我在“ 测试驱动的设计,第2部分 ”中介绍了圈复杂性,但其中有些细微之处我没有在此处讨论。 通过Java™工具进行圈复杂度测量的一个复杂因素是工作单元。 循环复杂度是方法级别的度量,但是Java编程中的工作单元是类。 因此,圈复杂度测量通常是一类中所有方法的复杂度之和或平均值。 两种措施都很有趣。

    例如,以下情况是可能的。 假设一个类有一个非常复杂的方法(CC = 40),但也有很多非常小的方法(例如Java代码中常见的get / set方法对)。 有了工具,如JavaNCSS(请参阅相关信息 ),报告这一指标作为所有方法的总和,圈复杂度是整个班级大量。 如果您使用Cobertura之类的工具,该工具将类的平均圈复杂度报告为该类的平均值,则该类看起来不再那么糟糕,因为许多简单方法都在摊销高度复杂的类。 由于这种工作单元不匹配,因此有必要同时考虑环复杂度的总和和均值。 如果单独考虑它们,则噪声会渗入结果。 同时使用两个数字可减轻这种可能性。

    软件指标与物理指标

    在软件中,度量是指将客观测量值应用于显影工件以确定粗粒度特征。 与物理指标(例如仪表棒)不同,大多数软件指标不能反映现实世界中的某些特征。 复杂度为5的圈数没有测量单位; 它不会告诉您代码的任何物理属性。 与其他代码的圈复杂度相比,该数字才有意义。

    设计感兴趣的其他指标是两个耦合数: 传出和传入耦合。 传出耦合度量当前类引用的类数。 通过简单的检查很容易确定:打开相关的类并计算对其他类的引用(在字段和参数中)。 传入耦合更难确定并且更有价值。 它测量使用当前类的其他几个类。 您可以使用命令行fu来确定这一点,也可以使用一些了解此指标的工具之一来确定它。 一种这样的工具是ckjm,用于运行Chidamber&Kemerer面向对象度量套件(见的开源工具相关主题 )。 尽管启动和运行有点复杂,但它既提供了循环复杂性(报告为一类所有方法的循环复杂性的总和),也提供了传出和传入耦合数。

    但是,一旦有了这些数字,它们意味着什么,特别是在设计方面? 作为指标生成的数字提供了有关您的代码的信息的一个单一维度,而原始数字本身通常含义不大。 您可以通过两种方式从指标生成有用的信息。 一种是查看特定值随时间和现货趋势的变化。 或者,您可以组合指标以丰富信息密度,这是我将在本文中向您展示的方法。

    指标和设计

    在本系列的几篇文章中,我一直在折磨Struts代码库-不是因为我对Struts有偏见,而是因为它是一个著名的开源项目。 相信我:您可以从世界上找到的大多数代码中获得无吸引力的设计特征! 从Struts开始,我将继续使用它来说明我的观点。

    ckjm的输出是文本,该文本可转换为XML(以及通过XSLT的各种转换,转换为其他格式)。 图1显示了多个ckjm度量的组合,其中WMC (每个类的加权方法)是该类方法的圈复杂度之和,而Ca是传入耦合:

    图1. ckjm度量结果在一个表中

    图2显示了同一表,按WMC排序:

    图2. ckjm指标,按WMC排序

    仅通过查看此结果,您就可以知道DoubleListUIBean是Struts代码库中最复杂的类。 这表明重构是消除某些复杂性并查看是否可以找到一些抽象的重复模式的理想选择。 但是,WMC编号并不能告诉您是否将投资此类重构为更好的设计是否是对时间的有效利用。 请注意,该类的Ca为3。只有其他三个类使用该类,这表明不值得花费大量时间来改进该类的设计。

    图3显示了相同的ckjm结果,这次按Ca排序:

    图3. ckjm结果,按传入耦合排序

    这种组合视图表明,Struts中使用最多的类是Component (鉴于Struts是Web框架,这并不奇怪)。 尽管Component并不那么复杂,但其他177个类都使用了Component ,这使其成为改进设计的理想之选。 更好地设计Component会对许多其他类产生连锁React。

    WMC和Ca的组合是阅读图3中提供的透视图的最佳方法。 这可以在一个视图中告诉您代码库中重要的部分和复杂的部分。 如果您是在没有任何先验知识的情况下进入此代码库的,则此视图可提供有关您的努力可能产生最佳结果的见解。 尽管它不是万无一失的,但是您现在拥有的有关代码库的更多信息,而不仅仅是从查看大量代码中获得的信息。

    数值指标可以深入了解您的代码,但它们的级别很低,提供有关特定类的信息,但并不能从多角度全面了解代码库。 现在有许多工具可以通过可视化将指标提升到一个新的水平。

    指标可视化

    指标的可视化提供特定维度的替代视图,可以是单个维度,也可以是多个维度的集合。 Smalltalk社区创建了大量的度量可视化(甚至创建了一个名为Moose的平台来启用这些类型的可视化;请参阅参考资料 )。 Smalltalk社区开发的许多度量技术已迁移到Java编程。

    iPlasma和行业标准

    与圈复杂度有关的一些常见问题是“我的代码与其他代码相比如何?” 和“对于一个特定的班级来说,一个好的数字是多少?” 该项目iPlasma回答这些问题(见相关主题 )。 iPlasma是在罗马尼亚作为大学项目创建的平台,用于评估面向对象设计的质量。 它会生成一个金字塔,显示项目的关键指标以及与这些数字的行业标准范围的比较。

    当您运行iPlasma时,您指向一个源代码目录,并且它经过一段时间后产生了一个如图4所示的度量金字塔,它基于Struts 2.0.11代码库:

    图4. iPlasma指标金字塔

    一旦您了解如何阅读,金字塔中便充满了信息。 每行都有一个彩色的百分比; 百分比是通过这一行中的数字与该行中的数字之比得出的。 表1从顶部开始显示数字指示的内容:

    表1.了解iPlasma金字塔
    码 描述 无损检测 直接后代数 击中 继承树的高度 NOP 包裹数量 NOC 班数 NOM 方法数量 LOC 代码行 赛洛 圈复杂度 呼叫 每种方法的调用 FOUT 扇出(给定方法调用的其他方法数)

    数字表示比率。 颜色表示比率符合行业标准范围的位置(来自众多开源项目)。 每个比率可以是绿色(在范围内),蓝色(在范围内)或红色(在范围外)。 对于Struts代码库,NDD和CYCLO超出了这些值的行业标准,而LOC和NOM则低于此标准。 使用的范围显示在表2中:

    表2. iPlasma指标的行业范围
    低 中 高 CYCLO /线 0.16 0.20 0.24 LOC /方法 7 10 13 NOM /班 4 7 10 NOC /包装 6 17 26 呼叫/方法 2.01 2.62 3.20 扇出/通话 0.56 0.62 0.68

    iPlasma还会基于金字塔生成建议,如金字塔正下方的iPlasma显示屏所示。 图5显示了针对Struts的建议:

    图5. iPlasma建议

    iPlasma生成的数字可用于多种用途。 首先,它们使您可以在多个维度上将代码库与其他代码库进行比较。 其次,这些数字表示您可能要花费很多精力来改善代码卫生和设计的地方。 例如,对于Struts,iPlasma表示继承树的深度非常高,并且方法往往过于复杂。 但是,您必须根据上下文理解这些数字。 像Struts这样的Web框架往往会具有相当复杂的层次结构,这意味着NDD编号可能不需要担心。 但是,CC编号与上下文无关,它太高,表示方法级别的设计气味。

    为了便于比较,图6显示了iPlasma金字塔的Vuze的项目,用Java语言(见一个开源的BitTorrent客户端相关主题 ):

    图6. Vuze的iPlasma金字塔

    Vuze是一个大型项目(超过500,000行代码),在继承树的深度,每个类中的方法数量,每个方法的代码行数量以及每个方法的调用数量方面存在潜在的设计问题。

    依存关系

    紧急设计需要查看代码中的关系和其他高级抽象。 试图从源代码中看到这些高级概念,让人想起蒙住眼睛的人的形象,他们试图通过触摸来理解大象。 大象的每个部分看起来都像其他东西,但是触摸太局限了,无法整体查看。

    确定类和对象之间的依赖关系会遇到相同类型的本地化问题。 诸如iPlasma之类的工具可让您查看代码总体特征的摘要,但不会告诉您要调查的特定站点。 幸运的是,其他工具可以帮助您从几种不同的角度看到大象。

    Smalltalk的社区创建一个名为CodeCrawler(参见工具相关信息 ),基于麋平台,其示出的代码的图形表示,其尺寸为类的大小,方法的长度,以及一些其它度量上。 可以使CodeCrawler与Java代码一起使用,但这令人生畏。 幸运的是,您不必进行任何战斗,因为X-Ray项目已经拥有了(请参阅参考资料 )。

    X-Ray是一个Eclipse插件,可以产生一些可视化效果,以帮助您查看代码的整体结构,包括类之间的依赖关系的饼图,如图7中Struts所示:

    图7.类依赖关系的X射线可视化

    圆边上的每个元素都是一个类,线条表示这些类之间的依赖关系。 该行的粗体表示依赖性的强度。 单击该类将显示有关该类的信息,然后双击该类将在Eclipse编辑器中打开该类。 当然,此视图包含太多有用信息。 幸运的是,您可以放大以查看各行。 粗线表示类之间的强依赖关系(有效耦合),这可能表示当两个类之间的联系过于紧密时存在设计缺陷。

    X-Ray还包​​括一个类似的软件包依赖关系视图,如图8所示:

    图8.软件包依赖关系的X-射线视图

    整体结构

    另一个X射线视图也显示了有用的代码可视化效果,同样基于CodeCrawler。 系统复杂性视图将您的代码库显示为图形,其中继承层次结构以自上而下的树状视图显示,框的大小指示类中代码的行数,框的宽度指示方法。 图9显示了系统复杂性的可视化:

    图9. X射线系统复杂性视图

    此视图还以粉红色线显示呼出电话(有效耦合),以红色线显示呼入呼叫(afferent耦合)。 与之前的可视化效果一样,单击其中一个框将带您进入Eclipse中的类。 您的代码视图提供了独特的视角,很难通过查看代码来实现。 如果您可以沿着特定的维度快速进行过滤,缩小代码部分的范围,则应该更轻松地发现围绕特定方面的设计缺陷。

    摘要

    X-Ray和iPlasma仅表示可用于Java代码的一小部分可视化类型。 明智地使用它们可以使您Swift将精力集中在隐藏在项目代码沼泽中的设计方面。 查找惯用模式是紧急设计的关键推动力之一,而易于查看模式(好的和坏的)的工具大大减少了调查工作,从而为重构代码留下了更多的时间来使其更好。


    翻译自: https://www.ibm.com/developerworks/java/library/j-eaed6/index.html

    Processed: 0.010, SQL: 8