查看代码时,哪些事情会立即敲响警钟?[关闭]


98

几周前,我参加了一次软件工艺活动,当时发表的评论之一是“我相信我们在看到错误代码后都会认出错误代码”,每个人都明智地点头,无需进一步讨论。

这种事情总是让我感到担忧,因为有人认为每个人都认为自己是高于平均水平的司机。尽管我认为我可以识别错误的代码,但我还是想了解更多有关其他人认为代码气味的信息,因为很少有人在博客上或仅在少数书籍中对此进行详细讨论。尤其是,我想听到一种语言而不是另一种语言中的代码味道会很有趣。

我将从一个简单的开始:

源代码管理中注释掉代码比例很高的代码 -为什么在其中?是要删除吗?是半成品吗?也许不应该将其注释掉,而只有在有人测试某些东西时才进行注释?就个人而言,我发现这种事情确实很烦人,即使只是到处都是奇数行,但是当您看到大块的代码散布在其余的代码中时,那是完全不可接受的。通常,这也表明该代码的其余部分也可能具有可疑的质量。


61
有时我会遇到一些人,他们将代码注释掉,然后检入并说:“将来可能再次需要它-如果现在将其删除,将会丢失它”。我必须反驳“ Er,...但这就是源代码管理的目的”。
talonx 2010年

6
有时,尤其是在优化时,将旧代码作为注释很方便,因此您知道模糊的优化代码将替换什么。想像一下,用一线位旋转交换替换掉三线交换并保留temp。(尽管如此,除非程序大小至关重要,否则我认为无需使用单行交换-EVER。)
Chris Cudmore 2010年

4
我正在维护/清理由我们的一位工程师编写的代码,这些工程师编写了一些有用的东西,但承认他不是程序员。当我合并内容时,我将注释掉他的旧代码,然后我们回顾这些更改,并向他展示如何用更小/更有效/更容易理解的东西替换他。之后,我将那些块剥离出来,然后将其检入。拥有旧代码很有好处,因为他看到了如何更简单地完成工作,并且我还记得为什么我们在讲话时更改了事情。
锡人2010年

8
我将“可能使用”的内容留给1次提交,然后,如果事情没有中断或找不到需要,则在下一次提交时将其删除。
保罗·内森

24
printf("%c", 7)通常会为我敲响警钟。;)

Answers:


128
/* Fuck this error */

通常会在一个废话try..catch块中找到,它会引起我的注意。差不多/* Not sure what this does, but removing it breaks the build */

还有两件事:

  • 多个嵌套的复杂if语句
  • 尝试捕获块,用于定期确定逻辑流
  • 与通用名称的功能processdatachangereworkmodify
  • 100行中六到七种不同的支撑样式

我刚发现的一个:

/* Stupid database */
$conn = null;
while(!$conn) {
    $conn = mysql_connect("localhost", "root", "[pass removed]");
}
/* Finally! */
echo("Connected successfully.");

正确,因为必须蛮力地使用MySQL连接才是正确的处理方式。事实证明,数据库的连接数存在问题,因此它们一直处于超时状态。他们没有调试它,而是反复尝试直到它起作用为止。


19
如果我能投票赞成6次!所有好的例子。我还不喜欢那些自大的/有趣的评论(尤其是如果其中包括骂人的话)-第一次阅读这些评论可能会有点可笑,但很快就会变得很老(因此会分散注意力)。
FinnNk

5
我喜欢您的示例,尽管我会说在某些情况下,不可避免要嵌套多个if语句。在具有大量业务逻辑的情况下,代码可能会有些混乱,但是,如果业务本身一开始就令人困惑,则简化代码将降低对流程建模的准确性。正如爱因斯坦所说:“事情应该尽可能简单,而不是简单一点。”
Morgan Herlocker 2010年

2
@Prof Plum-您能举什么例子?通常,使用多个嵌套if的替代方法是将其分解为(许多)方法。初级开发人员倾向于避免这种情况,好像它不如if那样可取。但通常在按下时会说“如果要减少行数”。需要对OOP有信心的人介入,并提醒他们更少的行=更好的代码。
STW 2010年

