您如何阻止临时解决方案永远持续下去?


79

说一个问题有两种可能的解决方案:第一种是快速但笨拙的。第二种是可取的,但实施起来将需要更长的时间。您需要快速解决问题,因此您决定尽快解决该问题,并计划在以后开始研究更好的解决方案。问题是,一旦问题得到缓解,它就会急剧下降到待办事项清单中。您仍然计划在某个时候提供更好的解决方案,但是很难证明现在就实施它是合理的。突然之间,您发现使用了效果不理想的解决方案已经花费了五年时间,并且诅咒了一段时间。

这听起来很熟悉吗?我知道在我工作的地方不止一次。一位同事描述,故意制作不良的GUI,以便长期使用它不会偶然。您有更好的策略吗?


很好的问题-我刚进入一个包含许多这类解决方案的项目。我热切地等待着答案。
克里斯·玛拉斯蒂·乔治

敏捷但but强的人倾向于永久化。在一个个人项目(小型网站)上,我十年前编写的“临时”解决方案至今仍在使用。
Powerlord

Answers:


37

编写一个测试案例,说明黑客失败。

如果您无法编写一个测试失败的测试,那么说明该黑客毕竟没有问题,或者您的测试框架不够完善。如果是前者,请先逃之on,然后再浪费不必要的优化工作。如果是后者,则寻求另一种方法(标记黑客或测试...)


那可能是最好的解决方案。测试失败通常是高优先级。
Toon Krijthe

1
正是因为失败的测试是重中之重,所以这并不是解决问题的方法,而是与团队和/或经理抗衡的好方法。
Michael Borgwardt

1
如果这使我的团队感到反感,那么显然他们不同意我的“开始寻求更好解决方案的计划”。如果他们是正确的,那么“快速”版本不是黑客,这是一个有效的解决方案。尝试设计一个测试失败是确定我的代码是否足够好的最佳方法。
史蒂夫·杰索普

1
...我的一般观点是,如果“快速”修复足够好,那么这个问题就构成了一个错误的问题,这是不应该解决的:“我应该如何做不需要做的工作?”。如果“快速”修复程序不足以发布,那么将不会受到同事的反对。
史蒂夫·杰索普

1
还请注意,我不打算用8个词来提供一种万能的开发方法,愚蠢的人可以阅读一次然后盲目地跟踪,从而跟踪并修复所有可能的代码缺陷;-)只需使用您拥有的机制(测试) ),以智能方式衡量缺陷,毕竟这是针对缺陷的。如果您确实无法编写测试,那么请寻找其他确定代码是否包含缺陷的方法。如果代码可以附带缺陷,请考虑“可选”测试。但最重要的是,客观地量化问题。
史蒂夫·杰索普

17

策略1(几乎从未选择过):不要实施合并。甚至不要让人们知道这是可能的。第一次就用正确的方法做。就像我说的那样,由于时间限制,几乎从未选择过此选项。

策略2(不诚实):说谎和欺骗。告诉管理人员黑客中存在错误,以后可能会引起重大问题。不幸的是,在大多数情况下,管理人员只是说要等到漏洞成为问题之后再修复漏洞。

策略2a:与策略2相同,但确实存在错误。同样的问题。

策略3(以及我个人最喜欢的策略):尽可能设计解决方案,并做得很好,以至于实习生或代码猴子都可以做到。证明花少量代码猴子钱比证明自己的薪水要容易,因此它可能就完成了。

策略4:等待重写。继续等待。迟早(可能稍后),某人将不得不重写该东西。那时也可以这样做。


策略4的唯一问题是-当您最终进行重写时,还存在主要的时间和预算限制-因此,hack被复制了-或其他笨拙的解决方案被放入了重写中。
Ken Ray

1
策略4的一个问题是,经过5年的变通和修复,准备好重新编写时,翻译中会丢失一些内容。
乔瓦尼·加尔博

究竟。只需支付6个月的重新编写费用(基本上使他们获得与原来相同的应用程序,但有额外的错误),业务利益相关者就不会感到生气。策略5:在有意义的情况下逐步谨慎地重构事物。
Eric Z Beard

16

这是一篇有关技术债务的重要相关文章。

基本上,这类似于您做出的所有技术决策的债务。有好债,也有坏债……您必须选择可以以最少的长期成本实现所需目标的债务。

最糟糕的债务是小而少的积累快捷方式,类似于信用卡债务……每个人都不会受到伤害,但是不久之后您就进入了贫困之家。


