您如何应对编写的丑陋代码?[关闭]


88

所以您的客户要求您编写一些代码,所以您这样做。然后,他按预期更改了您的规格,并且您像个好小家伙一样努力地实现了他的新功能。除了...新功能与旧功能有点冲突,所以现在您的代码一团糟。您确实想回去修复它,但是他不断要求新事物,并且每次您完成清洁工作时,都会再次陷入困境。

你是做什么?停止成为OCD狂热者,只接受您的代码将使事情变得一团糟,无论您做什么,都只是继续增加这种怪异的功能?是否保存版本2的清洁?


15
这是一个很好的问题。
沃尔特

3
我认为这是适用80/20规则的好地方。
Mark C 2010年

嗯..首先不要写难看的代码吗?
Roopesh Shenoy

8
@Roopesh:首先不是丑陋的,而是当你不断地处理问题时它变得丑陋。使用这些附加功能,您将意识到可以对核心结构进行不同的设计以更好地支持这些功能。此时,您可以返回并重新编写大量基础,也可以仅添加功能。通常,没有足够的时间来备份和重新编写一半的程序。
mpen

然后说“设计时要考虑改变”。当然,很容易说出来,但是当一些基本情况发生变化,因为您的客户并不真正知道他想要什么,而只给您一半的规格时,这有点困难。
mpen

Answers:


41

换一份工作,让其他人处理。Muahahahhahahaa。

.....

开玩笑吧 :)

但说真的,估计填充是您的朋友。我通常会做一个体面的现实估计,然后再加倍。这可能听起来有些过分,有时甚至是,但最好还是高估一些,有时甚至看起来有点慢-比通过产生错误的代码并总是夸大您的估计来留下不好的印象。当然,通过让代码库变黑,您将招致技术债务。

另一个(相关的)提示:总是估计看似很小,对一个像样的块没有费力的工作。举例来说,假设-您几乎可以肯定的是,一条线只需30秒更改一次-给它1小时(或者您的时间表或CR系统上最低的时间段,例如15分钟/0.25小时) 。并为稍大但仍相对琐碎的项目提供半天或1天的时间段。

这样做的原因主要是心理上的:我发现,如果您习惯于迅速修改一些小改动,就会感到工作很匆忙,而且您永远也不会坐下来收拾东西,并重构需要重构的东西。而且,在实际的水平上:微小但并非不重要的更改有时会爆发,并且您不希望一直感觉自己落后于进度并扑灭了虫子。这是为什么代码库会随着时间推移而变黑的部分原因。

最后,请始终记住,人们不必知道您在稍微增加估算值。只要您是一位称职的开发人员,而且您正在以适当的速度进行工作,那么这种填充就不会引起注意。即不要告诉PHB“我的最初估计是要花两个小时,但要给我半天时间”。只要告诉他“我认为大约需要半天。” 放在那里


12
+1为邪恶。;)for(printf("MUHU"); 1; printf("HA"));
Mateen Ulhaq 2010年

1
@muntoo:花了我一点时间才意识到那是什么...没看到for。可爱;)
mpen

4
我确定这取决于经理,但您不一定需要说谎。我和首席技术官有一个了解;他知道我可以给出一个合理的估计,但是只有大约50%的置信度。如果我加入了一个忽悠因素,那么我可以以90%的置信度给出相同的估计。而事实证明,过的很长一段时间,许多人宁愿可靠的估计,以天真乐观的人,即使他们不承认或者意识到这一点,所以他给出了悲观的估计,以他的老板,除非它是一个紧急情况。
亚罗诺(Aaronaught)2010年

2
完全不用花不到半个小时的时间就可以很好地做到这一点。即使对代码进行一次更改仅需5分钟,也会产生大量开销。
Murph

2
@Murph-当场。我拒绝任何少于半天的商业估算。在开发人员获取正确的代码,进行更改,运行单元测试,通过构建进行测试以及测试是否完好无损之前,到此,这只需要5分钟。
乔恩·霍普金斯

66

故意高估了下一个功能所需的时间。花费额外的时间进行清理。

您将永远无法证明维护的合理性,而客户无论如何都需要维护,因此请给他们苦药(下一个功能的成本略有增加),这样他们才能变得更好。


为此+1。估计填充FTW。确实,同样的建议也可用于证明错误修复和维护需要多长时间(无论如何,内部:证明PHB,而不是客户(您说客户不在乎)是合理的)。
鲍比表