2
@STW这是一个好点,但是,我想说这取决于嵌套的深度。我肯定会同意,除了三个嵌套深之外,通常都需要重构,因为它会变得很毛茸茸。但是,保险报价是一个很好的例子,其中多重嵌套实际上可以很好地模拟现实世界。除某些费率/溢价外,该手册的字面含义如下:“如果这是一项财产,并且其最低费率低于5.6,并且是在NC中,并且在房屋中有船,则应这样做并这样。” 还有许多其他选择。
Morgan Herlocker

4
@josh,如果“他们”是同事,那么我会思考为什么您不说“我们” ...

104

对我来说,主要的危险标志是重复的代码块,因为这表明该人要么不了解编程基础知识,要么就因为太害怕而无法对现有代码库进行适当的更改。

我以前也把缺少注释视为危险信号,但是最近在处理很多非常好的代码而没有注释的情况下,我对此进行了缓解。


1
+1:我从同事那里看到了一些代码,他们自称是linux专家,他写了一个简单的循环应用程序作为一个长函数,整个过程在main()中一遍又一遍。kes。
KFro

4
@KFro,这是循环展开。那就是编译器一直在做的事情:)非常高效!

3
@Thorbjorn:有时候,您需要稍微帮助编译器;毕竟,您是聪明的人,他只是一台笨拙的计算机。
yatima2975

3
我见过的另一个原因:要求顾问尽快执行该功能(当然,这也是为什么缺少测试和文档的原因)。复制/粘贴比思考如何正确处理要快。
LennyProgrammers 2010年

4
避免代码重复是一种困扰。在像C ++这样的语言中,要剔除各个部分并不总是那么容易,但仍然具有健壮和高效的代码。有时,一些剪切和粘贴是更实际的选择。同样,可以应用优化原则-剪切和粘贴可以为您提供快速简便的解决方案,您以后可以根据需要进行重构。您可能为以后节省了一些麻烦的维护工作,但是您可以确定自己现在正在避免延迟。
Steve314 2010年

74

试图展示程序员的聪明才智的代码,尽管它没有增加任何实际价值:

x ^= y ^= x ^= y;

12
哇,这比swap(x, y);
-JBRWilkinson

8
如果X和Y是指针,这种分配发生在一段时间讲理的长度,它香甜打破保守的垃圾收集器贝姆一样GC。
SingleNegationElimination

12
顺便说一下,由于多次更改而中间没有插入顺序点,因此该代码在C和C ++中尚未定义。
fredoverflow 2010年

9
看着那,唯一想到的就是表情符号:^_^
Darien

62
  • 20,000(夸张)线功能。任何占用多个屏幕的功能都需要重构。

  • 同样,类文件似乎永远存在。可能有一些概念可以抽象到类中,这些概念将清除原始类的目的和功能,以及可能在哪里使用它,除非它们都是内部方法。

  • 非描述性,非平凡变量,或太多非琐碎的非描述性变量。这些使人们推论出实际发生的谜团。


9
我倾向于尽可能将功能限制为1个屏幕。
Matt DiTrolio 2010年

20
1个屏幕甚至是一屏。大约十行后,我开始感到脏。
布莱恩·罗

54
好吧,我要说一下可能不受欢迎的意见。我说写代码功能是原子的,从上到下的过程,这些过程被分解成单独的函数,这是代码的味道,因为开发人员坚持某些“功能应该简短”的习惯。函数应该沿功能行断开,而不仅仅是因为它们应该是一些神话般的“正确大小”。这就是为什么它们被称为“功能”的原因。
丹·雷

7
@Dan,功能不应该因为简短而简短,但是一次只能拥有太多信息。也许对我来说我脑子很小,限制是几个屏幕:)。在开始测试边界时,将功能分解为多种功能是避免错误的必要条件。一方面,它提供了封装,因此您可以在更高的层次上进行思考;另一方面,它隐藏了正在发生的事情,因此使函数的工作更加困难。我认为应该分解功能以提高可读性,而不是为了适应“完美的长度”。
Dominique McDonnell '12