那是一篇很棒的文章-谢谢。当我问这个问题时,我想到的是II-A-1(汽车贷款类比)而不是II-A-2(信用卡)的债务。我现在看到这些债务可能很好,而且该组织可以明确地为它们计划。
汤米·赫伯特

14

在进行截止日期驱动的工作时,这是一个主要问题。我发现添加了关于为什么选择这种方式的非常详细的注释,以及一些有关如何进行编码的提示。这样,人们在查看代码时就可以看到并保持最新。

另一个可行的选择是在跟踪框架中添加一个bug.feature(您确实有一个吧,对不对?),详细说明返工。这样一来,它就可见了,并且可能会在某个时候强制问题。


同意 将项目添加到跟踪系统。问题在于,除非解决了与功能相关的重大问题,否则通常不会解决临时解决方案。除非您发现自己无法维护代码,否则也许可以。您如何提出这个问题?
s_t_e_v_e

是。如果您知道一段代码将要失败,那么即使它尚未失败,也是一个错误,应该将其作为一个代码进行跟踪。这样做的另一个心理优势是,当您进行草率的修复时,项目的bug数量会增加。
罗伯特·罗斯尼

13

唯一可以证明修复这些问题的理由(因为它们并没有真正损坏,只是丑陋)是在您拥有涉及相同代码部分的另一功能或错误修复时,您不妨重新编写它们。

您必须对开发人员的时间成本进行数学计算。如果满足软件需求,并且唯一的错误是代码在幕后令人尴尬,那么就不值得修复。

整个公司都可能倒闭,因为过分热心的工程师每年都会在遇到麻烦时坚持进行重新架构。

如果它没有错误,并且满足要求,那就完成了。装运它。继续。

[编辑]

当然,我并不是要提倡所有时间都被黑客入侵。您必须在开发过程的正常过程中仔细设计和编写代码。但是,当您遇到需要快速完成的黑客攻击时,您必须进行成本效益分析,以了解清理代码是否值得。如果在应用程序的整个生命周期内,您花费在纠缠的hack上的编码时间要多于修复该代码的时间,那么当然要修复它。但是,如果不是这样的话仅仅因为查看源代码会使您感到不适,重新编码一个可以正常运行的,没有错误的应用程序将非常昂贵且冒险。


1
“如果它没有错误,并且满足要求,那么就完成了。请发货。继续前进。” 我不同意。我目前正在使用一个非常复杂的代码库,以至于任何简单的更改都需要几天而不是几个小时的时间。它没有“虫子”,但结构不良会带来持续的成本。
克里斯托弗·约翰逊

好吧,您不想只破解所有内容,但最终会陷入混乱。所有这些都是成本效益的:如果它使您放慢了脚步,那么它确实需要重新编码,如果在应用程序的整个生命周期中节省的时间超过了冗长的错误修正,而无需重新设计。
Eric Z Beard

我认为您的评论是对的,埃里克。也许您可以编辑答案以反映出来?
汤米·赫伯特”

7

您不做临时解决方案。

有时我认为程序员只需要被告知这一点。

对此感到抱歉,但很严重-hacky解决方案毫无价值,即使在第一次迭代时,也可能比正确完成一部分解决方案花费的时间更长。

请不要再给我留下您的废话代码来维护。只要总是正确就可以了。无论花多长时间,谁会对你大吼大叫。

当您坐在那里,在其他人调试他们的愚蠢骇客的早期交付后,不停地抽签,您会感谢我的。

即使您不认为自己是一个优秀的程序员,也要始终努力做到最好,绝不要走捷径-这样做不会花费您任何时间。如果您不相信我,我可以证明这一说法是正确的。


在少数情况下,骇客入侵是对的-一般而言,甘特图显示,只要正确执行,其他23个人就会无所事事。同样,讨论也适用于原型,甚至适用于破解IMO。
史蒂夫·杰索普

没有原型。原型是生产代码的另一个名称。
Greg D'

特别要注意的是,尽管首先进行hack所需的时间总计较长,然后再正确进行,但这可能会缩短项目时间。其他所有人至少可以开始针对您的黑客测试其代码,例如,这些代码在功能上可能是完整的,但性能却令人无法接受。
史蒂夫·杰索普

@格雷格d:原型是一个产品,但它不是产品。除非您当然不能阻止发问者想阻止的事情,这就是IMO问题相似的原因。
史蒂夫·杰索普