5
我认为这也是解决问题的一种合理方法。他们所遭受的开发人员的痛苦需要作为额外的费用转回。管理人员和销售人员也必须接受这种哲学,否则开发人员将陷入困境,并遭受不断恶化的代码库的攻击。
Tin Man

1
哦,进一步:绝对,理想是开放,诚实的沟通。我仅建议无法完全实现的应对机制。这是欺骗的长期医学。
Frank Shearar 2010年

3
这是估算填充吗?在我保持代码质量的同时,似乎是时候实施一项新功能了。
David Thornley,2010年

2
我认为这主要是正确的方法,但是我将以不同的方式描述它的特征。他们正在雇用您制定专业的质量代码。这意味着您需要将估计时间纳入“正确执行”的时间。如果您熬夜整夜并在第一次正确运行后就宣布“完成”,则不要根据花费的时间进行估算。这可能意味着在竞争情况下,有时您会出价低下。没关系。您将因提供高质量和一致性而赢得声誉,并最终赢得胜利。玩长游戏。
布兰登·杜莱特

11

尝试在集成新功能时进行适当的重新设计。以后没有了。没有重新设计,您将不断增加越来越多的摩擦,以进行进一步的更改和新功能。

在某个时候,您将陷入停滞不前的状态,一切似乎都需要花费很多时间。大多数公司可能会在此时进行大笔改写,即版本2。它的经济性很差,如果客户愿意,现在是您的客户尝试其他开发团队的好时机。

正确的重新设计/重构可以保护您的客户投资并保持可持续发展。您需要内置它。为变化而优化,轻装上阵。


6

关于高估的所有评论,我认为有一点点(机会)错失了。

它不是估计(仅)更改所花费的时间,然后添加一些信息,它是关于估计修改代码(重构!)以使其可以安全地进行更改并随后进行更改所需的时间。变化(可能有点杂乱无章)。好的,这等同于同一件事...但是没有任何伪造,拉伸或高估的问题,仅是说要执行此操作,我首先需要执行此操作,这将花费多长时间总共。这里的关键是,您可以处理更改所依赖的系统部分,而无需再进行其他操作-如果其他地方有可怕的代码...很难,到那里就可以抓住它。

回到最初的问题-经过多年的努力,对我来说,当您实施某些事情时,除非您知道(不相信,不期望(怀疑?),不认为但知道),否则,也需要这样做,那么您应该执行实现该要求所需的一切,而不必再以尽可能整洁而优雅的方式进行了。

当您要实现下一件事时(稍后一段时间),您将采取必要的步骤将代码库(以及数据库等)带到实现该功能所需的状态,以尽可能整洁和优雅的方式进行。这种重构是处理项目发展过程中自然产生的混乱的地方-并希望避免创建更多的混乱(或至少保持级别一致)。

这里的讨论领域之一是“技术债务”-就像透支一样,您必须还本付息,而您离开它的时间越长,您就会产生更多的利息(在这种情况下,需要时间来纠正)-这给了您很好的回报。花费一些时间来减少技术债务的论点。

这也是单元测试和其他自动化测试开始出现的地方(如果我能做得很好,我肯定会成为一个更快乐的人!),再加上适当的构建服务器(可以运行至少一些)您的测试)。与它们结合在一起但本身具有价值的是诸如依赖注入和控制反转之类的模式(永远不确定这两者的“相同”程度是多少),因为它们使更改管道更容易,因此可以处理隔离。

最后-请记住,如果它没有损坏,请不要修复它。纯粹为了整理代码而对代码进行整理可能会很令人满意,但是它也有引入错误的机会,因此,如果您不需要更改代码而不在此基础上进行代码编写可能会很痛苦,那么最好保留一些内容独自一人-修复或更换的机会最终将滚滚而来!


4

1)适当的变更控制是您的朋友

如果客户更改了合适的规范,这是他的权利,但是这是一项更改,需要付费(或以适合项目结构/关系的任何方式进行收费)。

所做更改的估算应包括必要的重构成本。客户可能会以高昂的代价大吃一惊,但是此时您需要向他解释,因为代码已经写了一半,所以有一些元素需要重写以确保其将来的健壮性和可支持性。如果不这样做,那么他将来可能会遇到问题,因为将来的支持或变更会变得更加昂贵。

