您如何将程序从开发中过渡到发布?


67

在某个时候,正在开发一个程序。一直在添加,删除或更改功能。每个版本都不过是一个原型。因此,此时我不会在编写超级干净的代码上浪费太多时间,因为我永远不知道事情持续多长时间。当然,我尝试将代码质量保持在某些标准上,但是时间始终是一个问题。

然后是程序完成的时刻,决策者说“就是这样”。此时我确实有一个可以正常工作的原型,但是在开发阶段,所有来回的代码都有些混乱。我应该开始测试/最终调试,但是我的直觉告诉我,现在应该以某种方式清理和/或重写内容,以提供使其易于维护等的适当体系结构。

一旦对材料进行了测试和批准,则没有必要进行重写。我经常站在那儿,工作着一个“完成的”原型,在测试过程中发现一个错误,我发现这是整个开发过程中非智能编码的结果。我正在测试中,错误修正将是一个重写……真是一团糟!

我敢肯定,有更好的/教科书方式。但是我必须在一个真正的工作环境中工作,而不是一切都是教科书。

那么,如何将工作原型转换为具有稳定代码库的发行版本?也许我不应该认为开发一旦完成就将其视为清理阶段……我不知道,我需要帮助。

编辑

我想澄清一些事情。

  • 我100%愿意在此之前和之后都这样做,代码清晰易读。但是我也必须把事情做好,并且不能梦想代码干净整洁的美丽。我必须找到一个折衷方案。

  • 通常,一项新功能实际上只是我们要尝试的东西,看看实现这样的事情是否有意义。(尤其是在移动应用中,是为了在实际设备上获得真实的外观)。因此(imho)在第一次“让我们看看”迭代中并不能证明过多的工作是不小的。但是有时会出现问题,我何时支付此技术债务?这就是这个问题的全部内容。

如果我知道一半的功能将在一天后被删除(到现在为止我们公司已有足够的经验),我真的很难相信解决我的问题的最佳方法是仍然投入额外的时间来编写所有干净的东西,即使大部分将在不久后删除。对我来说,如果事情一发不可收拾,我进行一次大的清理,我会节省时间,因此是我的问题。


68
您的问题是“我把自己挖了一个洞;我如何出去?” 当然,标准答案是第一步,请停止挖掘。您的开发过程可以概括为“产生大量技术债务,然后在到期时将其忽略”。如果这是一个问题,请更改您的开发流程。仅检入符合其精心编写的规范的干净,可用,调试且经过仔细检查的代码。不要陷入债务,也不必摆脱债务。
埃里克·利珀特

11
@NikkyD如果没有足够的时间进行适当的实施,则需要与您的经理进行一次对话,以讨论对软件质量的影响。了解每个人在告诉您的内容:不花时间在前面会损害您以后高效工作的能力。您要提出的另一个问题是:如果您要离开公司(或“坐公交车奔跑”),对于新开发人员来说,熟悉代码会非常昂贵。他们认为自己现在节省的钱以后会花掉他们。
jpmc26,2013年

32
如果您要创建一个小的功能分支来模拟功能的建议用户界面,那就太好了。使它尽可能快又脏,将其显示给客户端,然后删除该分支。当汽车制造商用黏土和纸张制造汽车来模拟新设计时,他们就不会尝试在黏土模型中安装引擎。确定功能是否值得做的过程应该很便宜。一旦决定使用该功能,请确保您干净的代码开始并且始终生成干净的代码,因为该代码现在是生产代码
埃里克·利珀特

10
“不能梦想代码干净整洁的美”这是对“干净代码”含义的根本误解。干净的代码并不意味着您花了一个下午使标签对齐,以便可以打印代码并对其进行构图。干净的代码好的代码,好的代码干净的代码。干净的代码是可以正常运行,可以调试并且可以理解的代码。如果您从一开始就没有时间编写干净的代码,那么您肯定没有时间编写凌乱的代码,以后再进行修复。那就是任务需要多长时间。
GrandOpener