6
@ Dominic,@Péter,我认为我们三个人实际上是在说同样的话。当有充分的理由将代码分解为较小的函数时,我是支持的。我所拒绝的是为了功能设计中的短性而设计的短性。您知道,调用栈比需要的长三倍,但是至少这些函数很短。我宁愿调试一个可以很好且清楚地完成一件事情的高个函数,而不是通过十二个链接的函数来追逐执行路径,每个链接函数只能从前一个函数中调用。
丹·雷

61
{ Let it Leak, people have good enough computers to cope these days }

更糟糕的是,这是来自商业图书馆!


32
这不会响起警钟。实际上,它可以将您踢到两腿之间。
史蒂文·埃弗斯

15
女儿是一个吸毒者。谁在乎,至少她不会变得肥胖。:: sigh ::
Evan Plaice 2010年

17
当我遇到麻烦时,邦图妈妈来找我。说到智慧的话,就让它泄漏。让它泄漏..让它​​泄漏。让它泄漏哦,让它泄漏。如果它只泄漏一次,那不是leaaaaaak。(如果您到目前为止阅读过,请+1)。我真的需要考虑脱咖啡因。
蒂姆·波斯特

13
“随着最后期限的临近,泄漏是我所能看到的,在某人耳语的地方,'写在C .. eeeeee !!!'中。”
chiurox 2010年

9
从前有两个操作系统。如果运行超过49天,则其中一个泄漏并坠毁,另一个则是完美的,并且可以永久运行。一个于1995年推出,是为了吸引巨大的同志,并被数以百万计的人使用-另一个从未出货,因为他们仍在检查它是否无错误。哲学和工程学是有区别的。
马丁·贝克特

53

注释非常冗长,以至于如果有英文编译器,它将可以编译并完美运行,但不会描述代码没有的任何内容。

//Copy the value of y to temp.
temp = y;
//Copy the value of x to y.
y = x;
//Copy the value of temp to x.
x = temp;

此外,如果代码遵循一些基本准则,则可以删除对代码的注释:

//Set the age of the user to 13.
a = 13;

15
有,它叫做COBOL :-)
Gaius

26
第二种情况不是最坏的情况。最坏的情况是:/ *将用户年龄设置为13 * / a = 18;
PhiLho

4
@PhiLho-不,更糟糕/*/是缺少时,因此将*/忽略所有到下一个结尾的代码。幸运的是,语法高亮使这种事情如今很少见了。
2010年

3
再说一次,a对于user_age?真?
glasnt 2011年

2
我曾经在以前的雇主那里维护过代码标准文档,其中一部分是适当的注释。我最喜欢的示例来自MSDN:i = i + 1; //increment i
Michael Itzoe 2012年

42

编译时产生警告的代码。


1
有一个候选者可以将“所有警告作为错误”编译器选项添加到makefile /项目中。
JBRWilkinson 2010年

3
我想如果您在一个由多个您根本不信任的人组成的项目中可能会很有用-尽管如果我加入一个设置了该选项的项目,那将使我自己担心另一个程序员。
宫阪丽

1
我不同意这一点。某些编译器警告(例如,有符号的和无符号的比较,当您知道两个值都是无符号的时,即使类型不同也是如此)比使用不必要的强制转换乱扔代码更可取。如果我使用可移植的有符号整数来减少代码,那么只有当整数具有无符号值时函数才会对其进行修改,我将这样做。
蒂姆·波斯特

13
我宁愿用几乎多余的内容来使我的代码混乱,也不愿(unsigned int)用良性警告来使我的警告/错误列表混乱。我不希望警告列表成为盲点。PITA还可以向其他人说明为什么您忽略警告,而不是说明您为什么要自然而然ints地表达unsigned ints
宫阪丽

有时,无论您做什么,都必须使用会产生错误的API。经典示例是在API被设计破坏的情况下定义的(一些旧的ioctl()常量就是这样,有时OS开发人员坚持在标头中使用错误的类型),或者在不推荐使用某些东西的情况下留下一个很好的替代品(Apple,谢谢您)。
Donal Fellows,

