How to debug?
-
I've gotten into a few habits with debugging that I've found helpful.
Firstly, as some folks have already mentioned I break my code up into small bits as much as possible. I've got a module that around 1000 lines of code and the longest method is only 7 lines, and it was a dream to debug. It's really easy to spot what's going wrong when it's such a tiny box. Also, there is no reason to be wary of writing a method with only a single line of code in it's body if it will meaningfully capture some logic in your overall code. This way the method names become a part of your documentation, and allow you to follow the logic easily and it naturally describes the problem you're working on.
Secondly, anytime I'm going to be writing a complicated method I will generally write my tests before I write my code. This often helps me to clarify the design, build some of the documentation, and it can speed up the debugging process considerably. I will also keep my test code even if I never use it again. You'll see a lot of coders type a few quick lines in the console to test something while they're writing a method and then throw it away. I do the same thing, but I just copy/paste it into another file and hold onto it. I never end up using almost all that code, but for the few times I do when
Thirdly, I will test my code after almost every change. There is no harm in testing the method after changing just a single line of code, particularly when you're working in a scripted language like Ruby and don't have to recompile. I found that if I deferred debugging till I had "something worth running" I'd often find a chain of bugs which would obscure the real error behind the scenes. You catch a lot of little things like typos, missing brackets, type mismatches and such which are easy to quash. Also, I find it's easier to debug what I'm doing while it's fresh in my mind. If I find a semantic error in code I wrote even an hour earlier it's not fresh and I have to figure out what I was doing at that point again to see where it went wrong.
Fourthly, I avoid state data as much as possible. Anytime declare a global, class, or instance variables you open up the possibility of side effects in your code which can make debugging a nightmare. I would also tend to avoid methods with a bang over their un-banged counterparts, so I would almost always use Array.map instead of Array.map! unless I had good reason to do so. State data exists for a reason, and they're good reasons but my experience tells me they're often used without any justification other than familiarity with procedural languages like C, Basic or Pascal. It's actually possible to write every program imaginable without any state data, which may have costs in runtime, modularity, and readability but it at least gives the sense that you can in fact avoid them and if it makes your code easier to debug and maintain that's often a good trade. Also, I never make state data private or protected while writing my code. It's much easier to debug this way since you can sniff their values, and I can always go back and make them private or protected at a later time. This applies to both variables and class definitions as well.
Finally, I read my documentation when I'm debugging. If I'm coming back to a project where new features have been introduced and suddenly I've got unintended behavior it's really nice to have a clear understanding of what the codes purpose is, why I chose that particular implementation over others, and some of the bugs I'd previously squashed in the code. I really hate fixing one bug only to introduce a new bug I had previously fixed and just forgotten about by making the same mistake again. A one-liner saying "this prevents and off-by-one error in the loop that follows" can be really handy. Also, I consider variable names as documentation. It's easier to figure out what "for point in points" means when compared to "for pt in pts". I also prefer "and" to "&&" and "not" to "!" for the same reasons, and I would rather use a for...in loop to the .each method. The more expressive your code, the easier it is to debug.
Also, it can be handy to familiarize yourself with a few different types of common bugs. It's easier to detect a bug when you're getting odd behavior if that behavior resembles what you'd expect from a particular type of bug and you also begin to build up a set of techniques to track them down and fix them.
-
@cleverbeans said:
Thirdly, I will test my code after almost every change. There is no harm in testing the method after changing just a single line of code, particularly when you're working in a scripted language like Ruby and don't have to recompile. I found that if I deferred debugging till I had "something worth running" I'd often find a chain of bugs which would obscure the real error behind the scenes. You catch a lot of little things like typos, missing brackets, type mismatches and such which are easy to quash. Also, I find it's easier to debug what I'm doing while it's fresh in my mind. If I find a semantic error in code I wrote even an hour earlier it's not fresh and I have to figure out what I was doing at that point again to see where it went wrong.
Yes, test often. So many times I've tripped over a bug do to a typo I made to a quick change. If I code larger chunks, the higher the likely hood of a typo bug or something silly sneaking its way in. (I'm often surprised if there is no errors after I've written a longer section of code. I begin to think that there must be something seriously wrong I haven't spotted yet.)
-
I know, I'm a complete outsider in this discussion, but I have a question and an idea.
My question: In what debugging situations is it necessary to restart Sketchup?
And my idea:
A plugin that resets Sketchup to it's initial state. So you never have to restart SU or manually reload a plugin to test a script.
-
@liquid98 said:
I know, I'm a complete outsider in this discussion, but I have a question and an idea.
My question: In what debugging situations is it necessary to restart Sketchup?
And my idea:
A plugin that resets Sketchup to it's initial state. So you never have to restart SU or manually reload a plugin to test a script.
If your script makes menu items or toolbars you will [usually] have trapped it with
file_loaded()
so you don't get multiple entries... so if you change those reloading the script won't affect those... but otherwise any code changes are usually reflected in the tool's operation without a need to restart if you useload "myscript.rb"
....... if you tool has decent start/commit blocks to undo what it's just done [incorrectly] you rarely need to restart Sketchup after tweaking your code... -
@liquid98 said:
My question: In what debugging situations is it necessary to restart Sketchup?
In additions to what TIG mentioned in regard to menus, you might want to restart after doing some major refactoring where you might have renamed methods etc. You might still be calling the old method.
And there might be things your plugin has to do at startup, such as some observers. But it belong to the rare cases. -
Thanx guys,
I'm working with dynamic screen notes and dynamic tooltips, and have to restart SU all the time to get them
refreshed.. But that's not common for most plugins I suppose. -
A tooltip for a UI::Command instance object can be changed at ANY time, simply by calling the instance object's tooltip= method, with an argument that is different than what the current tooltip text is.
This means that you must make and keep available, a reference (sloppily called a variable,) to that instance object, so you can later call it's instance methods.
You can also change the status bar text and the validation proc dynamically in the same way.
-
Its enough to make a grown man cry! It only took me 3 hours to find the 2 letter typing error. I hope this is not age related? There was no hint of a problem in the Ruby console, Notepad++ or SciTE. Its enough to make one
if( @stud != "YES" ) #...get the number of joists required for the related @vec/@joc #...@soc = joist on center spacing @num_stud=((@vec/@soc)+1).to_i definitions=model.definitions count=definitions.add entities=count.entities #...draw 1st stud base=entities.add_face(@pt1, @pt3, @pt33, @pt11) base=entities.add_line(@pt1, @pt33) base=entities.add_line(@pt3, @pt11) #...transform stud location t=Geom;;Transformation.translation(Geom;;Vector3d.new(0, 0, 0)) entities=model.active_entities entities.add_instance(count, t) #...copy studs to their new locations i = 1 while i < @num_stud # Transformation i = i + 1 vec = @pt5 - @pt6 # width between which studs are to be drawn vec.length = @soc*(i-1) t=Geom;;Transformation.translation(Geom;;Vector3d.new(0,@soc*(i-1), 0)) t=Geom;;Transformation.translation(vec) entities.add_instance(count, t) end end if # end if @stud
I feel better now!
-
line 7: no argument for the instance method
DefinitionsList.add()
-
@dan rathbun said:
line 7: no argument for the instance method
DefinitionsList.add()
No that's not it ! ..... nice try!..... try again?
-
end if
! -
@tomot said:
@dan rathbun said:
line 7: no argument for the instance method
DefinitionsList.add()
No that's not it ! ..... nice try!..... try again?
Wow... that's strange! An empty argument creates a new definition, whose name is "Component". The API does not mention this!!!
And Jim.. got it correct... although I would think Ruby would issue a
ScriptError
, something like "blah blah blah...`end' expected" -
yup! Jim is right!. So back to the initial subject, is there a debug routine for such errors?
your editor should be causing a high pitch sound for end if or at least a blicking, or bouncing simile. -
I was going to suggest checking the syntax, but you would need to have Ruby version 1.8.6 installed (not a bad idea if you are developing plugins.)
$ ruby -c plugin.rb plugin.rb:32: syntax error, unexpected $end
-
@jim said:
I was going to suggest checking the syntax, but you would need to have Ruby version 1.8.6 installed (not a bad idea if you are developing plugins.)
$ ruby -c plugin.rb plugin.rb:32: syntax error, unexpected $end
Jim: you have helped me with a few rubies I have posted here in the past,
would you please elaborate on I would install Ruby version 1.8.6 within the current Ruby/SU environment.
Currently I simply use NotePad ++ or SciTE to edit and develop my SketchUp Rubies. -
Ruby Binary Installer:
then use...
-
@dan rathbun said:
@tomot said:
@dan rathbun said:
line 7: no argument for the instance method
DefinitionsList.add()
No that's not it ! ..... nice try!..... try again?
Wow... that's strange! An empty argument creates a new definition, whose name is "Component". The API does not mention this!!!
And Jim.. got it correct... although I would think Ruby would issue a
ScriptError
, something like "blah blah blah...`end' expected"Dan, FYI, I have used that particular code several times to space entities between 2 know points, equally. I don't recall who helped me with the original code, many years ago.
-
@jim said:
Ruby Toolbar started - on Windows, it can open/close the Ruby Console, Clear it, and load/reload a file.
Jim: I get the following error when starting SU
-
You need WIn32API.so
-
I have written a debugger for Sketchup plugins with watches and breakpoints. Why isn't such a debugger already available? Would it be a good contribution to the community? The breakpoints based on watched variable changes seem like the best part.
Download the user guide that I attached.
It needs some work yet, as it processes only the Ruby snytax that I have
programmed with myself. It is a VB6 app. It would be free.Quote message
Face2Face plugin - autoextrusion between faces
Sent: Wed Dec 21, 2011 4:58 pm
by brian_concannonTIG,
I posted the plugin as you suggested, in the Resources/Plugins forum. It is being downloaded like crazy!
I hope you make it part of your Edgedraw plugins somehow.
anyway, I have written a debugger for Sketchup plugins with watches and breakpoints. Why isn't such a debugger already available? Would it be a good contribution to the community?
Quote message
Re: Face2Face plugin - autoextrusion between faces
Sent: Wed Dec 21, 2011 5:16 pm
From: TIG
To: brian_concannonIt would probably be a useful adjunct.
Why not post in the Developers' forum with a new thread.
You don't need to post the whole of your code, just some ideas to get a discussion rolling...
Thomthom, Jim and Dan are more in debugging etc than I am. I manually slog through with my own return nils, breaks, testing puts, UI.messageboxe, refreshes etc till I get it to work
Advertisement