【问题标题】:Good strategies for developing throwaway code?开发一次性代码的好策略?
【发布时间】:2010-11-25 07:55:06
【问题描述】:

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

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

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

【问题讨论】:

    标签: reusability throwaway


    【解决方案1】:

    不,不,不,不,不!

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

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

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

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

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

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

    【讨论】:

    • @Pavel Shved。我同情你的cmets。但我将捍卫一次性代码的概念——我所说的那个来自一个基于 Kruskal 的书的序列比对项目,我在大约 20 年前为学生设置了这个项目——我认为在 BBC Basic 中——它已经从那个 toC 迁移到 C++然后到 Java,现在我用它来对齐文本。在任何阶段,它都只是一个学习练习和一个游乐场。所以我对它的演变和状态不承担任何道德责任。但现在我认为它在不同的领域有一些附加价值,所以我正在重构它。
    • @peter:没有人强迫你负责。写好代码是一个好习惯,真的不需要很多时间去实践!对函数作用的微小描述,模块用途的 cmets,向我展示 为什么 存在特定行的修订控制系统 (svn blame)。这只会让人们重复使用你的作品,从而给你一个荣誉和归属。
    • @Pavel。谢谢。 因为我希望以负责任的方式行事,我才提出这个问题。编写原始代码时的 FWIW SVN 不存在 :-) 并且我们拥有的原始 CVS 系统没有得到维护。
    • @peter:好吧,你明白我的意思。注释每个函数的作用。并确保 每个 非显而易见的行(由修复一个棘手的错误引起)具有适当的注释并放置在单独的提交中。我可以向你保证——这足以让你得到追随者的称赞。而且,如果您甚至将事物模块化(即使它们还没有准备好直接重复使用——根据 Brooks 的说法,成本会高出三倍),您将受到工程师的喜爱。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      这是存储 sn-ps 的实用技巧。代替成熟的 cmets,输入一些关键字:

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

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

      编辑:我可以补充一点,免费的 Google 协作平台是真正可搜索的 wiki,是放置代码的好地方,无论是附件形式还是粘贴形式。

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

      【讨论】:

      • +1 这是个好主意。如果代码很容易搜索(与我发现无法搜索的 Sourceforge 不同)它会有所帮助
      • 好建议,但是每一个这样的sn-p都应该在项目中的显眼位置定义。对于参与该项目的人来说,它们是显而易见的,但对于外来者来说,它们完全不是。
      【解决方案4】:

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

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

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

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

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

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

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

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

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

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

      问候

      标记

      【讨论】:

      • 非常正确,归根结底,一次性代码和未完成代码之间存在区别。根据定义,丢弃物并不复杂到想要或需要保留,因此可以很容易地在更开明的时代重新生成。一次性代码是廉价龙舌兰酒。另一方面,未完成的代码真的需要好好照顾:包裹在(注释的)棉绒中,在黑暗的地方保持恒定温度,定期转动,并以柔和的声音朗读“掌握正则表达式”睡前。
      【解决方案5】:

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

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

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

      【讨论】:

      • 谢谢。我确实为此目的使用单元测试。这种类型的测试通常是“没有崩溃就结束了”。很难检查 - 例如 - 带有浮点数的复杂输出是否仍然正确。
      • @peter.murray.rust:您可以使用愚蠢的参数来检查它:例如当所有参数都为 0 时,大多数微分方程都有一个已知的输出。确保代码至少正确地做到了这一点。充分模块化一切,您可以对大部分代码进行基本的健全性测试..
      【解决方案6】:

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

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

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

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

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

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

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

      对于那些不具备良好代码纪律并且值得付出努力的人来说,他们必须自然而然地采用任何方法。

      【讨论】:

      • Peter,我完全同意您关于命名约定的建议。恕我直言,明确的名称是迄今为止通过代码传达您的意图最有效的方法。我们有一个指导方针:至少要花两倍的时间来想出一个好名字。
      • Git 或 Mercurial 至少可以在一定程度上帮助解决发现和维护工作方面的问题。如果您对可以识别您正在寻找的东西的字符串有一些想法,Git 的“grep”和“pickaxe”操作可能会有所帮助。至于保持存储库,如果您可以移动一些文件(通过任何方式),您可以分发代码及其所有历史记录。
      • 另外,你真的应该把它编辑到问题中,因为它澄清了,而不是回应你上面的错误。
      【解决方案7】:

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

      即使您只是在胡闹,也可以像计划将其投入生产一样编写代码。代码:

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

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

      【讨论】:

        【解决方案8】:

        我不同意“写 cmets”的所有答案。这是作为一个包罗万象的代码本身无法理解的。

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

        你更喜欢哪个:

        • 带有 cmets 的密码?
        • 大部分没有的代码都OK?

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

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

        【讨论】:

        • 是的,编写可维护的代码非常重要,我当然会赞同阅读 Code Complete 的建议(我还没有阅读 The Pragmatic Programmer)。但是,我仍然认为重要的是要评论您做出这些决定的原因。比如你为什么选择某种排序算法而不是其他算法(也许你期望数据已经部分排序,或者它不会超过 X 条记录)。评论可以清除很多“我到底在想什么?”稍后再提问。
        • 如果 cmets 可以直接与代码相矛盾,强烈考虑删除它们。在几乎所有情况下,cmets 只有在提供您通过阅读代码无法轻松获得的信息时才有用。
        • @Novelocrat 我同意。评论不是主要问题或解决方案。我将很快更详细地发布我的特定问题,但我仍然对一般经验感兴趣。 (由于 SO,我现在订购了 CC 并开始涉足它,并且肯定会采用任何接近零成本的方法。像你一样,我更喜欢大部分 OK 代码(这是),我不担心艰难的算法未注释 - 它们有效,我给了一个指向通用源的指针。
        • 作为我上面所写内容的一个很晚的推论:使用版本控制系统(我推荐使用 Git 或 Mercurial)虔诚地。像对待实验室笔记本一样对待提交消息 - 关键注释,以确保所描述的工作是可归因的和可重现的。我经常发现这些日志的内容比内嵌 cmets 提供更多信息,因为它们提供了更丰富的上下文来理解它们。
        【解决方案9】:

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

        【讨论】:

          【解决方案10】:

          一些策略:

          1. 好方法。以后找不到或无法理解的东西很难重复使用。
          2. 将每个查询保存到已备份或受源代码管理的文件夹中。
          3. 拥有一个通用的有用函数库,一旦重复使用,您可以将其“提升”到。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-14
            • 1970-01-01
            • 2010-10-31
            • 2014-07-03
            • 2022-12-03
            相关资源
            最近更新 更多