36

名称中带有数字而不是描述性名称的函数,例如:

void doSomething()
{
}

void doSomething2()
{
}

请让函数名称有意义!如果doSomething和doSomething2做类似的事情,请使用区分差异的函数名称。如果doSomething2是doSomething的功能突破,请为其功能命名。


同样,用于SQL的@Parm
Dave

2
+ mshtml
1-

3
GUI代码是一个例外。例如,如果一个蜗牛邮件表单有两个地址;地址1和地址2比地址和alternateAddress更合理。仅为静态的虚假标签也是一个合理的例外。
Evan Plaice

@Evan-足够公平,尽管我在功能上有所不同。
2011年

1
+1-我什至看到了它用作伪版本控制方法。
EZ哈特

36

魔术数字或魔术字符串。

   if (accountBalance>200) { sendInvoice(...); }

   salesPrice *= 0.9;   //apply discount    

   if (invoiceStatus=="Overdue") { reportToCreditAgency(); }

4
对于后两个而言,并没有那么糟糕,至少可以说明折扣,并且“过期”是直观的。的200,而另一方面...
塔尔卡

9
@Slokun-直观性不在于维护性和脆弱性。例如,考虑当折扣金额更改并且0.9在六个不同的地方硬编码时会发生什么。另外,使用字符串而不是常量/枚举在使用区分大小写的字符串的语言中会引起麻烦。
JohnFx 2010年

+1我只是花了太多时间来调试一个问题,该问题原来是由“ timeout = 15;”行引起的 埋在一个程序中。
aubreyrhodes 2010年

我认为有时最后一个可以,取决于invoiceStatus的数据来自何处。如果它只是来自返回解码后的JSON的公共api,则可以对硬编码的String常量进行检查。同意“ 200”和“ 0.9”只是魔术常数,不应以这种方式进行硬编码。即使仅在一个地方使用它们,如果在配置部分中分别定义它们而不是将它们散布在逻辑代码中,则维护起来也更容易。如果在多个地方使用它们,维护将变得更加容易。
李·李

36
  • 也许不是最坏的情况,但可以清楚地显示实现者级别:

    if(something == true) 
  • 如果一种语言具有for循环或迭代器构造,则使用while循环还可以演示实现者对该语言的理解程度:

    count = 0; 
    while(count < items.size()){
       do stuff
       count ++; 
    }
    
    for(i = 0; i < items.size(); i++){
      do stuff 
    }
    //Sure this is not terrible but use the language the way it was meant to be used.
  • 文档/注释中的拼写/语法不佳几乎和代码本身一样吃。这样做的原因是因为代码是供人类阅读和运行机器的。这就是为什么我们使用高级语言的原因,如果您的文档难以理解,则会使我在不看代码的情况下先发制人地对代码库形成负面意见。


29

我立即注意到的是深层嵌套的代码块(如果是,虽然是等)的频率。如果代码的深度经常超过两个或三个级别,则说明设计/逻辑问题。而且,如果它深入到8个巢穴,则最好有充分的理由使它不被分解。


6
我知道有人知道每种方法都应该只有一个return语句,但是当它导致6级以上的if / then嵌套时,我认为它的弊大于利。
达里安(Darien)

28

给学生的课程评分时,有时可以说出“眨眼”的时刻。这些是即时线索:

  • 格式不良或不一致
  • 连续超过两个空行
  • 非标准或不一致的命名约定
  • 重复代码,重复次数越多,警告越强烈
  • 一段简单的代码应该过于复杂(例如,以复杂的方式检查传递给main的参数)

我的第一印象很少是正确的,这些警告钟在大约95%的时间内是正确。一个例外是,该语言的新学员使用的是另一种编程语言的样式。挖掘并用另一种语言重新阅读他们的风格,这为我消除了警钟,然后学生获得了充分的信誉。但是这种例外很少见。

