Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Effective Debugging Rubyconf

Effective Debugging Rubyconf

Debugging is an art. And to be an effective artist, an artist must be intimately familiar with their tools. In this talk, we'll start gently and finish strong to ensure that there's something for everyone. We'll cover when to use a debugger, which debugger to use, and how to use the debugger, and how to quickly configure your debugger for maximum utility. We'll touch briefly on pry and why pry is not a debugger, except when it is.

Developers are always looking for ways to boost productivity. Effective debugging allows one to more quickly discover inaccuracies between our expectations and how the software actually behaves.

Jonathan Wallace

November 08, 2013
Tweet

More Decks by Jonathan Wallace

Other Decks in Programming

Transcript

  1. Case Study - use byebug - here’s the situation. -

    you’ve been handed an existing project by your boss..
  2. Sacculina Carcini - parasitic barnacle - takes over the host;

    host no longer molts; male crabs act like female crabs - http://www.flickr.com/photos/81858878@N00/9025250716/in/photolist-eKwLAY
  3. - this project has a test suite - previous developer

    completed feature and hands off a “green” test suite (or so he says)
  4. - turnip / rspec, explain that steps are executed in

    order. - execution stops rspec expectation is not met.
  5. - not enough information on line 12 to tell us

    why it failed - let’s look at the stack trace in the rspec output
  6. - the internal state of the crab should have a

    key that points to the parasite - let’s take a step back and review the feature again..
  7. - but we don’t know when the crab’s payload should

    have its infection - it could happen on lines 3 through 11..
  8. - at this point, it may be tempting to investigate

    the internal details of the crab class and its payload and how that works but that would be premature at this point. instead of anticipating where the problems lies, we’re going to allow our tool, the debugger, to direct our investigations. we’re not making assumptions as to the root cause of the error. let’s stay “assumption free.” - so, let’s use the ruby gem ‘debugger’..
  9. - instead, let’s place our debugger statement at the first

    step where the parasite and the host interact. - note that execution is paused on the ruby expression immediately following the debugger method call. - let’s run the debugger
  10. - and that is indicated by the presence of the

    hash rocket. - great. now we know where we are in the debugger session, let’s examine the code in this step...
  11. - we have two lines. - ah, line 12 looks

    interesting. do you remember what the original failure? it was related to the crab’s payload. - the crab’s payload was nil when the test expected there to be a value - let’s add the crab’s payload as a display (or watched) variable
  12. - first thing to note is that our displayed ruby

    expression is still nil - secondly, whoa, where are we..
  13. - we’re actually in a new file. we’re inside the

    attach method of the parasite. - the debugger command “step” goes into a method definition. we “step” into
  14. - a little different than last time. we provide a

    number after step. this indicates how many times to run the step command. this is useful when you want to issue the same command multiple times. this will run “step” 3 times for us.
  15. - we’re interested in what happens at the turnip step

    levels of lines 8, 9, 10 and 11. - how can we quickly stop execution at those lines? ...
  16. - well, i can think of one way, we could

    add ‘debugger’ statements at lines 16, 20, 24, and 28...
  17. - however, there’s a better way. let’s make use of

    the capabilities provided by the debugger tool.
  18. - the last time we stepped into a method, we

    took a detour that wasn’t necessary or informative. - let’s explore another debugger command, ‘next’...
  19. Recap and Advanced Commands - here’s the situation. - you’ve

    been handed an existing project by your boss..
  20. Case Study Recap • debugger • display • step •

    break • continue • next - debugger is a method that you may place in your application that will pause its execution allowing you to examine state, modify state, set further break points.
  21. Case Study Recap • debugger • disp • step •

    break • next • debugger • disp • step • break • next - debugger is a method that you may place in your application that will pause its execution allowing you to examine state, modify state, set further break points.
  22. Case Study Recap • debugger byebug • disp • step

    • break • next • debugger • disp • step • break • next If you’re using the latest version of byebug, which is 2.3.1, then you can’t use the ‘debugger’ alias. You must use ‘byebug’
  23. Case Study Recap •!!!! s/debugger/byebug/g !!!! • disp • step

    • break • next • debugger • disp • step • break • next So everywhere we saw ‘debugger’ used (only on line 10 in spec/steps.rb), you would use ‘byebug.’
  24. My PR was accepted yesterday. A new version of the

    gem hasn’t been pushed to rubygems.org yet but it is coming soon.
  25. Case Study Recap • debugger • display • step •

    break • next • debugger • disp • step • break • next • debugger • disp • step • break - also called watch
  26. Case Study Recap • debugger • display <ruby expression> •

    step • break • next • debugger • disp • step • break • next • debugger • disp • step • break
  27. Case Study Recap • debugger • disp <ruby expression> •

    step • break • next • debugger • disp • step • break • next • debugger • disp • step • break
  28. Case Study Recap • debugger • disp[lay] • step •

    break • next • debugger • disp • step • break • next • debugger • disp • step • break
  29. Case Study Recap • debugger • disp[lay] • step [n]

    • break • next • debugger • disp • step • break • next • debugger • disp • step • break
  30. Case Study Recap • debugger • disp[lay] • step •

    break • next • debugger • disp • step • break • debugger • disp • step • break • next
  31. Case Study Recap • debugger • disp[lay] • step •

    break <file name>:<line number> • next • debugger • disp • step • break • debugger • disp • step • break • next
  32. Case Study Recap • debugger • disp[lay] • step •

    b <file name>:<line number> • next • debugger • disp • step • break • debugger • disp • step • break • next
  33. Case Study Recap • debugger • disp[lay] • step •

    b Class.class_method • next • debugger • disp • step • break • debugger • disp • step • break • next
  34. Case Study Recap • debugger • disp[lay] • step •

    b Class#instance_method • next • debugger • disp • step • break • debugger • disp • step • break • next
  35. Case Study Recap • debugger • display • step •

    break • continue • next • debugger • disp • step • break • next • debugger • disp • step - continue execution until the application completes or we hit another breakpoint
  36. Case Study Recap • debugger • disp[lay] • step •

    break • next • debugger • disp • step • debugger • disp • step • break • next
  37. Case Study Recap • debugger • disp[lay] • step •

    break • next [n] • debugger • disp • step • debugger • disp • step • break • next
  38. Case Study Recap • debugger • disp[lay] • step •

    break • n [n] • debugger • disp • step • debugger • disp • step • break • next
  39. What did we miss? • finish • source • debugger

    • disp • step • break • next
  40. - remember in our case study when we were on

    line eleven and we “stepped” into the attach method on @sacculini_carcini?...
  41. - and at that time we stepped 3? - what

    if we had a loop, or many many lines of code?...
  42. - so instead of step, we use “finish” which execute

    code until the current stack has completed
  43. What did we miss? • finish • save • source

    • debugger • disp • step • break • next • debugger • disp • step • break • next
  44. - automatically evaluate ruby expressions - show full file paths

    or just the filename - - display context - auto start irb when prompt is shown
  45. What did we miss? • finish • save • source

    • debugger • disp • step • break • next
  46. Debugger Libraries • 1.8 -- ruby-debug • 1.9 -- debugger,

    ruby-debug19, debugger2 • 2.0 -- debugger, byebug, debugger2 - lag time between new version of ruby and a fully supported debugger - debugger2 / byebug - use external C APIs
  47. Why? - why? coupling! - let’s take a look at

    the change log for the debugger gem...
  48. Ruby’s C API - in the past, most debugging tools

    are tightly coupled to the C internals. - because the debuggers were hooking into internals, every time ruby changed, you needed a new debugger
  49. Debugger Versions • 1.8 -- ruby-debug • 1.9 -- debugger,

    debugger2, ruby-debug19 • 2.0 -- debugger, debugger2, byebug • debugger • disp • step • break • next - lag time between new version of ruby and a fully supported debugger - debugger2 / byebug - use external C APIs
  50. ~/.rdebugrc • set autoreload • set autoeval • set autolist


    - for ruby 1.8.7 - if you’re using debugger, byebug or debugger2, these are the defaults
  51. Debugger Versions • 1.8 -- ruby-debug • 1.9 -- debugger,

    debugger2, ruby-debug19 • 2.0 -- debugger, debugger2, byebug • debugger • disp • step • break • next • debugger • disp • step - lag time between new version of ruby and a fully supported debugger - debugger2 / byebug - use external C APIs
  52. Debugger Versions • 1.8 -- ruby-debug • 1.9 -- debugger,

    debugger2, ruby-debug19 • 2.0 -- debugger, debugger2, byebug • debugger • disp • step • break • debugger • disp • step • break • next - lag time between new version of ruby and a fully supported debugger - debugger2 / byebug - use external C APIs
  53. Pry • “powerful alternative to [...] IRB [...]” • syntax

    highlighting • “flexible plugin architecture” - here’s the important thing, PRY is a REPL (read eval print loop) - let’s take a look; two things to do
  54. - similar display, column numbers on the left, hash rocket

    indicates the current line - pretty colors
  55. - notice we have to use “break”, no shortcuts -

    and we must use the relative path from the project directory to when specifying the file
  56. - pry tells us how often the break point is

    hit - we have a few more things to note about pry...
  57. byebug - mashup of debase, another debugger for ruby 2.0

    (C ext part) and debugger (lib and test dirs) - i didn’t investigate debase much because there’s not a lot of documentation
  58. - for JRuby, feel free to use any of the

    Java tools for debugging
  59. Overview • Case Study • Recap and advanced commands •

    Debugging Libraries • Pry - next, step, break, continue, display - finish, source, save - ruby-debug 1.8.7, debugger for 1.9, byebug for 2.0 - can use pry w/debugger and byebug)
  60. Slides and Code and Image • https://speakerdeck.com/jwallace/effective- debugging-rubyconf • https://github.com/wallace/

    sacculina_carcini.git • http://www.flickr.com/photos/ 81858878@N00/9025250716/in/photolist- eKwLAY
  61. Get to know me! KNOW ME http://blog.jonathanrwallace.com/about FOLLOW ME @jonathanwallace

    WORK WITH ME http://www.bignerdranch.com CODE WITH ME github/wallace - thanks to Big Nerd Ranch, organizers and people who helped me with this talk