7

我经常(在研究环境中)编写一次性代码——例如探索科学属性或过程的算法或模型。许多这些“实验”是一次性的,但有时我发现我需要稍后再使用一些。例如,我刚刚发现了 7 年前编写的字符串匹配代码(由于其他优先事项而停止),但现在对于同事的项目很有价值。看过之后(我真的写了这么难以理解的代码吗?)我意识到当我重新启动“项目”时,我可以做一些事情来帮助我(“实验”仍然是一个更好的词)。早期的实验“奏效了”,但我知道当时我没有时间重构,因为我的优先事项放在其他地方。

哪些方法在使此类工作能够被挖掘和重复使用方面具有成本效益?

编辑:我已经回答了我自己的问题(如下),因为存在超出实际来源本身的问题。

4

10 回答 10

9

我不同意所有“写评论”的答案。这是作为无法理解的代码本身的全部内容而提供的。

为自己获取一份Code Complete(Steve McConnell,第 2 版)的副本。如果你一开始就学会了编写可维护代码的技巧,就不会花费你更多的时间,而且你以后可以更轻松地回到你的工作中。

你更喜欢哪个:

  • 带有注释的神秘代码?
  • 大多数情况下没有代码?

我更喜欢后者,因为在未注释神秘代码的情况下,OK 代码更容易理解,而注释是原始开发人员可能犯错误的另一个地方。代码可能有问题,但永远不会出错

一旦您对Code Complete感到满意,我会推荐The Pragmatic Programmer,因为它提供了更高级别的软件开发建议。

于 2009-09-03T15:26:24.380 回答
5

[回答自己的问题] 这个问题还有其他几个方面尚未提出,我在重新审视它时会发现这些方面很有用。其中一些可能是“不言而喻的”,但请记住此代码是 SVN 和 IDE 之前的代码。

  • 可发现性。实际上很难找到代码。我相信它在我的 SourceForge 项目中,但是 7 年来有太多的版本和分支,我找不到它。所以我必须有一个搜索代码的系统,在 IDE 出现之前我认为没有。
  • 它有什么作用?. 当前的 checkout 包含大约 13 个类(全部在一个包中,因为当时不容易重构)。有些是透明的(DynamicAligner),但有些是不透明的(MainBox,因为它扩展了一个 Swing Box 而得名)。发行版中有四个main()程序,实际上大约有 3 个子项目。因此,拥有一个关于组件实际是什么的外部清单至关重要。
  • 如何运行它的说明。运行程序时,main()会提供一个简短的命令行用法(例如DynamicAligner file1 file2),但不会说明文件内容的实际样子。我当时当然知道这一点,但现在不知道。所以在同级目录中应该有关联的示例文件。这些比尝试记录文件格式更有价值。
  • 它仍然有效吗?. 应该可以不假思索地运行每个示例。第一个问题是相关的库、运行时等是否仍然相关且可用。一位前同事编写了一个系统,该系统只运行特定版本的 Python。唯一的答案是重写。因此,我们当然应该尽可能避免任何锁定,我已经训练自己(尽管不一定是同事)这样做。

那么我和同事如何才能避免将来出现问题呢?我认为第一步是在创建代码时应该有一个创建“项目”(无论多么小)的纪律,并且这些项目应该受到版本控制。这对你们中的一些人来说可能听起来很明显,但在某些环境(学术界、国内)中,建立项目管理系统会产生很大的开销。我怀疑大多数学术代码不受任何版本控制。

然后是如何组织项目的问题。默认情况下,它们不能在 Sourceforge 上,因为代码 (a) 微不足道,并且 (b) 默认情况下不打开。我们需要一个服务器,其中可以有公共项目和私人项目。我会计算出设置和运行它的工作量约为 0.1 FTE - 即各方一年 20 天(安装、培训、维护) - 如果有更简单的选项我想知道,因为这是一个大某些情况下的费用——我是花时间设置服务器还是写论文?

