32 答疑(三):如何选择合适的异常处理方式? 你好,我是景霄。

不知不觉中,我们又一起完成了第三大章规范篇的学习。我非常高兴看到很多同学一直在坚持积极地学习,并且留下了很多高质量的留言,值得我们互相思考交流。也有一些同学反复推敲,指出了文章中一些表达不严谨或是不当的地方,我也表示十分感谢。

大部分留言,我都在相对应的文章中回复过了。而一些手机上不方便回复,或是很有价值很典型的问题,我专门摘录了出来,作为今天的答疑内容,集中回复。

问题一:应该使用哪种异常处理方式?

第一个问题是code2同学的疑惑。下面这两种处理的风格,哪一种风格更有效、更优雅?

  • 第一种,在代码中对数据进行检测,并直接处理与抛出异常。
  • 第二种,在异常处理代码中进行处理。

其实,第一种方法,可以翻译成下面的“if…elif…”语句: if [condition1]: raise Exception1(‘exception 1’) elif [condition2]: raise Exception2(‘exception 2’) …

而第二种方法,则对应着下面异常处理的代码:

try: … except Exception as e: …

这两种方法很大的一个区别是,第一种方法一旦抛出异常,那么程序就会终止;而在第二种方法中,如果抛出异常,会被程序捕获(catch),程序还会继续运行。这也是我们选择这两种方法的重要依据。当然,在实际工作中,到底使用哪一种方法,还是取决于具体的场景。

比方说,一个模块的功能是对输入进行检测,如果输入不合法,则弹出对话框进行提示,并终止程序。那么,这种情况下,使用第一种方法更加合理。

但是,如果换成一个产品的服务器端,它需要应对各种可能发生的情况,以保证服务器不崩溃。比如在连接数据库时,如果网络异常,无法连接,那就需要捕获(catch)这个异常(exception),进行记录,并同时保证其他功能不受影响。这种情况下,我们通常会选择第二种方式。

问题二:先写出能跑起来的代码,后期再优化可以吗?

第二个问题,夜路破晓同学提到了很多程序员传授的“经验之谈”,即先写出能跑起来的代码,后期再优化。很明显,这种认知是错误的。我们从一开始写代码时,就必须对功能和规范这两者双管齐下。

代码功能完整和规范完整的优先级是不分先后的,应该是同时进行的。如果你一开始只注重代码的功能完整,而不关注其质量、规范,那么规范问题很容易越积越多。这样就会导致产品的bug越来越多,相应的代码库越发难以维护,到最后不得已只能推倒重来。

我在Facebook工作时就遇到过这样的情况,参与过类似的项目。当时,某些功能模块因为赶时间,code review很宽松,代码写得很不规范,留下了隐患。时间一长,bug越来越多,legacy越来越多。到最后,万分无奈的情况下,我们几个工程师专门立项,花了三个多月时间,重写了这一模块的代码,才解决了这个问题。

问题三:代码中写多少注释才合适?

第三个问题,小侠龙旋风同学留言说,自己的同事要求代码中有70%的注释,这显然有点过了。但是反过来说,如果你的代码中没有注释或者注释很少,仅凭规范的变量名肯定是远远不够的。

通常来说,我们会在类的开头、函数的开头或者是某一个功能块的开头加上一段描述性的注释,来说明这段代码的功能,并指明所有的输入和输出。除此之外,我们也要求在一些比较tricky的代码上方加上注释,帮助阅读者理解代码的含义。

总的来说,代码中到底需要有多少注释,其实并没有一个统一的要求,还是要根据代码量和代码的复杂度来决定。不过,我们平常书写时,只要满足这样的规范就可以了。

另外,必须提醒一点,如果在写好之后修改了代码,那么代码对应的注释一定也要做出相应的修改,不然很容易造成“文不对题”的现象,给别人也给你自己带来困扰。

问题四:项目的API文档重要吗?

第四个问题,是未来已来同学的留言。他提到了项目的API文档的问题,这一点说得非常好,在这里我也简单介绍一下。

我在专栏中主要讲的是代码的规范问题,但很多情况下,光有规范的代码还是远远不够的。因为一个系统,一个产品,甚至一个功能模块的代码,都有可能非常复杂。少则几千行,动辄几十万行,尤其是对于刚加入的新人来说,在ramp up阶段光看代码可能就是一个噩梦了。

因此,在这方面做得比较规范的公司,通常也会要求书写文档。项目的文档,主要是对相应的系统、产品或是功能模块做一个概述,有助于后人理解。以一个service为例,其对应的文档通常会包括下面几部分:

  • 第一点,系统的概述,包括各个组成部分以及工作流程的介绍;
  • 第二点,每个组成部分的具体介绍,包括必要性、设计原理等等;
  • 第三点,系统的performance,包括latency等等参数;
  • 第四点主要说明如何对系统的各个部分进行修改,主要给出相应的code pointer及对应的测试方案。

这些内容,也希望屏幕前的你能够牢记。

今天我主要回答这些问题,同时也欢迎你继续在留言区写下疑问和感想,我会持续不断地解答。希望每一次的留言和答疑,都能给你带来新的收获和价值。

参考资料

https://learn.lianglianglee.com/%e4%b8%93%e6%a0%8f/Python%e6%a0%b8%e5%bf%83%e6%8a%80%e6%9c%af%e4%b8%8e%e5%ae%9e%e6%88%98/32%20%e7%ad%94%e7%96%91%ef%bc%88%e4%b8%89%ef%bc%89%ef%bc%9a%e5%a6%82%e4%bd%95%e9%80%89%e6%8b%a9%e5%90%88%e9%80%82%e7%9a%84%e5%bc%82%e5%b8%b8%e5%a4%84%e7%90%86%e6%96%b9%e5%bc%8f%ef%bc%9f.md