不要制造原型,要制造钉子。峰值是实现功能的垂直生产代码,它永远不会比原型代码花费更多的时间-更快地破解是一个完全的幻想,即使在短期内。
Bill K

7

突然之间,您发现使用了效果不理想的解决方案已经花费了五年时间,并且诅咒了一段时间。

如果您要诅咒它,为什么它在TODO列表的底部?

  • 如果不影响您,您为什么要诅咒它?
  • 如果它影响到您,那么这是一个问题,需要立即解决。

通常,业务需求与您的痛苦不符。IT为企业服务。如果我们做的不是推进他们的目标,那么我们就有危险的脱节的危险。有时我们有机会做,仅使用IT的项目,但即使如此...

1
同意,只要他们的业务模型继续运行,管理层就不会在乎是否会影响我们。您必须提出一个商业案例,说明为什么现在就需要修复它,否则您的痛苦哀号将充耳不闻。
亚当·贝莱尔

如果业务需求与您的痛苦不符,那么您“不应”用适当的版本替换黑客,这个问题归结为“我该如何颠覆雇主的目的来为自己服务?”。答:组建工会。
史蒂夫·杰索普

5
  • 我要确保我对长期修复的优先级表示支持,尤其是在短期修复加入之后。
  • 我详细说明了为什么它是hack而不是长期解决方案的原因,并利用这些原因使利益相关者(经理,客户等)了解为什么需要修复它
  • 根据情况,我什至可能会在其中注入一些最坏情况的恐惧。“如果这条安全线折断,整个桥可能会倒塌!”
  • 我负责提出长期解决方案,并确保已部署该解决方案

4

这是很难的。我个人做过一些骇客活动,有时您不得不将产品推销到客户手中。但是,我照顾它的方法就是做到这一点。

告诉项目负责人,您的老板或客户:有一些地方需要清理,并进行更好的编码。我需要一个星期的时间来做,现在要花更少的钱,然后从现在起六个月后,当我们需要在子系统上实现扩展时。


在您的编程经验中,有什么使您相信,编程不良的解决方案比编程良好的解决方案更快地实现,测试和发布?说真的 我见过人们通常会在不知道如何正确执行时说出来。
Bill K

@Bill K:编程不佳从来都不在我的发言中。可能不太理想的解决方案。关于债务,您不承担任何债务,我承担一些小债务,我可以迅速偿还。我以后总是可以重构,客户不在乎,但是他们关心的是他们在一小时内需要董事会的报告。
MagicKat

@Bill K:所以在这种情况下,请确保代码库不是DRY,但是您是客户的英雄。然后,一旦交到客户手中,您就可以轻松地重构代码。对于长期而言,更重要的是一个小时的非DRY代码库,但客户满意,或者一个DRY代码库和客户不满意。
MagicKat

4

通常,此类问题是由于与管理层或客户的沟通不畅而引起的。如果该解决方案适用于客户,则他们认为没有理由要求对其进行更改。因此,需要事先告知他们要进行的权衡,以便他们可以在计划了快速解决方案之后计划额外的时间来解决问题。

如何解决它取决于它为什么是一个不好的解决方案。如果您的解决方案不好,因为很难更改或维护,那么第一次您必须进行维护并且有更多时间,那么这是升级到更好解决方案的正确时机。在这种情况下,如果您告诉客户或老板您首先选择了一条捷径,将很有帮助。这样,他们知道他们不能期望下一次快速解决方案。弄乱用户界面是确保客户回来修复问题的好方法。

如果由于风险或不稳定而导致解决方案不好,那么您确实需要与进行规划的人员交谈,并计划一些时间来尽快解决问题。


4

祝好运。以我的经验,这几乎是不可能实现的。

一旦由于压力而走上了实施骇客的湿滑之路,那么您很可能会习惯于一直生活。无论内部实施多么糟糕,几乎都没有足够的时间来对已经可以工作的东西进行重新设计。是什么让您认为您会“在以后的某个时间”神奇地拥有更多时间来修复该hack?

我能想到的唯一例外是,黑客是否完全阻止您实施客户所需的另一项功能。然后,您别无选择,只能进行返工。


“是什么让您认为您会在以后的某个时间神奇地拥有更多时间来修复黑客?” 我现在知道如何解决这个问题:当维修技术的费用超过维修技术的费用时,企业可以决定退还技术债务。请参阅Mike Stone链接到的文章。
汤米·赫伯特

