如何提高功能的可维护性

时间:2010-02-12 05:35:00

标签: language-agnostic parameters

我将在此扩展我对When a method has too many parameters?所做的评论,其中OP与其他人的函数有轻微问题,其中有97个参数。

我非常相信编写可维护的代码(编写通常比阅读更容易,因此Steve McConnell(赞美他的名字)的短语“只写代码”)。

由于统计数据显示大多数车祸发生在路口并且我的经验(ymmv)显示大多数“异常”发生在接口处,我会列出一些我要做的事情以试图避免接口上的误解并邀请您的评论如果我我错了。

但是,更重要的是,我邀请你提出更具预防性的建议(看,毕竟还有一个问题 - 如何改进?)。

  • 以(最新)DoxyGen格式的形式提供足够的文件,描述每个参数的性质和海豚。
  • 绝对 NO 以全局变量作为隐藏参数的后门恶作剧。
  • 尝试将参数限制为六或八。如果更多,则将相关参数作为结构传递;如果它们不相关则重新考虑该功能。如果需要这么多信息,维护是否过于复杂?它可以分解成几个较小的函数吗?
  • 尽可能经常使用CONST。
  • 一种编码标准,表示输入参数首先出现,然后仅输出,最后输入/输出,由函数修改。
  • 我还#define一些空的宏来使声明更容易阅读:

    #定义INPUT
    #定义OUTPUT
    #定义MODIFY
    bool DoSomething(INPUT int howOften,MODIFY Wdiget * myWidget,OUTPUT WidgetPtr * const nextWidget)

只是一些想法。我怎样才能改进这些?感谢。

4 个答案:

答案 0 :(得分:4)

按顺序解决您的要点:

  1. 精心设计的类型通常会使Doxygen格式注释浪费时间。
  2. 虽然如上所述(“shenanigans”的定义很糟糕),但并非所有人都使用全局变量就像许多人所暗示的那样糟糕。如果你必须在真正使用之前传递一个参数超过四次,那么全局性很可能不会出错。
  3. 八个甚至六个参数通常过多。任何超过两三个开始表示该函数不止一件事。一个明显的例外是一个构造函数,它将许多其他项聚合到一个对象中(例如一个地址对象,它将街道名称,数字,城市,国家,邮政编码等作为输入)。
  4. 更好地称为“写const-correct代码。”
  5. 鉴于C ++的默认参数功能,通常最好按可能性的升序排序以使用默认值。
  6. 别。只是不要!如果什么是输入和输出是什么并不明显,那么这几乎可以证明基本设计存在致命缺陷。
  7. 至于我认为实际上很好的想法:

    1. 正如第一点所暗示的,专注于类型。一旦你做对了,大多数其他问题就会消失。
    2. 使用一些(甚至只有一个)中心主题。对于Lisp,一切都是列表。对于Unix,一切都是文件(文件都是简单的字节流)。模仿这种简单。
    3. 编辑:回复评论:

      1. 虽然你确实有一些观点,但我的经验仍然表明使用Doxygen(以及类似的javadoc)生成的文档几乎普遍没用。从理论上讲,该工具并不能阻止正常的文档,但实际上它最多也是罕见的。
      2. Globals肯定会引起问题 - 但是我已经足够大了,在它提供了很多替代方案之前就已经使用了Fortran,并且在某种程度上它确实没有像许多人所暗示的那么糟糕。许多故事似乎至少是第三手,每次重新讲述时都会添加一些额外的“香料”。我看过一个故事听起来很像我几十年前左右讲过的一个夸张的版本......
      3. 嗯...... Markdown格式化似乎不赞成我的跳过数字。
      4. 再次......
      5. 我的评论特定于C ++,但是很多其他语言也支持默认参数和/或重载,它也适用于大多数语言。即使没有它,像f(param1, param2, 0,0,0);这样的调用也很容易被视为具有默认参数。在某种程度上,按使用顺序排序很方便,但是当您执行订单时,您选择的顺序几乎与简单一致无关紧要。
      6. 是的,void *参数对您没有多大帮助 - 但MODIFY void *稍微好一些。 const的实际类型和一致使用提供了更多信息,并由编译器进行检查。其他语言可能没有/使用const,但它们可能也没有宏。 OTOH,有些人直接支持你想要的东西 - 例如,Ada有inoutinout说明符。

答案 1 :(得分:2)

我不确定我们是否会就此达成一致意见,每个人都会提出不同的想法(彼此视角的好坏)。话虽如此,我发现 Code Complete 是我遇到这类问题的好地方。

答案 2 :(得分:1)

我的一个很大的痛苦是控制功能之间的耦合。 (控制耦合是指一个模块控制另一个模块的执行流程,通过传递标志告诉被调用函数该做什么。)

例如(从我刚刚处理的代码中剪切和粘贴):

void UartEnable(bool enable, int baud);

而不是:

void UartEnable(int baud);
void UartDisable(void);

换句话说 - 参数用于传递“数据”,而不是“控制”。

答案 3 :(得分:0)

我会使用鲍勃叔叔在他的“清洁代码”一书中提出的“规则”。

这些我认为我记得的那些:

  • 2个参数正常,3个不好,更需要重构
  • 评论是不好名字的标志。所以应该没有,并且函数和参数的目的应该从名称
  • 中清楚
  • 简化方法。目标是低于10行代码。