在考虑更高级的代码时,这是我的其他警告:

  • 许多 Java类的存在,它们只是用于保存数据的“结构”。无论这些字段是公共字段还是私有字段,以及使用获取方法/设置方法,都仍然不是经过深思熟虑的设计的一部分。
  • 名称不佳的类,例如只是一个名称空间,并且代码中没有真正的凝聚力
  • 引用代码中甚至没有使用的设计模式
  • 空的异常处理程序,无需解释
  • 当我在Eclipse中提取代码时,代码中有数百个黄色的“警告”,主要是由于未使用的导入或变量

在样式方面,我通常不喜欢看到:

  • 仅回显代码的Javadoc注释

这些只是错误代码的线索。有时看似不好的代码实际上不是,因为您不了解程序员的意图。例如,可能有一个很好的理由,即某些事情看起来过于复杂-可能还有其他考虑因素在起作用。


我看不到从一种语言到另一种语言使用样式是多么严重的错误(每个缩进2、4、8个空格...)。如果学生没有其他可遵循的风格,那么自洽就没有错。作为分级员,您会看到十亿个程序,因此您处于另一端,但这并不是完全放弃另一种(但始终如一)风格的原因。
尼克T

18
我认为只聚合数据的类(即结构)没有错。这就是数据传输对象(DTO)的功能,它可以使代码比说的更具可读性,例如,将20个参数传递给方法。

1
您对struct的评论已到位。如果数据为原始格式,则不会有任何修改,这很好。但是95%的时间中,您应该在类中具有一些函数来格式化/操作数据。我只记得我的一些代码基本上使用了这种模式,应该加以改进。
DisgruntledGoat 2010年

2
+1表示不一致的样式和多余的换行符(我见过随机的缩进,没有缩进,随机的和不断变化的命名约定以及更多-以及在生产代码中!)。如果您什至不愿意做正确的事,那么您还能做什么呢?
迪恩·哈丁

1
我正在寻找相对于主体缩进太远的方法的声明行。这是他们从其他人的文件中复制粘贴的标志。
巴里·布朗

25

个人喜好/宠爱:IDE生成的名称被使用。如果TextBox1是系统中的主要变量,那么代码审查就会给您带来另一件事。


25

完全未使用的变量,尤其是当变量的名称类似于所使用的变量名称时。


21

很多人提到:

//TODO: [something not implemented]

虽然我希望这些东西得到实施,但至少他们做了一个说明。我认为更糟糕的是:

//TODO: [something that is already implemented]

如果您从未想过将它们删除,那么Todo毫无价值,而且会造成混淆!


1
我刚刚经历了必须在发布产品中生成所有TODO报告的练习,以及存储它们的计划。近一半被淘汰。
AShelly

1
-1 TODO注释在MS Visual Studio中用于跟踪项目中仍需要工作的部分。IE,IDE保留了一个跟踪TODO的列表,因此您可以轻松地单击它们并将其直接带到TODO所在的行。我希望看到TODO明确放置,以查看仍需要完成哪些工作。请参阅dotnetperls.com/todo
Evan Plaice 2010年

3
@Evan Plaice:哇,您的意思是VS IDE识别出实现了某些内容并删除了//TODO注释?太棒了!
JBRWilkinson 2010年

4
@Prof Plum为什么不创建一个政策,将TODO负责人的姓名放在注释中。这样,如果有剩余的食物
Evan Plaice

3
比更好的计划// TODO ,使用您的bug跟踪器,这就是它的目的!
SingleNegationElimination

20

需要我向下滚动才能阅读所有内容的方法。


14
嗯..这取决于正在实施的内容。当实现一些复杂算法时,发生这种情况并非不合理,因为这是它们的定义方式。当然,如果大多数方法都是那样,那就是一个危险信号。
Billy ONeal

9
作为一个笼统的声明,我不同意,浪费时间不断进行重构,以使所有内容都符合这种自我施加的规则,这实际上增加了项目的总体成本。
匿名类型

1
我不同意该规则会增加项目的总体成本,但是我认为这是主观的,因为它取决于开发人员。如果在开发过程中遵循“关注点分离”的一般原则,那么如果选择这样做,那么重构将不是一件容易的事。需要考虑的一点是,如果没有编写原始项目的开发人员试图用300余行代码来修正一堆方法,那么三年下来要花多少钱?费用多少?
BradB

