如何训练自己,避免编写“聪明”的代码?[关闭]


75

您是否只需要用Expression s 来展示新技巧或将三个不同的过程归纳起来就知道吗?这并不一定要达到宇航员的规模,实际上可能会有所帮助,但是我不禁注意到其他人将以更清晰,直接(有时很无聊)的方式实现相同的类或程序包。

我注意到我经常通过过度解决问题来设计程序,有时是故意的,有时是出于无聊。无论哪种情况,我通常都会诚实地相信我的解决方案是清晰而优雅的,直到我看到相反的证据,但通常为时已晚。我中还有一部分人喜欢无证假设而不是代码重复,而更喜欢简单性。

我该怎么做才能抵制写“聪明的”代码的冲动,什么时候我应该做错了

当我现在与一个经验丰富的开发人员团队一起工作时,问题变得更加严峻,有时我写智能代码的尝试即使是我自己,经过一段时间消除优雅的幻想似乎也是愚蠢的。


5
稍微偏离主题,但thedailywtf.com/Articles/...

@乔:这是非常主题,谢谢!我已经阅读了这篇文章,但是现在很高兴重新发现它。

33
调试很多聪明的代码...应该可以解决问题。
丹·奥尔森,

@Joe那篇文章中的数据库链接就是死的。
jnewman 2011年

简短答案:最短,最简单的代码胜出。消除重复,但不要“仅仅因为”而添加层。福勒的重构可能会给您一些见识。
凯文·克莱恩

Answers:


54

当我现在与一个经验丰富的开发人员团队一起工作时,问题变得更加严峻,有时我写智能代码的尝试即使是我自己,经过一段时间消除优雅的幻想似乎也是愚蠢的。

您的解决方案就在这里。我假设在这种情况下,“经验丰富”意味着“比您更有经验”。至少,您清楚地尊重他们。这是一个宝贵的学习机会-假设您的自我可以受到打击。(令人讨厌的东西,例如自我。可惜我们需要它们。)

您是否有与这些人的代码审查?如果是这样,如果他们还没有这样做,请明确要求他们打电话给您。提到您已经注意到自己有过度设计的趋势,使用简单设计的顶级气动风炮(最好由某种自动化的道路施工人员android操纵),而简单的羊角锤就足够了。

您可能经常会发现自己在座位上扭动,而在代码审查过程中,您的脸变成红色。忍受它。您正在学习。

然后,一旦掌握了其中的一些内容,请注意可能会过度设计的时刻。当这些时刻到来时,问自己:“如果有人在代码审查过程中要求我这样做,我是否可以捍卫我的解决方案作为最佳解决方案?还是我放弃了一个更简单的解决方案?”

有时,同行评审是对自己的工作有很好的了解的最好方法。


感谢您的答复。不,我们没有代码审查,主要是因为项目规模大且客户的资源非常有限。但是我想我可以通过每天结束时询问“我可以捍卫我的解决方案是否是最好的解决方案”来测试自己。

7
没有代码评论?rk 我会写一些自以为是的东西,但我也曾在那种环境下工作过。它们既耗时又给每个人带来痛苦,但它们对于手头的项目和您自己的个人开发确实非常有价值。如果主题为“我们应该进行代码审查吗?” 每当出现时,请确保您的状态为“ Hell yes!” 而且,如果他们不对自己迫在眉睫的截止日期大加抨击,您可以要求您尊重的同事提供您不确定非正式的Code-Lite-Lite工作。
BlairHippo 2011年

1
嗯,该项目是一个启动项目,由于一些计划上的错误,在客户端,由于我们确实需要快速交付,否则就会遇到这种情况,否则就不值得付出努力。我刚刚和我们的PM进行了交谈,他确认了激进的截止日期是我们至少在现在不进行代码审查的唯一原因。如果启动成功并且时间限制变得更加宽松,我们将来可能会进行审查。

2
天啊。听起来很令人兴奋-带有单词带来的所有好与坏含义。:-)朋友,祝你好运;希望您能踏上美好的开端。
BlairHippo 2011年

