Coding style 防御性编码实践

Coding style 防御性编码实践,coding-style,Coding Style,自从我第一次写 if ($a = 5) { # do something with $a, e.g. print "$a"; } 并经历了正常的令人困惑的会议 为什么结果总是正确的 为什么一美元总是5美元 直到我意识到,我将5分配给$a,而不是进行比较 所以我决定把上面的条件写成 if (5 == $a) 换言之: 如果忘记添加第二个“=”号,请始终将常量值放在比较运算符的左侧,从而导致编译错误。 我倾向于称之为防御性编码,并倾向于认为它是防御性编程的近亲,不是在算法规模

自从我第一次写

if ($a = 5) {
   #  do something with $a, e.g.
   print "$a";
}
并经历了正常的令人困惑的会议

  • 为什么结果总是正确的
  • 为什么一美元总是5美元
直到我意识到,我将5分配给$a,而不是进行比较

所以我决定把上面的条件写成

 if (5 == $a)
换言之:

如果忘记添加第二个“=”号,请始终将常量值放在比较运算符的左侧,从而导致编译错误。

我倾向于称之为防御性编码,并倾向于认为它是防御性编程的近亲,不是在算法规模上,而是逐字逐句

您开发了哪些防御性编码实践


一周后:

对所有回答的人或将来可能添加另一个答案的人说一声“谢谢”


不幸的是(或者更幸运的是!)没有单一的正确答案。因此,我的问题非常广泛,更多地询问意见或经验教训,而不是事实

这是一个简单而明显的例子,但我从来没有在我的代码中重复同一个字符串常量两次,因为我知道如果我这样做,我将拼写其中一个错误:)请使用常量,各位

我不再使用你可以使用的语言了

if a = 5: print a
这帮我省去了很多麻烦


更严肃地说。。。现在,我总是在编写
if
s和
for
循环后立即编写花括号,然后再填充它们。这样可以确保我的括号始终对齐。

始终在if/for/while之后放上大括号。。。即使后面只有一句话。顺便说一句,Crockford也认为这样更好:

返回可变对象的副本,即数组的副本,而不是可变对象本身。

始终使用大括号:

if(boolean)
    oneliner();
nextLineOfCode();
不同于:

if(boolean)
{
    oneliner();
}
nextLineOfCode();

如果oneliner()是一个#定义的函数,但没有定义它,那么您的下一行代码就会突然受制于If()。同样的事情也适用于带有大括号的for循环等,那么下一段代码决不会无意中成为if/for等的条件。

我采用的前三种防御性编码实践是

  • 单元测试
  • 单元测试
  • 单元测试
  • 对于代码质量来说,最好的防御措施莫过于一个好的单元测试来支持您。

    避免不必要的测试。 范例

  • if(bool==true)
  • 指针检查(指针)
  • 编辑: if(指针)不可读,所以现在我更喜欢if(NULL!=指针)

    两件事:

    • 是的,单线区段。使用大括号。。。见鬼,大多数好的IDE都会为你制作它们
    • 在编写代码后对其进行注释,如果您提前完成了,则重新阅读注释。确保您的代码仍然符合注释所述
    • 单元测试是重读代码的一个很好的退路
    • 总是记录一个异常。。。或者,至少在调试过程中,不要在没有说明的情况下捕获异常
        • 始终初始化变量
        • 尽可能使用
          const
          (不使用
          mutable
        • 避免动态分配内存或其他资源
        • 始终使用大括号
        • 在编码实现之前,为任何类编写用例和测试代码
        • 打开尽可能多的有用警告(
          -Wall-Wextra-ansi-pedantic-Werror
        • 使用解决问题的最简单工具(在我当前的环境中,就是
          bash
          ->
          grep
          ->awk->Python->C++)

          • 就我个人而言,我不喜欢这种防御性风格,它使代码难以阅读

            VC编译器警告级别4将发现此(可能)错误。
            “警告C4706:条件表达式内的赋值”

            您可以在任何级别仅启用此特定编译器警告:

            #pragma warning(3,4706)
            

            将字符串与常量进行比较时,请写入

            if ("blah".equals(value)){}
            
            而不是

            if (value.equals("blah")){}
            

            以防止NullPointerException。但这是我唯一一次使用建议的编码风格(因为“if(a=1)…”在Java中是不可能的)。

            在Javascript世界中,我总是试图记住的一件事是始终在返回关键字所在的同一行上启动函数的返回值

            function one(){
                return {
                    result:"result"
                };
            }
            
            function two(){
                return 
                {
                    result:"result"
                };
            }
            
            这两个函数将不会返回相同的值。第一个函数将返回一个属性results设置为“result”的对象。第二个函数将返回
            未定义的
            。这是一个非常简单的错误,这是因为Javascript过于热衷于分号插入策略。分号在Javascript中是半可选的,因此Javascript引擎将在它认为应该添加分号的地方添加分号。因为
            return
            实际上是一个有效的语句,所以在return语句之后会插入一个分号,函数的其余部分基本上会被忽略。

            来自我的博客:

          • 积极思考,尽早返回,避免深度嵌套。而不是

            if(值!=null){ …做一些有价值的事情。。。 } 返回

            如果(值==null){ 返回 } ... 做一些有价值的事情

          • 避免使用“字符串常量”(即同一文本在多个引号中)。始终定义一个实常量(带有名称和可选注释,说明其含义)并使用它

          • 已安装的Resharper;)
            如果我做错了什么,我就不需要写“5==a”来得到警告:)

            在embedded.com上的文章中,有几条关于嵌入式C编程的建议。

            我同意。。。但在这个不太完美的世界里,编程语言的选择不是我的……我想,如果我能记住这样做,我就能记住==(遗憾的是)我不喜欢对正常思路的冲击;我不是在测试5美元,我是在测试一美元。我发现如果先列出要测试的数量会更容易。也许我是少数,但我不喜欢这种技术,尽管它是推荐的