18
向右滚动比向下滚动更让我烦恼。空格是“免费的”。
桑科旺科(Wonko the Sane),2010年

4
我宁愿滚动,也不必跳过整个文件(或多个文件)以弄清楚代码在做什么。
TMN 2010年

20

方法名称中的连词:

public void addEmployeeAndUpdatePayrate(...) 


public int getSalaryOrHourlyPay(int Employee) ....

说明:敲响警钟的原因是它表明该方法可能违反了单一责任原则


嗯...如果函数名称准确地定义了函数的功能,那么我不同意。如果该方法将两件事分开做,最好将它们分开,那么我可能会同意,具体取决于上下文。
桑科旺科(Wonko the Sane),2010年

2
这才是重点。连词暗示它很可能做不止一件事。根据每个问题,这只是使我意识到某些事情可能是错误的事情。
JohnFx 2010年

3
现在,如果您必须在多个地方添加一名雇员并更新他们的薪水,该怎么办?如果该方法包含两个方法调用(addEmployee(); updatePayrate();),那么我认为这不是问题。
马特·格兰德

13

将GPL的源代码链接到一个商业的,封闭源代码的程序中。

它不仅造成了直接的法律问题,而且根据我的经验,它通常表示粗心或无关紧要,这也反映在代码的其他地方。


6
尽管您的观点很好,但您的语气是不必要的。
JBRWilkinson 2010年

@JBRWilkinson:谢谢,你是对的。我向所有人道歉。
鲍勃·墨菲

我认为您的标题需要重写。静态和动态链接到GPL的源代码都违反了GPL ...
Gavin Coates

好点。我已经重写了整个帖子。谢谢大家。
鲍勃·墨菲

9

语言不可知:

  • TODO: not implemented
  • int function(...) { return -1; } (与“未实施”相同)
  • 由于非异常原因而引发异常。
  • 滥用或不一致使用0-1null作为特殊的返回值。
  • 断言没有令人信服的评论说为什么它永远不会失败。

特定语言(C ++):

  • 小写的C ++宏。
  • 静态或全局C ++变量。
  • 未初始化或未使用的变量。
  • 任何array new显然不安全的RAII。
  • 显然不是边界安全的数组或指针的任何使用。这包括printf
  • 数组未初始化部分的任何使用。

特定于Microsoft C ++:

  • 与任何Microsoft SDK头文件已定义的宏冲突的任何标识符名称。
  • 通常,对Win32 API的任何使用都会引起很大的警钟。始终打开MSDN,并在有疑问时查找参数/返回值定义。(已编辑)

特定于C ++ / OOP:

  • 实现(具体类)继承,其中父类同时具有虚拟和非虚拟方法,而在应该/不应该虚拟之间没有明显的明显概念区别。

18
// TODO:对此答案发表评论
johnc

8
我猜“不可知的语言”现在意味着“ C / C ++ / Java”吗?
Inaimathi 2010年

+1“因非异常原因而引发异常”完全不同意!
billy.bob 2010年

2
@Inaimathi-TODO注释,函数存根,异常滥用,零/空/空语义的混淆以及毫无意义的健全性检查是所有命令式/ OOP语言以及在某种程度上通常是所有编程语言所固有的。
宫阪丽

我相信,小写的C预处理程序宏可以的,但前提是它们仅对参数进行一次评估并且仅产生一条语句。
乔D

8

奇异的缩进样式。

有两种非常流行的样式,人们会将这场辩论推向高潮。但是有时候我看到有人使用一种非常罕见的,甚至是一种自家的缩进样式。这表明他们可能没有与自己以外的任何人进行编码。


2
或只是表明他们是一个非常受尊敬的个人主义天才,而没有被与“最佳实践”无关的同质编码实践网络所吸引。
匿名类型

1
我希望你在讽刺。如果有人以这种不寻常的方式编码,那应该引起警钟。它们可以随心所欲地具有艺术性,但仍然...警钟。
肯(Ken)