2

我尝试构建该hacky解决方案,以便可以尽可能轻松地将其长期迁移。假设您有一个正在SQL Server cuz中建立数据库的家伙,这是他最强大的数据库,但是您的公司标准是Oracle。使用尽可能少的不可转让功能(例如Bit数据类型)构建数据库。在此示例中,不难避免使用位类型,但是这使以后的转换更加容易。


2

教育负责最终决策的人,从长远来看,为什么这种行事方式不好是坏事。

  • 用它们可以涉及的术语来描述问题。
  • 包括成本,生产率和收入曲线图。
  • 教他们技术债务
  • 定期重构,如果您被推动。
  • 切勿在非技术人员面前称其为“重构”或“返回并清理”。取而代之的是将其称为“适应”系统以处理“新功能”。

基本上,不了解软件的人不会重新审视已经起作用的事物。从他们的角度来看,开发人员就像是机械师,他们希望每次有人想要添加功能时都要拆开并重新组装整个汽车,这听起来很疯狂。

它有助于对日常事物进行类比。向他们解释,当您制作临时解决方案时,如何做出适合快速构建而不是稳定,可维护等的选择。这就像选择使用木头而不是钢材来构建,因为木头更容易切割,因此,您可以更快地构建临时解决方案。但是,木材根本无法支撑20层建筑的基础。


2

我们使用Java和Hudson进行持续集成。“临时解决方案”必须带有以下注释:

// TODO: Better solution required.

每次Hudson运行构建时,它都会提供每个TODO项目的报告,以便我们获得需要改进的任何未完成项目的最新,高度可见的记录。


1

好问题。这也使我很烦恼-而且在大多数情况下,我是唯一负责在自己的项目(是的,小型企业)中确定问题优先级的人。

我发现需要解决的问题通常只是问题的一部分。IOW,需要紧急修复的客户并不需要解决整个问题,而只是其中一部分-更大或更小。有时,这使我能够创建一种解决方案,该解决方案不是解决完整问题的方法,而只是解决客户子集的问题,这使我可以在问题跟踪器中保留更大的问题。