8
@BlairHippo:我只是听从你的建议,冷静下来,好心地问这位同事,他指出了我的变化所带来的问题,以便与我进行非正式审查,他同意了。这也有助于消除我们谈话中的某些尴尬(例如“您编写了复杂的代码,但我必须解决它。”)。谢谢!

20

最好的做法是牢记Brian Kernighan的格言:

“调试的难度是一开始编写代码的两倍。因此,如果您尽可能聪明地编写代码,就定义而言,您就不够聪明,无法对其进行调试。”


1
我完全同意这句话,但问题是如何克服成为聪明男孩的诱惑?可以告诉您生病时不要吃冰激凌,​​但有时无济于事。

13
+1表示每个代码猴子都应该心知肚明,但-1表示没有为OP提供如何将其应用于自己的工作的见识。因此,一切都变得均匀,没有箭头点击。
BlairHippo 2011年

2
很好的报价,但不是OP的问题的真正答案。
Jim G.

5
丹尼尔,您好,我们不仅在报价中寻找更多内容:该网站仅在问题与充满经验,事实和参考的长而深思熟虑的答案搭配时有用。根据您自己的经验,您还能添加更多吗?

2
-1:丝毫不回答OP的问题。
托马斯·爱丁

15

通常,对于具有任何重要意义的软件问题,至少有三种解决方案:显而易见的方法,非显而易见的复杂方法(聪明)和非显而易见的简单方法(优雅)。关于作者的引用在这里适用:

放下脑海里的一切,然后就当作家了。但是,一位作家可以毫不怜悯地判断自己的东西的价值,并摧毁其中的大部分。—科莱特

您将无法编写优美的代码,直到您可以毫无怜悯地判断自己的代码的价值并将其大部分销毁为止。如果您通过最终结果来判断优美的代码,那么它看起来似乎很容易,但是它需要放慢速度,遍历许多草稿,征求其他人的建议并去除页面上没有的内容。这意味着,即使您的代码运行良好,您也要问自己或同事为什么有些感觉不正确,直到您对答案感到满意为止。也许感觉太长或重复,或者您觉得编译器应该已经能够捕获某种错误。大多数有少量经验的程序员都可以轻松地识别不雅代码。诀窍是找出原因

这是编写更优雅的代码的有条理的方式。它还经常需要具有洞察力的知识,以帮助您以新的方式看待问题。这很难实现,但有助于减慢速度,在您开始编码之前先考虑问题。当您找到一个好的解决方案时,寻找一个更好的解决方案。阅读其他代码会有所帮助。上课或阅读最佳实践书籍会有所帮助。学习其他编程范例会有所帮助。向喜欢您的代码的同事寻求建议。


3
这让我想起了一位老数学家的名言:“对于每个问题,都有一个简单,优雅且错误的解决方案。”
Joris Timmermans

9

我将添加到现有答案中,以TDD方式进行开发,因此您首先要编写有关代码应执行的测试,然后实施以使测试变得绿色。这样,您将仅满足测试所施加的要求。由于您将编写测试,因此这是采用自律式开发方法的好方法。


我肯定会尝试在有时间时强加给自己。
jnewman 2011年

之后编写测试也是发现代码中大量错误的好方法。它以某种方式进行自我审查。但是,如果重新开始,TDD显然是最好的方法。
凡纳

6

当为一个跨过许多不同技能组和多年的庞大而充满活力的团队工作时,发展会自然而然地被“降低”到当前或历史上最保守或最缺乏知识的团队的最低水平。

这不一定是一件坏事,因为聪明的代码可能更难调试,更难在技术规范中传达,并且编写时间更长,从而降低了开发时间。

有时候,聪明的代码很重要,例如当性能成为要求时,聪明的代码会在软件的成熟周期的后期提供效率和性能提升。