2)应该进行重构,从而为客户提供真正的长期利益

在考虑重构时,您始终需要考虑实际需要和重要内容,并确保重构工作能够提供真正的长期物有所值。

毕竟,我们应该做这些事情,以便使代码在中期/长期内保持可扩展性和可支持性,以确保客户的投资保持有效,而不是出于理论上的追求。重构工作(和相应的估计)应该以此为范围,而不仅仅是因为您现在认为可能会有更好的方法。


3

一些程序员建议控制客户端问题的一种方法是让客户端签名并授权初始规范。然后,当他们要求更改初始规格中未包含的需求变更时,您告诉他们您需要仔细阅读合同和项目时间表以计算额外的成本和时间延迟,然后将其作为合同的附件。显然,它确实阻止了客户坚持使用新的(不可预测的)功能。


2
+1; 它可以正常工作,但是也因为过于僵化而冒着疏远客户的危险。在某种程度上,您能否执行此操作取决于项目的类型(大小)和客户的期望。
肯·亨德森

3

我目前正在处理的代码库中有以下评论:

/*
 * Every time I see this function, I want to take a shower.
 */

我知道,您所描述的情况非常好。我要做的是(尽力而为)等到一切解决之后,任何一种“蠕变”都会使所有蠕变变得“蠕变”。到那时,您可能已经发布了一些可用的东西,并且您可能需要花费一些时间来整理和实施某些内容。

您无法反复清理许多小混乱。那只会使您的工作和沮丧感增加三倍。等待它变得更大,但几乎不会动乱,然后您可以对其进行处理。


2

我的偏好是首先避免这种情况。

这完全取决于您如何阅读规格。容易将它们视为石碑,但实际上大多数规格都在变化。设计代码时,请查看规范各部分更改的可能性。随着时间的流逝,您会很好地预测这一点。

陷入困境,经验和判断力非常重要。您是否因为此意大利面条式代码编写了新的错误?实施需要更长的时间吗?这些将指向进行战术重构。

对于未来,听起来您需要与客户合作。对他们说,“看起来该产品正在大大超出原始规格。尽管原始设计在那个水平上是不错的,但在X方向和Y方向上进行扩展需要在设计中进行一些调整”,您甚至可以得到满意的结果。客户为此付费。


我不知道我是否会将其视为“错误”。我正在进行一些重大更改,当您开始撕下基础时,自然一切都会崩溃。这都是可以修复的。我提醒我的客户,定期进行这样的更改需要付出一定的成本,但是他希望获得我无法给出的即时“估计”。在您真正考虑了需要进行的所有设计更改之前,甚至无法停车。但是他只是不明白。无论如何,他在付款,他也没有抱怨太多。
mpen

2

按小时收费,如果他要更改,可以说很好,但可以将编写好的代码所需的时间纳入公式。还要记住,编写整洁的代码可以长期维护您的利益。现在节省时间可能会在以后花费您。


我按小时收费,但问题是,即使我花时间编写“好的代码”,它也很快变得过时了,我想知道是否有任何意义。我认为我要在项目稳定之前就不断进行清理,以增加成本。
mpen

1

我认为编写软件需要与业务需求齐头并进。如果这是一个一次性项目(例如需要在一周内构建一个原型,每天都会有新的输入),那么就不必担心代码的可维护性和其他问题-时间很关键,您只需要尽可能快地将您的代码推出。

但是,如果您正在编写一个长期的应用程序,那么就需要考虑所有这一切,因为这对构建新功能,修复现有错误,集成到其他应用程序和其他内容所需的时间有相当大的影响-并且这会转化为业务影响(因为以后需要更多时间和更多成本)。

因此,最好让决策者在必要时对不重构代码的实际成本敏感-根据我的经验,如果两个选项的成本和时间影响都是以可衡量的方式向决策所有者解释的,则决策可以是不费吹灰之力。不要指望别人告诉您“是的,尽管编写代码要花两倍的时间,并且没有给我带来额外的好处,但是请继续编写漂亮的代码”。就是那样行不通。


1

使它成为您流程的一部分,我称其为“极端重构”,它将变得很大!;)只需快速进行操作,并在添加了足够多的新功能后发现疤痕组织,就可以对其进行重构。不断问自己“现在,如果我从头开始,那我会怎么做”

认为自己可以设计和考虑所有事情的人大多在自欺欺人,您(和客户)总是在学习过程中学习。使用这些课程。