2
尽管在Haskell / ML / F#之外极为罕见,但我发现有一种非常罕见的样式(我相信它称为Utrecht样式)非常有用。向下滚动至“模块形状”:learningyouahaskell.com/making-our-own-types-and-typeclasses。这种样式的优点在于,您不必修改前一行的定界符即可添加新的定界符-我经常忘记这样做。
宫阪丽

@ReiMiyasaka已经晚了七年,但是...乌特勒支的风格真的让我很生气。我相信,在Haskell规范中不对垂直组织的列表强加另一个“布局规则”是一个错误。这样,解析器仅通过检查缩进就可以检测到新的列表条目,这就是每个人反正组织其列表的方式。
瑞安·赖希

@RyanReich Weird,七年后,我仍然喜欢它。不过,我同意;对于所有语法上的尴尬和失败,F#还允许仅用换行符和缩进符来分隔项目(在大多数情况下),这使得代码整洁。
宫阪丽

8

使用大量文本块,而不是枚举或全局定义的变量。

不好:

if (itemType == "Student") { ... }

更好:

private enum itemTypeEnum {
  Student,
  Teacher
}
if (itemType == itemTypeEnum.Student.ToString()) { ... }

最好:

private itemTypeEnum itemType;
...
if (itemType == itemTypeEnum.Student) { ... }

或最佳:使用多态性。
Lstor

8

弱类型的参数或方法的返回值。

public DataTable GetEmployees() {...}

public DateTime getHireDate(DataTable EmployeeInfo) {...}

public void FireEmployee(Object EmployeeObjectOrEmployeeID) {...}

2
+1:我必须使用一些“ REST” Web服务,这些服务以伪HTML表的形式返回所有内容,即使您传递的是明显的语法错误。未经授权?输入完整的垃圾?服务器容量过大?200(在一列,一个行表中加上可怕的消息)。AAaaaaaaaargh!
Donal Fellows,

7
  • 多个三元运算符串在一起,因此它不再像一个if...else块,而是变成一个if...else if...[...]...else
  • 长变量名,不带下划线或驼峰。我从一些代码中提取了示例:$lesseeloginaccountservice
  • 文件中的几百行代码,几乎没有注释,并且代码非常不明显
  • 过于复杂的if陈述。代码示例:if (!($lessee_obj instanceof Lessee && $lessee_obj != NULL))我砍掉了if ($lessee_obj == null)

7

代码气味:不遵循最佳做法

这种事情总是让我感到担忧,因为有人认为每个人都认为自己是高于平均水平的司机。

这是您的新闻快讯:世界上50%的人口智力水平低于平均水平。好的,所以有些人的智力完全是平均的,但是我们不要挑剔。另外,愚蠢的副作用之一是您无法识别自己的愚蠢!如果结合使用这些语句,事情看起来就不会那么好。

查看代码时,哪些事情会立即敲响警钟?

已经提到了很多好东西,并且通常来说,不遵循最佳实践是一种代码味道。

最佳做法通常不是随机发明的,并且经常是有原因的。很多时候它可能是主观的,但以我的经验,它们大多数都是合理的。遵循最佳做法应该不是问题,如果您想知道为什么会这样,请研究它而不是无视和/或抱怨它-也许是有道理的,也许不是。

最佳做法的一个示例可能是在每个if块中使用curly,即使它仅包含一行:

if (something) {
    // whatever
}

您可能没有必要,但我最近读到它是错误的主要来源。始终使用括号也已经在讨论堆栈溢出,并检查if语句有括号也是规则PMD,静态代码分析器为Java。

请记住:“因为这是最佳做法”,对于“您为什么要这样做?”这个问题永远是无法接受的答案。如果您无法阐明为什么某事是最佳实践,那么它不是最佳实践,那是一种迷信。


2
这可能很花哨,但我认为您选择的平均水平很重要。据我了解,世界人口的50%低于智力中位数(根据定义);但其他平均值却无法以相同的方式运作。例如采取人口(1,1,1,5),其具有为2的算术平均值
flamingpenguin