聪明的代码还可以将可能无法暴露于新语言功能或库调用的团队传达给开发团队更快,更易理解的代码。例如,当我由一个初级开发人员首次介绍给Linq时,我立即就厌恶它是不必要的,难以调试,愚蠢的和“聪明的”。在自己玩弄它并发现Linq查询有多么有用和强大之后,我花了一些时间来学习它,而我的DAL代码从未像现在这样清晰易读,并且易于调试和扩展。

我很遗憾以前没有开放的心态,希望我不会对这样一个“聪明”的初级开发人员这么苛刻。

我的观点是,“聪明”的代码应该是可疑的,但是我们不应该继续反对它,因为它可能扼杀创造力和创新。

编辑:我只是意识到我没有完全回答你的问题。如果您的项目中有能力非常轻松地编写聪明的代码,那么团队也许应该采用更严格的编码标准,以遵循统一而独特的模板和样式。这将有助于画出沙箱的线条,这样您就不会在追球的时候徘徊在街上。


6

如果20%(您的%可能会有所不同)或您添加的更多行需要记录在文档中-是时候退后一步并重新思考了

我真的认为您应该努力变得聪明,这是变得越来越熟练的自然副作用。给自己一个一般性的指导方针,例如需要阐明自己意见的%的评论,是一种迫使自己退后一步并评估使用学到的新东西是明智的选择还是仅仅是炫耀新玩具的一种好方法。


3
我倾向于将文档/评论视为失败。当您需要记录/注释某些内容时,这首先意味着您的代码不清楚。不幸的是,这是一个不现实的目标,我们需要在某些时候进行文档记录。请记住,这部分代码应减少到最少。
deadalnix 2011年

@deadalnix:不错。我怀疑我的%会比大多数人高,因为我通常使用否则会死机且使用大量宏的汇编语言进行编码。很难阅读,每位新员工都必须学习该语言,因此需要更多评论。
DKnight

2
@deadalnix-说明文档代码不清楚的文档。非常需要解释原因的文档。我看过太多的代码片段,我可以理解他们的所作所为,但是为什么他们决定以非直觉的方式来做到这一点。这使得很难维护。
HLGEM 2011年

@HLGEM这是有争议的。代码的不确定性可能来自设计不良的libs / API,来自概念本身的不确定性,如关注点之间的不良分离。我们生活在现实世界中,我们的能力是有限的,因此我们肯定需要文档,但是每次我们都需要文档时,这意味着有人编写了不完善的代码。没有文档不是您应该做的事情-甚至不要考虑它,但是您必须始终考虑一些事情才能不断朝着正确的方向发展。
deadalnix

@deadalnix-完美的代码在现实世界中绝不是实用的解决方案。
JeffO 2011年

4

我无法抗拒尝试一些聪明的事情。

因此,我自己在家中进行玩具项目。

当新颖性消失时-问题解决了。


3

我认为,找出您的代码是否过于“聪明”的一种方法是退后一步,问自己以下问题:

如果我要将这段代码的打印输出提供给从未使用过该项目/代码的人员,他们是否能够阅读并向我描述该函数的功能(在给他们一些简短的上下文之后)?如果没有,我需要做多少解释?我如何向服用CS101的人解释这一点?

如果事实证明您必须步行某个方法或类中的每一行或大多数行,那么这可能太聪明了。如果您必须向不熟悉它的人解释语言构造(例如LINQ),那可能就可以了。如果您必须先看一下一行代码并仔细考虑一下,然后再进行解释,则需要对代码进行重构。


在解决问题时,我听说过这种叫“橡皮鸭”的东西。当遇到困难时,请尝试向对此一无所知的人(例如,您的橡皮鸭)解释问题,并查看解决方案是否不会落入您的膝盖。我必须认为这也将起作用。
BlairHippo

2

1)之前将其烧掉,这样您就知道这是一件坏事。尝试调试很早以前写的东西很有趣。我认为您已经覆盖了。
2)注释您的代码,在代码的每个部分之前解释您的工作。
3)如果您发现自己难以解释它,或者感觉需要插入图表,那么您刚刚做的事情太聪明了,可能可以做得更干净。