8
“我还必须把事情做好,并且不能梦想所有干净整洁的代码之美。我必须找到一个折衷方案。” 妥协意味着双方都“足够好”的中间立场。如果您的代码杂乱无章-尤其是如果您的代码杂乱无章,以至于您认为很难维护它-那么那还不够“好”,您需要找到一个更好的折衷方案。
anaximander

Answers:


98

因此,此时我不会在编写超级干净的代码上浪费太多时间,因为我永远不知道事情持续多长时间。

不知道某物能持续多久绝不能成为草率的借口-恰恰相反。最干净的代码是恕我直言,当您必须进行某些更改时,它不会妨碍您。因此,我的建议是:始终尝试编写最干净的代码- 尤其是在编写原型时。因为当必须更改某些内容时(肯定会发生),适应它会容易得多。

不要误会我的意思-我对“最干净的代码”的理解与为了美观而使代码漂亮无关。这确实会使您放慢脚步。在我看来,干净的代码是易于解释的代码(无需编写过多的文档-可以提高速度),易于理解(错误更少,调试所需的时间更少-加速,找到正确代码所需的时间更少)更改的地方-加速),以最少的必要代码量解决给定的问题(调试的代码更少-明显的加速),是DRY(必须更改的地方只有一个可以更改的地方-加速-引入风险较小)通过忘记更改第二位来解决新错误),遵循编码标准(无需考虑繁琐的事情-加快速度),使用较小的代码,

我应该开始测试/最终调试,但是我的直觉告诉我,现在应该以某种方式清理和/或重写内容,以提供使其易于维护等的适当体系结构

此后再执行“清理”是行不通的。实施新功能之前或开始实施新功能时,请考虑进行清理,但此后不进行清理。例如,每当您开始触摸某个功能的方法时,如果发现它的长度超过10行,请考虑将其重构为更小的方法- 立即完成功能。每当您检测到现有的变量或函数名称时,您都不完全知道其含义,请找出它的用途并执行其他操作之前重命名该名称。如果定期执行此操作,则至少应将代码保持在“足够干净”的状态。而且您开始节省时间 -因为您需要更少的调试时间。

我正在测试中,错误修复将是一个重写

……这就是我上面写的实际证明:“肮脏”会在您开始调试代码时立即困扰您,并使您变慢。

如果立即进行清理,几乎可以完全避免这种情况。然后,错误修复将在大多数情况下意味着对代码进行小的更改,而从不对架构进行重大更改。如果您在测试过程中确实发现了架构改进的证据,请将其延迟,放入问题跟踪系统中,然后在下次必须实施从该更改中受益的功能(开始使用该功能之前)时实施。

当然,这需要一些纪律和一些编码经验。这与“测试驱动的开发”背后的想法类似,它是事前做而不是事后做(TDD也可以提供帮助,但是即使您不使用TDD,我写的内容也能奏效)。因此,执行此操作时,在释放之前不需要任何特殊的“清理阶段”。


40
@NikkyD Doc Brown提出的建议是习惯,这些习惯实际上会减少花费的时间,从长远来看非常现实。想一想如果您不需要检查代码来确定如何在每次更改密码时不破坏它,可以节省多少时间。收益类似于从“狩猎和啄食”打字到学习触摸打字的转变。当您开始学习时,最初可能会花费更长的时间,但是一旦养成了习惯,无可否认,它会变得更好,并将在您的整个职业生涯中受益。如果您选择不尝试,您将永远无法到达那里。
丹尼尔(Daniel)

44
@NikkyD:它不会肿时间表。时间表已经肿;当您编写软件并陷入预算外的技术债务时,您只是没有考虑到膨胀。
埃里克·利珀特