当您是一名优秀的程序员时,您将能够相当快地进行重构,并且随着您不断地进行重构,代码将开始采用“适当的形式”,这意味着它将变得更加灵活,并且依赖更少。

如果客户知道您在“浪费时间”在重新制作内容,可能会感到不高兴,这样可以帮助您不问/不说,并且很快就知道。

以这种方式开发的代码最终将节省您的时间,并使添加新功能变得越来越容易。

我还要说的是,导致代码编写错误的最大原因之一是某些程序员担心进行更大的结构重构,而等待时间越长,情况就越糟。


1

依靠更高的力量

我不是在祈祷。我的意思是,请确保您有一个业务人员(即项目经理或同等职位)可以作为您和客户之间的填充物放置。如果客户要求太多,请让业务员放下脚步并准备使用“这是可行的,但我不确定这是否符合规范的范围,请参阅[业务员]”。

在正常的项目流程中,应该冻结通用规范,然后再进行认真的开发。

只要您允许,许多客户就会继续寻求改变/改进/增强。许多人会最大程度地滥用这种能力,因为这会使他们觉得自己从金钱中获得最大收益(即使它破坏了您的项目)。

请专人尽早完善和冻结规范,然后再执行。

与客户做一些额外的事情以增加好因果报酬没有错,但是当他们失控时准备好屈从于更高的权力。如果规范需要大量修改,也许是时候回到业务循环中,重新评估合同和/或在合同中增加附加内容(以公平的货币补偿)。

您遇到此问题的事实与您的编码方式无关。这表明您的项目经理对项目的利用不足(无论是您的错,他的错还是两者兼而有之)。

就像其他人在许多答案中所说的那样,在任何项目上也都需要为突发事件添加时间缓冲区,但是要确定在技术规范被冻结并由PM交付给客户之前,应该在关闭的门后决定。


0

最初的正确设计不能帮助避免问题。而且几乎不可能(或者非常困难)考虑所有未来的“也许”要求。因此,一段时间后,大重构将到来。最好的解决方案是重新编写所有内容。

简而言之:不要将炮塔安装到红色法拉利上,而要重新考虑需求并建造一个坦克。


0

用火杀死它。

Aka尽快重构:例如,当匆忙的截止日期中出现丑陋的代码时,我会在截止日期之后进行重构,因为在现有代码可维护之前,您不能(或至少不应)添加更多功能,否则这将使调试未来的代码变得更加困难。


0

为项目编写单元测试,以测试当前状态,然后在有时间时进行重构,这样可以避免在尝试清理项目时破坏项目。


0

最简单的答案。我将停止任何形式的编码,直到他对他/她到目前为止想要的东西有了最终的规范。

然后,他们需要对功能列表等进行优先排序,以确认当前必须包含哪些项目,以及以后可以进行哪些工作。

根据您的经验确定每个功能的时间/成本,然后告诉他们,如果他们想要这样做,将花费x的时间和金钱。

您应对功能范围不断扩大的大罪行,他们将不断地添加功能,直到一无所获或做得如此糟糕。

告诉他们最终清单后,您将按照他们的意愿进行将来的修改,但需要重点关注他们现在必须拥有的前15/20。

然后根据完成时间告诉他们,在发布该版本之后,您将可以讨论/讨论新版本。

一旦对当前版本要做什么做出最终决定,所有讨论/想法/建议都必须停止100%。

如果他不断想出主意,请告诉他/她在下一个版本的功能列表中写下它们,然后让您集中精力提供他们现在想要的最重要的功能。

如果他们继续浪费您的时间,请继续改变主意。然后,我将停止从事该项目,而继续从事其他项目,直到他们完成决定。

很难做到,但是特征范围的蠕变是如此破坏时间,精力,动力和清晰的思维。


0

从项目完整的角度来看:

与您的团队一起从代码中学习,了解下一次可以重构和重用的内容,然后喝杯啤酒。

从开发的角度来看:

耐心地解释为什么开发已停止,并解释了为什么直到所有规格都摆在桌面上并得到理解后,开发才能继续下去。然后,去喝啤酒。

从计划的角度来看:

要求所有规格,并与每个人一起清楚地了解开发路径。让客户/利益相关者尽可能紧密地参与进来,以确保所有人都在同一页面上。那天晚上晚些时候,给大家喝啤酒。明天,开始项目。

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.