除非必须调试或扩展它们,否则聪明的解决方案可能是很棒的。有时,这是唯一的解决方案。如果您可以准确地描述它到底在做什么,以及它是如何做的,那么聪明的解决方案是可以接受的。

我通常使用注释来描述我正在使用的一段代码。如果看起来最令人困惑,我还将描述我的工作方式。理想情况下,代码应简单明了且易于说明。但是,如果我难以解释自己的工作方式,那显然是我需要退后一步再试一次的明显信号。


2
评论技巧也对我有用。除其他原因外,我总是在任何不平凡的子例程上方都添加一个注释框,作为一种最终的健全性检查。如果我发现自己不得不做很多解释(或者有时为之感到歉意),这些问题包括令人费解的代码部分或怪异的输入参数或其他内容,那可能是一个警告信号,我可能需要重新考虑一下解决方案。
BlairHippo 2011年

@BlairHippo哈!我喜欢“最终的健康检查”。
菲利普(Philip)

2

开始编写简单代码的好方法可能是 要求聪明的项目上释放聪明的热情。答案的其余部分特定于.NET,但我敢肯定,可以用任何其他语言找到类似级别的项目。

开放源代码依赖注入框架可以在其中工作,仅要求提供Expression技巧知识,就有F#和许多人可能想要尝试的任务。

如果您喜欢数学(那是与语言无关的),那么就有Euler项目适合您。

最后但并非最不重要的一点是,在.NET世界中,有一个Mono项目,其中有很多领域需要开发人员关注,其中有些领域非常复杂。如何为开源静态.NET代码分析器工具做出贡献?其中涉及一些IL分析以及高级分析。无论是Cecil反射库,支持还是.NET反编译器,Jb Evain始终致力于开发一些有趣的东西Expression

如果不适合,只需启动自己的模拟框架即可:-)


2

当您只需要通过Expressions展示新技巧或概括三个不同的过程时,您知道这种感觉吗?

没有

这就是为什么我总是说这是一件好事的原因,当新开发人员陷入大量未记录的speghetti代码以进行维护和重构时。它将教给他们维护他们未编写的过分“聪明”代码的现实,并希望对可怜的schmuck产生一些同情,后者从现在起5年后将不得不调试其代码。


我认为这更可能使他们感到沮丧,并认为他们的代码将比编写此烂摊子的菜鸟更好,更优雅。没有人写代码是为了使其难以维护。
2016年

2

我认为这个话题是精心选择的。编写一次可以完成一万件事的Perl行是“很酷的”,但是当您不得不重新访问它时,它很烂。

另一方面,无论是否聪明,都必须记录代码。在业界公认的编程语言和我们人类普遍习惯的高级概念之间存在固有的阻抗失配。自记录代码根本无法实现-直到成为自然语言。即使Prolog代码也需要记录下来,因为无论它有多高级,它还是相当正式的。

细粒度的命令性代码用于实施粗粒度的计划-需要记录在案。当快速的3行路线图注释可用时,我不需要阅读方法的所有50行。

以后的编辑:一个更有说服力的例子是超越计算机的例子。一本书可能写得很好,但是我们经常想在不同的抽象层次上对其进行处理。通常,本书会提供摘要,这就是注释可以为代码提供的内容。当然,经过良好抽象的代码可以为自助文档大有帮助,但不能为您提供所有抽象级别。

当我们需要在正文中解释索赔背后的推理过程时,注释也可以像书中的注解一样发挥作用。

在这种情况下,我发现我先前提到自然语言的陈述超出了评论的需要是不正确的。甚至自然语言(如书中的语言)也可能适合文档使用,以稀疏方式解释文本中体现的抽象,或者提供绕道而不会使主体文本偏离轨道。注意,抽象良好的代码可能已经在自我记录方面大有帮助。

最后但并非最不重要的一点是,注释可以帮助编码人员保持较高的抽象水平。很多时候,我意识到我在步骤列表中包含的两个连续注释并不代表相同的抽象级别,这立即可以使我对我使用该代码所做的事情有个批判性的了解。

