条件记录具有最小的复杂度 [英] Conditional logging with minimal cyclomatic complexity

查看:184
本文介绍了条件记录具有最小的复杂度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读您是什么/对圈复杂度的良好限制? a>,我发现我的很多同事对这个新的 QA 政策感到非常恼火项目:每个功能不再有10个圈复杂度

After reading "What’s your/a good limit for cyclomatic complexity?", I realize many of my colleagues were quite annoyed with this new QA policy on our project: no more 10 cyclomatic complexity per function.

含义:不超过10个'if','else','try','catch'等代码工作流分支语句。对。正如我在您是否测试私人方法中解释的,此类政策有很多好的副作用。

Meaning: no more than 10 'if', 'else', 'try', 'catch' and other code workflow branching statement. Right. As I explained in 'Do you test private method?', such a policy has many good side-effects.

但是:在我们(200人 - 7年)项目的开始,我们很高兴地记录(不,很容易将其委托给某种类型的面向方面的编程日志方法)。

But: At the beginning of our (200 people - 7 years long) project, we were happily logging (and no, we can not easily delegate that to some kind of 'Aspect-oriented programming' approach for logs).

myLogger.info("A String");
myLogger.fine("A more complicated String");
...

当我们的系统的第一个版本上线时,内存问题不是因为日志记录(这是在一个点关闭),而是因为日志参数(字符串),总是计算,然后传递到'info() 'fine()'函数,只发现日志记录级别为OFF,并且没有日志记录。

And when the first versions of our System went live, we experienced huge memory problem not because of the logging (which was at one point turned off), but because of the log parameters (the strings), which are always calculated, then passed to the 'info()' or 'fine()' functions, only to discover that the level of logging was 'OFF', and that no logging were taking place!

QA回来了,程序员做条件记录。总是。

So QA came back and urged our programmers to do conditional logging. Always.