嗯,您引用了“ What-superstitions-do-programmers-have”一文,其中用户对没有花括号的花括号做了一个大胆的声明。我认为这并不是最佳做法的典范。
Evan Plaice 2010年

@Evan:是的,你是对的。我对此添加了更多信息,希望对您有所帮助。
Vetle

4
不利的一面是那些热心遵循“最佳实践”的人,而对为什么某事物是“最佳实践”却没有任何批评。这就是为什么我强烈不喜欢“最佳实践”一词的原因,因为对于某些人来说,这是一个停止思考并追随人群的借口。对于“为什么要这样做?”这个问题,从来没有一个可以接受的答案“因为这是最佳实践”。如果您无法阐明为什么某事是最佳实践,那么它不是最佳实践,那是一种迷信。
Dan Dyer 2010年

很好的评论,丹!我在答案中添加了最后两行。
Vetle

6

说“这是因为froz子系统的设计完全令人厌烦”。

这贯穿了整个段落。

他们解释说,需要进行以下重构。

但是没有做到。

现在,由于时间或能力方面的问题,他们当时可能已经被老板告知他们不能更改它,但这也许是因为人们太小了。

如果主管认为是j.random。程序员无法进行重构,那么主管应该这样做。

无论如何,我知道代码是由一支分散的团队编写的,具有可能的权力策略,并且他们没有重构沉闷的子系统设计。

真实的故事。它可能发生在您身上。


6

谁能想到一个示例,其中代码应通过绝对路径合法地引用文件?


1
XML模式算不算?
尼克T 2010年

1
系统配置文件。通常应通过./configure进行设置,但即使这样也需要在某个地方使用默认值。
eswald

4
/dev/null和朋友都可以。但是,即使这样的事情/bin/bash也是可疑的-如果您是一个具有某些古怪的系统/usr/bin/bash呢?
汤姆·安德森

1
由JAX-WS工具(至少JBossWS和Metro)生成的Web服务客户端代码包含WSDL文件的硬连线绝对路径(两次!)。这可能是非常不合适的/home/tom/dev/randomhacking/thing.wsdl。这是默认行为,这在犯罪上疯狂的
汤姆·安德森

4
关于/dev/null:我有一个习惯,在Windows上进行开发时,将应用程序和库保存在之下c:\devnull总是以某种方式在该文件夹内自动创建一个文件夹。我发誓我不知道是谁做的。(我最喜欢的错误/功能之一)
肖恩·帕特里克·弗洛伊德

6

捕获一般异常:

try {

 ...

} catch {
}

要么

try {

 ...

} catch (Exception ex) {
}

区域过度使用

通常,使用太多区域向我表明您的课程太大。这是一个警告标志,表示我应该进一步研究该代码段。


仅当您不执行任何操作就将其抛出时,捕获常规异常才是问题。实际上,对于大多数事情来说,一个异常类就足够了。我倾向于使用runtime_error。
CashCow 2011年

对于“捕获并丢弃异常”示例为+1。如果您没有采取任何例外措施,请不要抓住它。至少要记录下来。至少,至少要添加注释,以解释为什么可以捕获所有异常并在代码的这一点继续前进。
EZ哈特

5

类命名约定表明对他们试图创建的抽象的理解不足。或根本不定义抽象。

在一个VB类中,我想到了一个极端的例子Data,在第一个文件中,该类的标题为30,000+行。这是一个局部类,分为至少六个其他文件。大多数方法都是使用名称为的存储过程包装程序FindXByYWithZ()

即使没有那么生动的例子,我也确信我们所有人都只是将逻辑“倾销”到了一个构思欠佳的类中,给了它一个完全通用的标题,后来又后悔了。


5

重新实现语言基本功能的功能。例如,如果您曾经在JavaScript中看到过“ getStringLength()”方法,而不是对字符串的“ .length”属性的调用,则说明您遇到了麻烦。


5
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...

当然没有任何类型的文档,偶尔会有嵌套的#defines


昨天,我在生产代码中完全看到了这种“模式”……甚至在C ++生产代码中更糟……://
Oliver Weiler 2010年
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.