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

Effective Debugging - RubyconfIndia

Effective Debugging - RubyconfIndia

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.

D3630c5a12aa3e85748670729444d5a9?s=128

Jonathan Wallace

June 22, 2013
Tweet

Transcript

  1. Effective Debugging 1 Saturday, June 22, 13

  2. Overview • Case Study • Recap and advanced commands •

    Debugging Libraries 2 Saturday, June 22, 13
  3. Case Study 3 Saturday, June 22, 13 - here’s the

    situation. - you’ve been handed an existing project by your boss..
  4. Sacculina Carcini 4 Saturday, June 22, 13 - 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
  5. 5 Saturday, June 22, 13 - this project has a

    test suite - previous developer completed feature and hands off a “green” test suite (or so he says)
  6. 6 Saturday, June 22, 13

  7. 7 Saturday, June 22, 13

  8. 8 Saturday, June 22, 13

  9. 9 Saturday, June 22, 13

  10. 10 Saturday, June 22, 13 - turnip / rspec, explain

    that steps are executed in order. - execution stops rspec expectation is not met.
  11. 11 Saturday, June 22, 13 - not enough information on

    line 12 to tell us why it failed - let’s look at the stack trace in the rspec output
  12. 12 Saturday, June 22, 13 let’s examine the step definition

    on line 32 to see if it can tell us more
  13. 13 Saturday, June 22, 13 - here we are in

    the step definition file
  14. 14 Saturday, June 22, 13 - 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..
  15. 15 Saturday, June 22, 13 - here’s the feature -

    and we know the failure is on line 12...
  16. 16 Saturday, June 22, 13 - but we don’t know

    when the crab’s payload should have its infection - it could happen on lines 3 through 11..
  17. 17 Saturday, June 22, 13 - 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’..
  18. 18 Saturday, June 22, 13 - we have to do

    two things to use the ‘debugger’ gem
  19. 19 Saturday, June 22, 13 - update our gem file

    to include a reference to the ‘debugger’ gem
  20. 20 Saturday, June 22, 13 - call the debugger method

    which pauses our application. - but where should we put it?...
  21. 21 Saturday, June 22, 13 - there’s no relationship between

    host, the crab, and parasite, the sacculina carcini
  22. 22 Saturday, June 22, 13 - instead, let’s place our

    debugger statement at the first step where the parasite and the host interact. - note that we have the ruby statement “true” after the debugger method call. - the reason for this is that execution is paused on the ruby expression immediately following the debugger method call. - let’s run the debugger
  23. 23 Saturday, June 22, 13

  24. 24 Saturday, June 22, 13 - let’s take a moment

    to discuss what we see in the debugger
  25. 25 Saturday, June 22, 13 - we see ten lines

    of context
  26. 26 Saturday, June 22, 13 - the line numbers appear

    in the first column
  27. 27 Saturday, June 22, 13 - here’s the current line

    where the application is paused
  28. 28 Saturday, June 22, 13 - 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...
  29. 29 Saturday, June 22, 13 - 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
  30. 30 Saturday, June 22, 13

  31. 31 Saturday, June 22, 13

  32. 32 Saturday, June 22, 13

  33. 33 Saturday, June 22, 13 - we’ve now advanced the

    debugger session to line 11. we have yet to execute the ruby expression on line 11 (we have executed the “true” statement on line 10. - let’s “step” again and see what happens
  34. 34 Saturday, June 22, 13 - note that executing ‘true’

    did not change our displayed ruby expression
  35. 35 Saturday, June 22, 13

  36. 36 Saturday, June 22, 13 - first thing to note

    is that our displayed ruby expression is still nil - secondly, whoa, where are we..
  37. 37 Saturday, June 22, 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
  38. 38 Saturday, June 22, 13 - 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.
  39. 39 Saturday, June 22, 13

  40. 40 Saturday, June 22, 13

  41. 41 Saturday, June 22, 13

  42. 42 Saturday, June 22, 13

  43. 43 Saturday, June 22, 13 - yeah, we have a

    value for the payload
  44. 44 Saturday, June 22, 13 - uh oh, where are

    we?
  45. 45 Saturday, June 22, 13 - 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? ...
  46. 46 Saturday, June 22, 13 - well, i can think

    of one way, we could add ‘debugger; true’ statements at lines 16, 20, 24, and 28...
  47. 47 Saturday, June 22, 13 - so instead of just

    one debugger statement, we would have five...
  48. 48 Saturday, June 22, 13 - however, there’s a better

    way. let’s make use of the capabilities provided by the debugger tool.
  49. 49 Saturday, June 22, 13

  50. 50 Saturday, June 22, 13

  51. 51 Saturday, June 22, 13

  52. 52 Saturday, June 22, 13

  53. 53 Saturday, June 22, 13

  54. 54 Saturday, June 22, 13

  55. 55 Saturday, June 22, 13

  56. 56 Saturday, June 22, 13

  57. 57 Saturday, June 22, 13

  58. 58 Saturday, June 22, 13

  59. 59 Saturday, June 22, 13

  60. 60 Saturday, June 22, 13

  61. 61 Saturday, June 22, 13

  62. 62 Saturday, June 22, 13

  63. 63 Saturday, June 22, 13

  64. 64 Saturday, June 22, 13

  65. 65 Saturday, June 22, 13

  66. 66 Saturday, June 22, 13 - here we are at

    breakpoint 4
  67. 67 Saturday, June 22, 13 - the crab payload in

    our display list hasn’t changed from 0x007
  68. 68 Saturday, June 22, 13 - 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’...
  69. 69 Saturday, June 22, 13

  70. 70 Saturday, June 22, 13

  71. 71 Saturday, June 22, 13

  72. 72 Saturday, June 22, 13 - hasn’t changed from 0x007.

    - but wait, what’s that?!?!
  73. 73 Saturday, June 22, 13 - string vs. symbol!

  74. 74 Saturday, June 22, 13

  75. 75 Saturday, June 22, 13

  76. 76 Saturday, June 22, 13

  77. 77 Saturday, June 22, 13

  78. 78 Saturday, June 22, 13

  79. 79 Saturday, June 22, 13

  80. 80 Saturday, June 22, 13

  81. 81 Saturday, June 22, 13

  82. Case Study Recap • debugger • display • step •

    break • continue • next 82 Saturday, June 22, 13 - 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.
  83. Case Study Recap • debugger • disp • step •

    break • next 83 Saturday, June 22, 13 - 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.
  84. Case Study Recap • debugger • display • step •

    break • next 84 Saturday, June 22, 13 - also called watch
  85. Case Study Recap • debugger • display <ruby expression> •

    step • break • next 85 Saturday, June 22, 13
  86. Case Study Recap • debugger • disp <ruby expression> •

    step • break • next 86 Saturday, June 22, 13
  87. Case Study Recap • debugger • disp[lay] • step •

    break • next 87 Saturday, June 22, 13
  88. Case Study Recap • debugger • disp[lay] • step [n]

    • break • next 88 Saturday, June 22, 13
  89. Case Study Recap • debugger • disp[lay] • step •

    break • next 89 Saturday, June 22, 13
  90. Case Study Recap • debugger • disp[lay] • step •

    break <file name>:<line number> • next 90 Saturday, June 22, 13
  91. Case Study Recap • debugger • disp[lay] • step •

    b <file name>:<line number> • next 91 Saturday, June 22, 13
  92. Case Study Recap • debugger • disp[lay] • step •

    b Class.class_method • next 92 Saturday, June 22, 13
  93. Case Study Recap • debugger • disp[lay] • step •

    b Class#instance_method • next 93 Saturday, June 22, 13
  94. Case Study Recap • debugger • display • step •

    break • continue • next 94 Saturday, June 22, 13 - continue execution until the application completes or we hit another breakpoint
  95. Case Study Recap • debugger • disp[lay] • step •

    break • next 95 Saturday, June 22, 13
  96. Case Study Recap • debugger • disp[lay] • step •

    break • next [n] 96 Saturday, June 22, 13
  97. Case Study Recap • debugger • disp[lay] • step •

    break • n [n] 97 Saturday, June 22, 13
  98. What did we miss? • finish • source 98 Saturday,

    June 22, 13
  99. What did we miss? • finish • source 99 Saturday,

    June 22, 13
  100. 100 Saturday, June 22, 13 - remember in our case

    study when we were on line eleven and we “stepped” into the attach method on @sacculini_carcini?...
  101. 101 Saturday, June 22, 13 - and at that time

    we stepped 3? - what if we had a loop, or many many lines of code?...
  102. 102 Saturday, June 22, 13 - so instead of step,

    we use “finish” which execute code until the current stack has completed
  103. 103 Saturday, June 22, 13

  104. What did we miss? • finish • source 104 Saturday,

    June 22, 13 - source has an analog called save, but in my explorations it does not save displayed ruby expressions in debugger
  105. 105 Saturday, June 22, 13

  106. What else did we miss? • which versions of ruby?

    106 Saturday, June 22, 13
  107. 107 Saturday, June 22, 13

  108. Debugger Versions • 1.8 -- ruby-debug • 1.9 -- debugger,

    ruby-debug19, debugger2 • 2.0 -- debugger, byebug, debugger2 108 Saturday, June 22, 13 - lag time between new version of ruby and a fully supported debugger - debugger2 / byebug - use external C APIs
  109. DEBUGGERS STINK! 109 Saturday, June 22, 13 provocative slide!

  110. Why? 110 Saturday, June 22, 13 - why? coupling! -

    let’s take a look at the change log for the debugger gem...
  111. 111 Saturday, June 22, 13

  112. 112 Saturday, June 22, 13

  113. Ruby’s C API 113 Saturday, June 22, 13 - 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
  114. Debugger Versions • 1.8 -- ruby-debug • 1.9 -- debugger,

    debugger2, ruby-debug19 • 2.0 -- debugger, debugger2, byebug 114 Saturday, June 22, 13 - lag time between new version of ruby and a fully supported debugger - debugger2 / byebug - use external C APIs
  115. ~/.rdebugrc • set autoreload • set autoeval • set autolist

    115 Saturday, June 22, 13 - for ruby 1.8.7 - if you’re using debugger, byebug or debugger2, these are the defaults
  116. Debugger Versions • 1.8 -- ruby-debug • 1.9 -- debugger,

    debugger2, ruby-debug19 • 2.0 -- debugger, debugger2, byebug 116 Saturday, June 22, 13 - lag time between new version of ruby and a fully supported debugger - debugger2 / byebug - use external C APIs
  117. Debugger Versions • 1.8 -- ruby-debug • 1.9 -- debugger,

    debugger2, ruby-debug19 • 2.0 -- debugger, debugger2, byebug 117 Saturday, June 22, 13 - lag time between new version of ruby and a fully supported debugger - debugger2 / byebug - use external C APIs
  118. 118 Saturday, June 22, 13

  119. Pry • “powerful alternative to [...] IRB [...]” • syntax

    highlighting • “flexible plugin architecture” 119 Saturday, June 22, 13 - here’s the important thing, PRY is a REPL (read eval print loop) - let’s take a look; two things to do
  120. 120 Saturday, June 22, 13 - add pry and pry-debugger

    to your Gemfile
  121. 121 Saturday, June 22, 13

  122. 122 Saturday, June 22, 13

  123. 123 Saturday, June 22, 13 - similar display, column numbers

    on the left, hash rocket indicates the current line - pretty colors
  124. 124 Saturday, June 22, 13 - binding.pry stops us before

    the binding.pry statement on line 10 so we don’t need “; true”
  125. 125 Saturday, June 22, 13

  126. 126 Saturday, June 22, 13 - notice we have to

    use “break”, no shortcuts - and we must use the relative path from the project directory to when specifying the file
  127. 127 Saturday, June 22, 13 - after hitting enter, we

    see info about the break point...
  128. 128 Saturday, June 22, 13 - in addition we see

    the context too for the break point.
  129. 129 Saturday, June 22, 13

  130. 130 Saturday, June 22, 13 - pry tells us how

    often the break point is hit - we have a few more things to note about pry...
  131. 131 Saturday, June 22, 13 - no shortcuts for commands

    unless you define them
  132. Debugger (+ Pry) Versions • 1.9 -- pry + pry-debugger

    132 Saturday, June 22, 13
  133. byebug 133 Saturday, June 22, 13 - 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
  134. why byebug? 134 Saturday, June 22, 13

  135. 135 Saturday, June 22, 13 - only for ruby 2.0.

    otherwise works as debugger in terms of commands, etc.
  136. Others? • Rubinius? • JRuby? 136 Saturday, June 22, 13

  137. 137 Saturday, June 22, 13

  138. 138 Saturday, June 22, 13 - for JRuby, feel free

    to use any of the Java tools for debugging
  139. Overview • Case Study • Recap and advanced commands •

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

    sacculina_carcini.git • http://www.flickr.com/photos/ 81858878@N00/9025250716/in/photolist- eKwLAY 140 Saturday, June 22, 13
  141. Get to know me! • http://blog.jonathanrwallace.com/about • jonathan.wallace@gmail.com • @jonathanwallace

    • http://www.bignerdranch.com/about_us/ nerds/jonathan_wallace 141 Saturday, June 22, 13 - thanks to Big Nerd Ranch, organizers and people who helped me with this talk