if(myLogger.isLoggable(Level.INFO) { myLogger.info("A String");
if(myLogger.isLoggable(Level.FINE) { myLogger.fine("A more complicated String");
...

但是,现在,由于每个函数限制的循环复杂度水平,他们认为他们在函数中放置的各种日志被认为是负担,因为每个if(isLoggable())被计为+1循环复杂度!

But now, with that 'can-not-be-moved' 10 cyclomatic complexity level per function limit, they argue that the various logs they put in their function is felt as a burden, because each "if(isLoggable())" is counted as +1 cyclomatic complexity!

因此,如果一个函数有8'if','else'一个紧密耦合的不容易共享的算法和3个关键日志操作...它们违反了限制,即使条件日志可能不是真的部分的该函数的复杂性...

So if a function has 8 'if', 'else' and so on, in one tightly-coupled not-easily-shareable algorithm, and 3 critical log actions... they breach the limit even though the conditional logs may not be really part of said complexity of that function...

您将如何解决这种情况?

我在我的项目中看到了一些有趣的编码演变(由于冲突),我只想先得到你的想法。

How would you address this situation ?
I have seen a couple of interesting coding evolution (due to that 'conflict') in my project, but I just want to get your thoughts first.

感谢所有的答案。

必须坚持,问题不是'格式化'相关,而是'参数评估'相关(评价可能是非常昂贵的,只是在调用一个方法,什么也不做)。

所以当一个A String,我其实是指一个Function(),一个函数()返回一个字符串,并调用一个复杂的方法收集和计算所有类型的日志数据,要显示的日志记录...或没有(因此问题和义务使用条件日志记录,因此人为增加圈复杂度的实际问题...)

Thank you for all the answers.
I must insist that the problem is not 'formatting' related, but 'argument evaluation' related (evaluation that can be very costly to do, just before calling a method which will do nothing)
So when a wrote above "A String", I actually meant aFunction(), with aFunction() returning a String, and being a call to a complicated method collecting and computing all kind of log data to be displayed by the logger... or not (hence the issue, and the obligation to use conditional logging, hence the actual issue of artificial increase of 'cyclomatic complexity'...)

获取您的某些人提出的变化功能点(感谢约翰)。

注意:java6中的快速测试显示我的 varargs函数在被调用之前会对其参数进行求值,因此它不能应用于函数调用,但是对于Log Retriever对象(或函数包装器),toString如果需要调用。

I now get the 'variadic function' point advanced by some of you (thank you John).
Note: a quick test in java6 shows that my varargs function does evaluate its arguments before being called, so it can not be applied for function call, but for 'Log retriever object' (or 'function wrapper'), on which the toString() will only be called if needed. Got it.

我已经张贴了我对这个主题的经验。

我会留在那里,直到下星期二投票,然后我会选择

再次感谢所有建议:)

I have now posted my experience on this topic.
I will leave it there until next Tuesday for voting, then I will select one of your answers.
Again, thank you for all the suggestions :)

推荐答案

在Python中将格式化的值作为参数传递到日志记录函数。仅当启用日志记录时才应用字符串格式化。仍然有一个函数调用的开销,但是这是格式化比较小。

In Python you pass the formatted values as parameters to the logging function. String formatting is only applied if logging is enabled. There's still the overhead of a function call, but that's minuscule compared to formatting.

log.info ("a = %s, b = %s", a, b)

参数(C / C ++,C#/ Java等)。

You can do something like this for any language with variadic arguments (C/C++, C#/Java, etc).

很难检索,但是当格式化它们到字符串是昂贵的。例如,如果您的代码中已经有一个数字列表,您可能想要记录该列表进行调试。执行 mylist.toString()将需要一段时间没有什么好处,因为结果会被丢弃。因此,您将 mylist 作为参数传递给logging函数,并让它处理字符串格式化。

This isn't really intended for when the arguments are difficult to retrieve, but for when formatting them to strings is expensive. For example, if your code already has a list of numbers in it, you might want to log that list for debugging. Executing mylist.toString() will take a while to no benefit, as the result will be thrown away. So you pass mylist as a parameter to the logging function, and let it handle string formatting. That way, formatting will only be performed if needed.

由于OP的问题特别提到Java,所以上面的例子可以使用:

Since the OP's question specifically mentions Java, here's how the above can be used:


我必须坚持认为问题不是格式化相关,而是参数评估

I must insist that the problem is not 'formatting' related, but 'argument evaluation' related (evaluation that can be very costly to do, just before calling a method which will do nothing)

诀窍是有对象不会执行昂贵的计算,直到绝对需要。这在像Smalltalk或Python这样的支持lambda和closed的语言中很容易,但是仍然可以在Java中用一点想象力来实现。

The trick is to have objects that will not perform expensive computations until absolutely needed. This is easy in languages like Smalltalk or Python that support lambdas and closures, but is still doable in Java with a bit of imagination.

假设你有一个函数 get_everything()。它将从数据库中检索每个对象到一个列表中。你不想调用这个,如果结果将被丢弃,显然。因此,不是直接调用该函数,而是定义一个内部类 LazyGetEverything

Say you have a function get_everything(). It will retrieve every object from your database into a list. You don't want to call this if the result will be discarded, obviously. So instead of using a call to that function directly, you define an inner class called LazyGetEverything:

public class MainClass {
    private class LazyGetEverything { 
        @Override
        public String toString() { 
            return getEverything().toString(); 
        }
    }

    private Object getEverything() {
        /* returns what you want to .toString() in the inner class */
    }

    public void logEverything() {
        log.info(new LazyGetEverything());
    }
}

在此代码中,调用 getEverything()被包装,所以它不会被实际执行,直到它需要。只有在启用调试的情况下,日志功能才会对其参数执行 toString()。这样,你的代码只会受到函数调用而不是完整的 getEverything()调用的开销。

In this code, the call to getEverything() is wrapped so that it won't actually be executed until it's needed. The logging function will execute toString() on its parameters only if debugging is enabled. That way, your code will suffer only the overhead of a function call instead of the full getEverything() call.

这篇关于条件记录具有最小的复杂度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