我个人十分不喜欢加很多log。
大家都知道,写代码最怕的是context switch,比如在代码编辑器tab间来回跳转,不停的在代码编辑器tab页上滚上滚下,这就是所谓的distraction。
log也一样,你每加一行log,你就把代码以你这行log为中心,分成了上下两部分,原来可以如行云流水般阅读的代码,当读到你这行log的时候,读者也不得不顿一顿,就如同手机撸到一半卡壳一般,等你看懂这行其实是条log,再回来想看下面的code,又要花费个几秒钟重新load之前的context。几秒钟看似不长,但如果出现次数多了,比如几百,几千次,累加起来对生产力的影响威力惊人。
这里面的root cause是,log本身不属于业务逻辑,当你在一段完整的code里插入log的时候,等于是你的log把这段完整的逻辑给打散了。readability hurts。
我个人也十分不喜欢太多的defensive programming。在一个method的开头check这个check那个。这些check,都不属于业务逻辑。很多时候其实我method本身的逻辑没几行,前面的check却占了几十行,也就是说,在我read 这个method的时候,我浪费了大部分时间来read这些业务逻辑无关的code,而read code的目的不是为了了解你怎么check parameters,而是要了解业务逻辑。readability hurts。
个人认为,经过精心design和test的代码,只需在输入那里做defensive programming,在你自己写的模块内部,用test而不是defensive来保证质量。
defensive programming和try catch,往往被用的无脑化,不管三七二十一,每个method开头我就defensive一把,每个method我都用try catch一包。但问题是,假设你的defensive或者try block检测到了一个问题,那么你能在你的catch里处理吗?很多人只是无脑化的机械的用这些pattern,但是没有考虑过当在你的这个method里你要check的一个问题真的发生的时候,你的这个method是否真的能handle这个问题,如果你的method不能handle而要throw到上一层去handle,那么你这些defensive还有什么用呢,反而你需要在上一层加try catch而不是在这一层加。
代码里很多无用的try catch,catch住了以后只是打一行log然后继续throw上去,那么为什么不在能处理这个exception的某个上层catch住只打一次log就行了呢?一个try catch加上大括号占据了6行,你一个屏幕能显示多少行?屏幕这么宝贵的资源不能省着点用吗,难道你想来回拖滚动条造成context switch吗? readability hurts。
这里借用猫哥的一句话: “Code is read far more than it's written.”,再怎么做trade off,readability不能trade off。
最后,log的根本目的是用来debug程序,不然怎么会有logLevel=Error,Warning,Information这种区分呢。debug程序主要是找出哪一次运行给系统造成了问题,此时在log里加上什么trackingID之类的东西就非常必要了。
如果系统有performance问题,那么需要的不是log,而是一个monitoring system。可问题是很多人把log用成了monitoring system。
当我们看performance问题的时候,我们其实并不关心单次的某个method跑的时间或者CPU占用率,我们关心的是在总体上这个method跑的情况怎么样,此时就有average elapsed time,max elapsed time,min elapsed time, 75% tile elapsed time这些指标。然而这些指标都是基于某个时间段的这个method的运行情况来统计的。所以看performance的时候,用来debug单次method执行的trackingID并没有什么用。
所以log和monitoring system并不是一回事,当你在debug log里只加上简单的时间信息把它当成performance log来用的时候,这样的log是简陋的,你并没有用相关的performance API来记录数据,你没有最大化这条log的功效,记一条log需要IO,代价是很贵的,不最大化它的功效,你就浪费了资源。而对于debug purpose来讲,这样的log又太冗余了,很多字段和debug issue没什么关系。
所以,如果没有monitoring system,至少也要把debug purpose的log和performance purpose的log分成2种不同的log来实现。
网友评论