我重新表述这个问题,因为它要么太无趣,要么太难以理解。 :)
最初的问题是因为我正在从 Java 转换到 Groovy,但该示例在转换到任何高级语言(Ruby、Python、Groovy)时同样适用。
Java 很容易调试,因为代码行之间有明确的关系,并且行为相当细粒度,例如使用 for 循环操作数组:
for ( int i=0; i < array1.size(); i++ )
{
if ( meetsSomeCriterion(array1.elementAt(i) )
{
array2.add( array1.elementAt(i) );
}
}
因此您可以在循环中的测试上设置断点,看看接下来会发生什么。 (我知道有更好的方法来写这个;这只是为了说明这一点。)
在像 Ruby 这样的语言中,惯用的风格似乎更喜欢更高级别的单行编码,例如来自 http://rubyquiz.com/quiz113.html
quiz.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse
我想知道您是否可以建议任何有效的技术来调试此问题,例如,如果您更改了常规表达式...您是否仍会使用传统的调试器,并单步进入/越过链式方法? 或者,还有更好的方法?
谢谢!
I'm rephrasing this question because it was either too uninteresting or too incomprehensible. :)
The original question came about because I'm making the transation from Java to Groovy, but the example could apply equally when transitioning to any of the higher-level languages (Ruby, Python, Groovy).
Java is easy to debug because there is a clear relationship between lines of code, and fairly fine-grained behaviour, e.g. manipulate an array using a for loop:
for ( int i=0; i < array1.size(); i++ )
{
if ( meetsSomeCriterion(array1.elementAt(i) )
{
array2.add( array1.elementAt(i) );
}
}
so you can set a breakpoint on the test in the loop and see what happens next. (I know there are better ways to write this; it's just to illustrate the point.)
In languages like Ruby the idiomatic style seems to favour higher-level one-liner coding, e.g. from http://rubyquiz.com/quiz113.html
quiz.to_s.reverse.scan(/(?:\d*\.)?\d{1,3}-?/).join(',').reverse
I'm wondering if you can suggest any effective techniques for debugging this, for example if you changed the regular expression ... would you still use the traditional debugger, and step into/over the chained methods? Or is there a better way?
Thanks!
发布评论
评论(3)
如果我要调试你的示例,我要做的第一件事就是将其分解为多个步骤。 我不在乎它是“pythonic”还是“ruby way”或“tclish”或其他什么,这样的代码可能很难调试。
这并不是说我不会编写那样的代码。 一旦调试完成,有时可以将其全部连接到一行中,但我发现自己更倾向于可读性和可维护性,而不是编写简洁的代码。 如果单行方法确实更具可读性,我会采用它,但如果不是,我不会。
If I were to debug your example, the first thing I would do is break it down into multiple steps. I don't care if it's "pythonic" or "the ruby way" or "tclish" or whatever, code like that can be difficult to debug.
That's not to say I don't write code like that. Once it's been debugged it is sometimes OK to join it all into a single line but I find myself leaning more toward readability and maintainability and less toward writing concise code. If the one-liner approach is genuinely more readable I'll go with it, but if it's not, I don't.
将多个操作组合到一行中是非常好的,因为您仍然可以查看相关行并知道它将完全执行您希望它执行的操作。 当你无法查看代码并说“是的,好吧,它确实是 xyz,它不可能不能”时,你就应该考虑将其分解为单独的部分。
我给具有长过程/方法的人同样的建议。 如果您无法查看代码并确切知道它在所有情况下都在做什么,那么请将其分解。 您可以将每个“不明显”的代码分解为它自己的方法,并单独为该部分编写测试。 然后,您可以在原始方法中使用该方法,并且知道它会起作用......而且您的原始方法现在更容易理解。
同样,您可以将“scan(/(?:\d*.)?\d{1,3}-?/)”代码分解为另一种方法并自行测试。 然后,原始代码可以使用该方法,并且应该更容易理解并知道它正在工作。
Combining multiple actions into a single line is all well and good, when you can still look at the line in question and know that it's going to do exactly what you want it to do. The minute you get to the point where you can't look at the code and go "yeah, ok, it does xyz, there's no way it couldn't" is when you should consider breaking it into individual pieces.
I give the same advice to people with long procs/methods. If you can't look at the code and know exactly what it's doing in all situations, then break it up. You can break up each of the "non-obvious" bits of code into it's own method and write tests for that piece alone. Then, you can use that method in your original method and know it's going to work... plus your original method is now easier to understand.
Along the same lines, you can break your "scan(/(?:\d*.)?\d{1,3}-?/)" code off into another method and test that by itself. The original code can then use that method, and it should be much easier to understand and know it's working.
如果我必须调试像您发布的这样一行,我发现没有什么比将其分解为独立语句更有帮助了。 这样您就可以看到每个方法接收的参数以及返回的内容。
此类语句使代码难以维护。
If I have to debug such a line as the one you posted I find that nothing helps as much as breaking it into stand-alone statements. That way you can see what each method receives as a parameter , and what it returns.
Such statements make code hard to maintain.