某些问题超越了编码,并像其他活动一样影响编码。注释可以帮助您阐明代码的基本原理和方面,而我发现它们是一个令人愉快的伴侣,它会讲一种较柔和的语言,从而使人受益于更改。


1

怎么样?不断向那些经验丰富的开发人员显示您的代码。当您因过于幽默和花哨而受到抨击时,请把它吸起来,并问他们他们将如何做以及为什么这样做(当然是非对抗性的方式)。

根据-1编辑:

许多月前,我处于相同的情况-我有一个老板每次在Delphi中使用指针或“带有结构”时都会畏缩,另一个老板威胁要解雇我,如果我不停止短路我的所有布尔值0-1并在各处使用单字母变量。

我之所以学到是因为我问为什么,他们费力去解释,因为他们认为我可能相当于-大声笑...。


1
嗨,Mikey,我们不仅在寻找单行代码:该网站仅在问题与充满经验,事实和参考的长而深思熟虑的答案搭配时有用。根据您自己的经验,您还能添加更多吗?

1

我觉得有必要炫耀吗?没有了,不会再有了。我是怎么过去的?就像大多数人都摆脱了其他不良习惯一样……有意识地,有意识地练习适当的技巧。您做得足够多,您就会了解最佳实践的价值,并且通过不断地使用它们,您将养成良好的习惯。

还应意识到,通过专注于功能性软件(即按时且易于维护),您将获得您所寻求的认可。经验丰富的开发人员会来找您,说“您编写的模块设计得很好。我只需要实现一个组件即可将其插入我的项目中。” 而不是“我不得不重新编写您编写的整个模块,以便仅在另一个组件中使用它?您甚至听说过鲍勃·马丁或沃德·坎宁安吗?”

TLDR:您并不孤单。作为智能解决问题的副产品,最好是对技能的认可。


0

对我来说,过于聪明的代码通常会努力解决虚构的未来需求,而不是着眼于当今的需求。大陷阱!

0%过于复杂的代码不是可以实现的目标。甚至可能不是要争取的最佳目标。过于复杂的代码是不好的,但是您必须尝试新事物才能成长为程序员。如果可以避免,则不应在生产代码上尝试使用它们。与机器不同,人类会犯错误。

代码审查帮助。花几年的时间来修复别人的“聪明”代码会有所帮助。专注于客户今天真正需要的东西会有所帮助。

学校和企业都有工作人员负责清理和维护人员。代码也需要清理和维护!尽可能清理混乱(尤其是您自己的混乱)!我认为那是最好的。


-2

除了到目前为止提供的良好建议(代码审查,调试,TDD方法)之外,您还应不时(重新)阅读(最佳书籍恕我直言)有关良好编码实践的信息:

  • 务实的程序员
  • 代码完成
  • 清洁代码

和其他,取决于您使用的技术。


-2

记住YAGNI-您将不需要它

程序员在认为必要之前不应添加功能...

YAGNI是XP实践“做可能可行的最简单的事情”(DTSTTCPW)背后的原则。它旨在与其他几种实践结合使用,例如连续重构,连续自动化单元测试和连续集成。如果不进行连续重构而使用,可能会导致凌乱的代码和大量的返工。

那些主张使用YAGNI方法的人认为,目前暂时没有必要但将来可能会编写代码的诱惑有以下缺点:

  • 花在增加,测试或改进必要功能上的时间。
  • 必须调试,记录和支持新功能。
  • 任何新功能都会限制将来的操作,因此不必要的功能可能会阻止将来添加所需的功能。
  • 在实际需要该功能之前,很难完全定义其功能并对其进行测试。如果未正确定义和测试新功能,即使最终需要它,也可能无法正常工作。
  • 它导致代码膨胀;该软件变得越来越大,越来越复杂。
  • 除非有规范和某种版本控制,否则使用该功能的程序员可能不知道该功能。
  • 添加新功能可能会建议其他新功能。如果还实现了这些新功能,则可能会导致雪球效应,从而导致功能蠕变...

3
尽管这可能是正确的,但更多细节将使它成为一个更好的答案。
克里斯·
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.