该项目应尽量鼓励良好的纪律。这确实是我希望从这个问题中得到的。它可能包括:

  1. 所需组件的模板(清单、自述文件、提交日志、示例、所需库等。并非所有项目都可以在 maven 下运行 - 例如 FORTRAN)。
  2. 一种在大量(至少数百个)小项目中搜索助记符字符串的方法(我喜欢将代码转储到 Googledocs 中的想法,这可能是一个富有成效的途径 - 但它需要额外的维护工作)。
  3. 明确的命名约定。这些比评论更有价值。我现在经常拥有 iterateOverAllXAndDoY 类型的名称。当例程实际创建信息时,我尝试使用 createX() 而不是 getX()。我有调用例程 process() 而不是 convertAllBToY() 的坏习惯。

我知道但没有使用过 GIT 和 Mercurial 和 GoogleCode。我不知道这些需要付出多少努力,以及他们回答了多少我的担忧。如果有一个 IDE 插件可以帮助创建更好的代码(例如“方法名称选择不当”),我会很高兴。

不管他们有什么方法自然而然地出现在那些不自然地有良好的代码纪律并且值得付出努力的人身上。

于 2009-09-04T09:07:06.903 回答
2

正如您在一篇文章中的出色回答所表明的那样,并且根据我自己的经验,用于研究的软件和已设计的软件之间存在难以跨越的差距。在我看来,Code Complete 可能会有所帮助,但作用不大。作为一个经济问题,与偶尔为某事找到以后的用途而获得奖励相比,重构所有内容以供重用是否值得?您的平衡点可能会有所不同。

这是存储片段的实用技巧。而不是全面的评论,抛出一些关键字:

  • “图同构包装器”
  • “聚合物模拟退火”
  • “字符串匹配费曼”
  • “平衡”

然后将代码放在 Google 可搜索的位置,例如 GMail 帐户。

编辑: 我可能会补充一点,免费的 Google 站点确实是可搜索的 wiki,它们是放置代码的好地方,无论是附件形式还是粘贴形式。

另外,我应该说我是 Code Complete 的粉丝,并且多年来一直给研究生编写科学研究软件的副本。这是一个好的开始,但没有灵丹妙药。我现在正在写一篇关于使用开源框架解决科学数据管理问题的论文,其中一个结论是,一些软件工程专业知识对于长期运行的系统是必不可少的。许多科学项目可能应该从一开始就为此进行预算。

于 2009-09-03T15:40:29.383 回答
1

不,不,不,不,不,不!

即使在研究环境中也不要编写一次性代码。请!

目前我正在搞乱这样一个“一次性代码”,即 BLAST 项目。问题是它开始是一个游乐场,但后来碰巧变得有些成功,现在它是一个实现了许多概念的简洁工具,但代码几乎无法维护。但这不是重点。

重点是,您为工程师进行研究,以便以后从您的发现中受益。在完成了关于一般概念的良好科学工作并编写了一个证明这一点成功的工具之后,您很容易忘记您这样做并不是为了发表文章和获得博士学位。你这样做是为了人类的利益。您的代码可能包含一堆难以调试的“特殊情况”、一组不适合任何会议文章的怪癖和技巧。在整个代码中记录和注释此类内容尤其重要。

如果开发人员决定在商业产品中实现您的概念,他可能已经研究了您代码中的怪癖和黑客行为,并且实现的错误将比它可能有的少十个。每个人都说“哇,他对A的研究真的很有用!” 但是如果你写“一次性”,他们会说“他的概念在纸上看起来不错,但 X 试图实现它并淹没在一堆错误中”。

编辑:取自下面的评论)为了帮助您的代码库的未来开发人员,您不需要太多。首先,注释每个函数的作用。其次,确保对棘手错误的每个非显而易见的修复都放在修订控制系统中的单独提交中(当然,带有适当的注释)。这已经足够了。而且,如果您甚至将事物模块化(即使它们还没有准备好进行彻底重用——根据布鲁克斯的说法,这将是成本的三倍),您将受到实施您研究的工程师的喜爱。