当然,这可能根本不适用于您的工作环境:(


1

这使我想起了“ CTool”的故事。最初,我们的一位开发人员提出了CTool,我称他为Don,这是解决我们遇到的问题的一种可能方法。作为认真工作的类型,唐插入了电源并交付了工作原型。你知道我要去哪里。一夜之间,CTool成为了整个公司部门工作的一部分。在第二天或第三天,关于CTool缺点的抱怨开始泛滥。用户质疑唐的能力,承诺和智商。Don的抗议从未被认为是生产应用程序,对此置若de闻。这持续了多年。最终,在Don离开后很久就有人来重写应用程序。到了这个时候,名称CTool变得非常讨厌,以至于无法命名为CTool version 2。甚至为CTool举行了一场正式的葬礼,有点让人想起Office Space中的复印机(或者它是打印机?)执行现场。

有人可能会说唐不配吊索和箭,因为它不能正确地修复CTool。我唯一的一点是,说你应该永远砍出一个解决方案可能是真实世界中不合理的。但是,如果您是这样做的人,请谨慎行事。


1
  • 以书面形式获得(电子邮件)。因此,当出现问题时,以后的管理人员就不会“忘记”它应该是暂时的。

  • 使它对用户可见。它越明显,人们越不会忘记在危机结束后回去做正确的事情。

  • 在临时解决方案针对项目,资源和时间表制定适当解决方案之前进行谈判,以获取真正的解决方案。真正解决方案的工作可能应在临时解决方案完成后立即开始。


1

您针对自己的“修复”提交了第二个非常有描述性的错误,并在受影响的区域中添加了待办事项注释,其中说:“该区域需要大量工作。请参见缺陷#555”(当然请使用正确的数字) 。那些说“别客气”的人似乎并不理解这个问题。假设您有一个现在需要启动并运行的系统,您的非骇客解决方案需要8天的工作时间,您的骇客需要38分钟的工作时间,这种骇客可以让您有时间进行工作,而不会因此而亏钱你在做。

现在,您仍然必须让您的客户或管理层同意,除了现在需要修复的N分钟外,还安排N * 100分钟来进行真正的修复。如果您必须在达成这样的协议之前拒绝实施hack,那么也许这就是您必须要做的,但是我在这方面与一些了解的人一起工作。


1

引入快速修复的实际价格是,当其他人需要引入第二快速修复时,他们将根据您自己的快速修复进行介绍。因此,快速修复的时间越长,它就越牢固。通常,骇客只比做正确的事情花一点时间,直到遇到第二个以第一个为基础的骇客为止。

因此,显然有时(或似乎是)有时需要引入快速修复。

假设您的版本控制支持它,一种可能的解决方案是每当您进行此类黑客攻击时,从源头引入一个fork。如果鼓励人们避免在这些特殊的“完成任务”分支中编写新功能,那么与将新功能与分支进行集成相比,最终的工作要比摆脱黑手多。但是,“好”叉子更有可能被丢弃。而且,如果您离发行版还有足够的距离,那么制作这样的fork将不切实际(因为不值得进行上述的双重集成),那么您可能甚至不应该使用hack。

一种非常理想的方法。

一个更现实的解决方案是将您的程序分成尽可能多的正交组件,并偶尔完全重写某些组件。

一个更好的问题是,为什么hacky解决方案不好。如果由于降低灵活性而不好,请忽略它,直到需要灵活性为止。如果由于影响程序行为而造成不良影响,请忽略它,最终它将成为一个错误修复程序并将得到解决。如果由于外观难看而不好,只要将hack本地化即可将其忽略。


1

我过去见过的一些解决方案:

  • HACK在代码中用注释标记(或类似的方案,例如XXX
  • 运行自动报告,并每周通过电子邮件发送给关心的人,这会计算HACK评论出现的次数
  • 在错误跟踪系统中添加一个新条目,其中包含行号和正确解决方案的说明(这样,在编写hack之前从研究中获得的知识不会丢失)
  • 编写一个测试案例,演示黑客如何失败(如果可能的话),并将其检入适当的测试套件(即,这样会引发错误,最终有人希望清除该错误)
  • 一旦安装了hack,并且压力减轻了,请立即开始使用正确的解决方案

这是一个很好的问题。随着越来越多的经验,我注意到的一件事:骇客为您节省了很短的时间,并且常常使您付出更多。紧密相关的是“快速修复”,可以解决您认为的问题-只是在发现问题根本不是问题时才发现。


1

撇开是否应该这样做的争论,让我们假设您必须这样做。现在的诀窍是以使远程影响最小化的方式进行操作,以后很容易将其删除,并使其自身成为麻烦,因此您记得要对其进行修复。

令人讨厌的部分很容易:每次执行kudge时都发出警告。

撕开的部分很容易:我喜欢这样做,是将kudget放在子例程名称的后面。由于您划分了代码,因此更新起来更容易。当您获得永久性解决方案时,您可以在子例程中实施该解决方案,也可以成为无操作人员。有时,子类也可以很好地工作。但是,不要让其他人依赖您的快速解决方案。不看情况就很难推荐任何特定的技术。

如果代码的其余部分很好,则最小化远程影响应该很容易。始终通过发布的界面,依此类推。


1

尝试向企业人员明确黑客的成本。然后他们可以以任何一种方式做出明智的决定。


1

您可能有意地以过于严格和单一目的的方式编写它,并且需要重写才能进行修改。


0

我们必须这样做一次-制作一个我们不希望保留的短期演示版。客户希望在winTel盒子上安装它,因此我们在SGI / XWindows中开发了原型。(我们都流利,所以这不是问题)。


0

自白:

为了从其他代码层读取数据,我在C ++中使用了'#define private public'。它以hack的形式出现,但效果很好,而且修复它从来都不是优先事项。现在是3年后...

无法删除黑客的主要原因之一是在修复黑客时引入新错误的风险。(特别是在处理TDD之前的代码库时。)


0

我的答案与其他答案略有不同。我的经验是,以下做法可帮助您保持敏捷并从hackey第一次迭代/ alpha解决方案过渡到可用于beta / production的状态:

  1. 测试驱动开发

  2. 小单元重构

  3. 持续整合
  4. 良好的配置管理
  5. 敏捷数据库技术/数据库重构

而且,不用说您必须获得利益相关者的支持才能正确地完成这些任务。但是,有了这些产品,您便拥有正确的工具和流程,可以自信地以主要方式快速更改产品。有时候,您的变更能力是您管理变更风险的能力,从开发的角度来看,这些工具/技术为您提供了更坚实的基础。

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.