7
@NikkyD:我向您介绍带有粘土脚偶像技术债务的概念。前者意味着您可以在不稳定的基础上构建声音软件,后者意味着您在结构不健全时尝试使用的功能所经历的“兴趣”(增加的成本)。
Matthieu M.

10
@NikkyD:不,我建议编写类似于台球专家打球的代码:对于局外人来说,每发球看起来都很简单,因为在发球后,球会停下来进行新的“简单发球”。而且在台球或编码中,这需要几年的练习时间;-)
Doc Brown Doc

16
@NikkyD:根据我的经验,当“添加一个小功能需要大量重构”时,代码已经一团糟,而“大量重构”的需求则来自于您需要更改所执行的函数或类的事实。过去没有保持足够的清洁。不要让事情变得如此遥远。但是,如果您处在这种情况下,请妥协。至少要遵循“ boyscout规则”,并将代码留在比添加功能之前更好的状态。因此,即使下周删除了该功能,代码的形式也应该比以前更好。
布朗

22

您有两个单独的问题,都具有相同的症状(草率的代码):

问题1:需求控制不足 我并不是说您的利益相关者经常更改您的需求,而是意味着您允许在错误修正/测试周期内更改需求。甚至敏捷方法也不支持这一点。构建,测试,交付,注入新需求。

问题2:您认为所写的内容是“暂时的”, 在软件开发中,“暂时的”代码确实非常罕见。您已经注意到自己,一旦满足用户需求,严格的供求关系就很难证明回溯并重新实现“完成”功能。那么,该怎么办呢?始终编​​写生产代码。从功能上来说,这意味着您对利益相关者的估算必须要大得多,这样您才有时间做正确的事情。

另外,请理解您在开发人员方面处于最困难的位置: 阅读Joel Spolsky对内部开发人员的看法。因此,如果您想保持自己的理智,就必须格外警惕。


21

这是一个普遍的问题-尤其是在设计本质上像软件 试用版气球时。

有许多方法可以提供帮助。首先,TDD方法可以帮助将代码库减少为严格要求的代码库。如果您的测试与代码并驾齐驱,那么您至少可以放心代码的行为。

花点时间重构。一旦有了原型并且客户非常渴望获得原型,很难说要花些时间(向他们完成)完成。我喜欢每天检查一次,然后进行重构检查,但是YMMV。

经常需要快速编写代码的开发人员-我们上一个部门有这样的开发人员。每个团队都希望他,因为他工作非常快。然而,一旦到了测试和发布他的代码的时间,车轮很快就脱落了。硬编码的东西,黑客和快捷方式无处不在。他的股票很快下跌了很多。

从一开始就削减生产代码似乎很麻烦,但是根据您的环境,有很多工具可以使开发变得毫无用处,例如GhostdocStylecop

从一开始就值得掌握正确的发展思路。令人惊讶的是,有许多原本只是权宜之计的后端分组系统成为了基础应用。


您的意思是曾经写过的每个止损解决方案,对不对?
RubberDuck

4
关于为客户辩护的重点。我与那些认为在完成GUI后也完成应用程序的客户方面有丰富的经验。我学会了在后台代码尚未准备就绪时使GUI看起来不完整,因此,只有在代码(和业务逻辑)准备就绪时,才使客户看到的内容看起来更加优美。很难解释说,向客户展示的成品仍然需要一两个月才能真正交付。
a安

11

不断地

开发速度是编写简洁,可读和可测试代码的主要原因。它不是为了美,也不是为了其他抽象价值。为什么我要否认自己,只在以后为将来的程序员做呢?

当然,可能会有一些变化,这些变化大多是表面上的,因此不是必需的;我认为,现在在开发过程中拥有适度不错的代码比现在乱成一团,希望以后再完善它要有用得多(让我们面对现实,即使您已经拥有了它,也永远不会发生)时间)。


6
从个人角度来看,我认为+1太困难了,因为在家中侵入个人项目并在日常工作中编写生产代码非常困难。在我的业余项目中编写专业代码会立即带来好处-代码更易于阅读,错误更少。
罗比·迪