我认为,如果研究人员抛开他们的狂妄自大,不再傲慢地认为他们不是这些肮脏的编码员,只是为了写出好代码而做着卑微的工作,那么世界将会变得更美好。编写好的代码不仅仅是这些愚蠢的程序员的工作。这是每个人都应该努力的真正有价值的事情。没有这个,你的实验场,你的代码,你的创意就会死掉。

于 2009-09-03T16:02:36.443 回答
1

我可能错过了整个讨论的重点,我经常这样做,但是这里是邀请砖块和投票的...

如果是一次性代码,就把它扔掉!

如果您不想扔掉它,请遵循上面的好建议。对我来说,我写了大量的一次性代码,它是被丢弃还是进入可重用状态并以防万一的问题归结为经济学。

我能预见到这段代码将再次有用的情况吗?千载难逢,一年两次,每月一次?

我是否能够在比使其可重用所需的时间更短的时间内重写此代码?如果这个问题的答案是否定的,那么我必须重复使用多少次才能使其在增强它的同时变得有价值?(回到上一个问题。)

如果我确实让这段代码可重用,我下次想要它时还能再次找到它吗?(任何人都有过这样的经历,绝对肯定地知道,在您的代码存储库中的某个地方只有您想要的片段,但不知道它被称为什么,也不知道在哪里查找或 grep 用于什么?)

最后,让快速编写的代码可重用的 3 步方法。在您喜欢的任何这些步骤之后停止:

1)将代码记录为黑盒。输入、输出、操作。仔细归档此文件。

2)编写有关如何构建/解释/安装代码的说明,以防您必须移植它。仔细归档这些说明。

3)只有在值得努力的情况下——提高源代码质量,使代码在未来可维护。确保源在源控制系统中并且可以找到。

问候

标记

于 2009-09-04T10:18:20.647 回答
1

我认为最重要的事情(如果你不重构它就不会发生)是评论并记录你当时的思考过程。它将有助于使代码不那么难以理解,并帮助您在需要时找到好的部分。

于 2009-09-03T15:08:03.953 回答
1

评论 - 描述您的想法以及您选择以某种方式实施某事的原因,包括您考虑过的替代方案。可能有各种奇特的解决方案,但在您编写代码时正确地注释您的代码似乎效果最好。

于 2009-09-03T15:09:12.737 回答
1

我会回应其他人所说的,就评论为什么编写代码及其预期用途的“原因”,但我也会添加以下内容:

就好像您打算将其投入生产一样进行编码,即使您只是在胡闹。代码:

  • 清晰度和可读性
  • 遵循当时的编码约定。(命名约定等)。即使这些约定会随着时间而改变,但如果您坚持这些标准,您以后更有可能能够理解它。
  • 安全性(如果适用)
  • 性能(如适用)

特别是,我会强调第一点,但其他点也很重要。我发现如果我稍后使用“测试代码”,我倾向于只在它有效的情况下使用它,而不是重构它。

于 2009-09-03T15:26:57.360 回答
0

您还可以从 TDD(测试驱动开发)人员那里借用单元测试的想法。您需要确保一次性代码无论如何都可以正常工作,那么为什么不将检查链接表达为一个小单元测试呢?这将有两个优点:

  1. 阅读测试代码非常清楚地传达了一次性的意图:毕竟它用同一种语言表达了它的期望:代码。

  2. 它也有助于解决您自我回答的第四个问题:“它仍然有效吗?”。好吧,这很简单:只需运行单元测试,它们就会告诉你什么和在哪里(运气好的话)为什么(它)不起作用。

于 2009-09-04T09:22:18.387 回答
0

一些策略:

  1. 好评论。很难重用您以后找不到或无法理解的内容。
  2. 将每个查询保存到已备份或受源代码控制的文件夹中。
  3. 拥有一个通用的有用函数库,一旦它被重用,你就可以“提升”它。
于 2009-09-03T15:07:42.783 回答