永远不会发生的原因之一是,随着时间的推移,您(更好)会做得更好。因此,如果您等待半年来“清理”某些东西,您不仅会忘记安全清理所需的所有细节,而且您将成为比以前更好的程序员,并且您很可能会被诱惑扔掉一切然后重新开始。而且由于这工作量很大(无论如何通常都是个坏主意),您可能会再次跳过清理。
a安

“为什么我要拒绝我自己,只在以后为将来的某个程序员做呢?” 启示!你猜怎么着?您有时(有时,经常)是那个未来的程序员。
—radbobo

@RobbieDee,最高级的观察!在接受采访时,马尔科姆·格拉德威尔(Malcom Gladwell)曾将“ 10,000小时规则”带到了大众的视野中(在《离群值》(Outliers)一书中),他说这必须是“刻意的实践”,否则只会浪费时间。意思是专注于改进,练习特定技巧以提高技能的特定方面,等等。
radarbob

@ThanosTintinidis,那么就存在“没有善行不罚”的问题。编写了如此干净的代码后,不可避免地会有人将其锁定。当其他人触摸您的干净代码时,请确保您是代码检查者。一种简单的添加方法破坏了封装和连贯性,甚至在联机文档中也有记载。我生气了一个星期。一年后,每次我看到该代码。
—radbobo

4

您可以通过区分“我只是在尝试查看它的工作方式”代码和“这已进入产品中”代码来实现。有很多方法可以做到这一点。

一种是分支,要么是源代码管理系统中的字眼。您为新报告或新导入布局或其他内容创建分支。如果人们喜欢它,则将其返回到主分支的工作是一项单独的,可跟踪的工作。可以将其分配给某人并进行报告,并且在管理层(或销售人员)同意该功能属于产品的前提下,这绝不会神奇地发生。

另一个是尖峰。您不会在产品中进行更改。您进入了一个非常简单的单独应用程序,该应用程序只为您提供放置代码的地方。您可能会感到混乱,因为您只是在探索新的API或其他任何东西。再说一次,如果您回来并报告“是的,我们可以做到,我已经弄清楚了”,这是一个可跟踪,可报告,可分配的任务,即在产品中编写产品就绪代码以完成您想要的事情。

在这两种情况下,产品就绪意味着可读性好,整洁,遵循命名标准,经过测试并坚持您的代码风格和性能目标。在这两种情况下,您都可以看到该作品。我同意,当某人很可能将功能从产品中撤回时,您不想每次都完成所有工作。但是,您也不想让这项工作变得无形。使用产品的单独副本或仅使用测试工具进行无关的产品处理,就可以让您浮出水面,以在有人决定要东西时制作出产品就绪的代码。

不利的一面是他们无法决定要买东西(意味着半定,凌乱,未经测试,未记录,可能已经缓慢实施的半版本,您已将其用作概念证明)。他们第一次让您对此事有所回击时,只需问一下是否应该每次都以较长时间(更昂贵)的方式这样做,以防万一,从而减慢了拒绝功能的步伐。如果您正确询问,您将获得“否”。


1

真的,我认为您已经理解了这个问题。问题在于您的编码风格要求您进行过多的返工。之所以需要太多的返工,是因为(a)没有足够的远见和规划,并且(b)在开发过程中定期添加的短期短期补丁组合增加了所需返工的复杂性。

因此,答案是

(a)将您的开发风格更多地转移到瀑布上,而不是灵活一些。但是不要一路走下去,因为经典瀑布有它自己的陷阱。有一个健康的平衡。我知道有时候可能只是考虑几天而已,就像没有完成任何开发一样,但是您必须信任该过程。在工程学中,您不能只将东西钉在一起,然后再将它们钉在顶部,并希望提出一种优雅的解决方案。如果没有人在做架构和更高级别的技术设计,那就是您的工作。您一直为忽略这项工作付出代价。

(b)尽量避免打补丁。不要仅在需要进行质量检查时才长期考虑。确实,您应该一直在测试构建的每一个小片段,并涵盖所有输入案例,包括那些不在幸福道路上的案例。从定义上说,修补程序/黑客几乎是一个短期修复,很可能会带来长期成本,从而打击客户在系统中的总体拥有成本。再次,发出代码的压力很大,因此必须保持平衡。但是,请尽量不要采取短期修复措施,尤其是。那些紧密耦合的组件,实际上应该是松散耦合的。将会有返工,因此请尽早进行以使其变得更容易,以避免随着时间的流逝而变得难以管理的hack和补丁。


2
只是一个提示-敏捷并不意味着“无意识的频繁更改”或“较少的设计”。实际上,我发现敏捷比人们通常所说的瀑布需要更多的设计。缺乏好的设计是瀑布在实践中效果不佳的原因之一-如果您实际上在设计上进行了适当的投资,则效果很好;它也比敏捷变得昂贵得多。如果您跳过敏捷中的设计部分,则只是将代码随意组合在一起,这将比避免设计的任何其他实践更好。
六安2013年

敏捷专注于短迭代,冲刺等,使原型快速发布,必然会给更大的压力是要提前忽略足够的设计
Brad Thomas

不,它专注于设计较小的零件。但总体而言,您必须进行大量设计,否则您将要生产出可怕的产品。关键是要使事物小型化,精心设计以及可互换。如果您在敏捷性方面的设计较少,那么您(和您的客户)就会受到损害。短迭代是使用敏捷的好处,而不是先决条件或仅是过程的一部分-一旦一切都变得足够好,您就可以突然负担得起短迭代,而不是相反。
六安2013年

当更大的画面通常是返工的最重要原因时,将更多的重点放在设计较小的零件上是一个主要问题。我已经看到很多钱全都浪费在企业突然说“但是我们需要它来做到这一点”上,这需要进行大范围的大修,这比我在改变设计中看到的要多。小的松散耦合组件
Brad Thomas

是的,但是到那时,您已经迷路了(无论您是尝试敏捷还是瀑布)。当您的“大局”由相对孤立的许多小零件组成时,您得到的唯一大范围的大修就是需要更换几乎所有东西时。当您需要从头开始时,哪种方法不会使您失去一切?甚至NASA的设计水平也导致“我们需要改变一切”。通过保持灵活性和适应性,您将获得更大的操作空间来适应大小变化。
a安

0

你写:

每个版本都不过是一个原型。因此,此时我不会在编写超级干净的代码上浪费太多时间,因为我永远不知道事情持续多长时间。...

然后是程序完成的时刻,决策者说“就是这样”。此时我确实有一个可以正常工作的原型,但是在开发阶段,所有来回的代码都有些混乱。

签入的版本可以是“原型”,因为它缺少功能或某些功能没有被充实,但是所有签入的代码应为不需要清理的生产质量代码。

我认为您将推迟“清理”时间。

我的经验法则是:

  • 从(子)功能开始
  • 可以随意编写不完整和不完整的内容,也许需要一些C&P来了解我要实现的内容,或者如果我不得不从头开始编写代码,请注意(这可以与TDD /测试结合使用,只是为了使我正在探索的实现空间得到快速反馈,所有的东西都经过了微调。
  • 子功能“作品”目前足够好
  • 现在进行清理:在SCC commit之前
    • 查看代码以了解明显的内容
    • 进行差异对比最后一次提交以检查更改,并可能发现一些问题
    • 修复我在便签本上记下的内容
  • 现在我进行提交-此代码质量已准备就绪

在这一点上,已提交的代码可能仍包含一些变通办法或“技术债务”,清理起来会很不错,并且当我为以下子功能自然而然时,我可能会对其进行清理,但是如果按原样释放该代码,将不会有任何问题。

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.