$30 off During Our Annual Pro Sale. View Details »

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.

Jonathan Wallace

June 22, 2013
Tweet

More Decks by Jonathan Wallace

Other Decks in Programming

Transcript

  1. Effective Debugging
    1
    Saturday, June 22, 13

    View Slide

  2. Overview
    • Case Study
    • Recap and advanced commands
    • Debugging Libraries
    2
    Saturday, June 22, 13

    View Slide

  3. Case Study
    3
    Saturday, June 22, 13
    - here’s the situation.
    - you’ve been handed an existing project by your boss..

    View Slide

  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

    View Slide

  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)

    View Slide

  6. 6
    Saturday, June 22, 13

    View Slide

  7. 7
    Saturday, June 22, 13

    View Slide

  8. 8
    Saturday, June 22, 13

    View Slide

  9. 9
    Saturday, June 22, 13

    View Slide

  10. 10
    Saturday, June 22, 13
    - turnip / rspec, explain that steps are executed in order.
    - execution stops rspec expectation is not met.

    View Slide

  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

    View Slide

  12. 12
    Saturday, June 22, 13
    let’s examine the step definition on line 32 to see if it can tell us more

    View Slide

  13. 13
    Saturday, June 22, 13
    - here we are in the step definition file

    View Slide

  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..

    View Slide

  15. 15
    Saturday, June 22, 13
    - here’s the feature
    - and we know the failure is on line 12...

    View Slide

  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..

    View Slide

  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’..

    View Slide

  18. 18
    Saturday, June 22, 13
    - we have to do two things to use the ‘debugger’ gem

    View Slide

  19. 19
    Saturday, June 22, 13
    - update our gem file to include a reference to the ‘debugger’ gem

    View Slide

  20. 20
    Saturday, June 22, 13
    - call the debugger method which pauses our application.
    - but where should we put it?...

    View Slide

  21. 21
    Saturday, June 22, 13
    - there’s no relationship between host, the crab, and parasite, the sacculina carcini

    View Slide

  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

    View Slide

  23. 23
    Saturday, June 22, 13

    View Slide

  24. 24
    Saturday, June 22, 13
    - let’s take a moment to discuss what we see in the debugger

    View Slide

  25. 25
    Saturday, June 22, 13
    - we see ten lines of context

    View Slide

  26. 26
    Saturday, June 22, 13
    - the line numbers appear in the first column

    View Slide

  27. 27
    Saturday, June 22, 13
    - here’s the current line where the application is paused

    View Slide

  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...

    View Slide

  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

    View Slide

  30. 30
    Saturday, June 22, 13

    View Slide

  31. 31
    Saturday, June 22, 13

    View Slide

  32. 32
    Saturday, June 22, 13

    View Slide

  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

    View Slide

  34. 34
    Saturday, June 22, 13
    - note that executing ‘true’ did not change our displayed ruby expression

    View Slide

  35. 35
    Saturday, June 22, 13

    View Slide

  36. 36
    Saturday, June 22, 13
    - first thing to note is that our displayed ruby expression is still nil
    - secondly, whoa, where are we..

    View Slide

  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

    View Slide

  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.

    View Slide

  39. 39
    Saturday, June 22, 13

    View Slide

  40. 40
    Saturday, June 22, 13

    View Slide

  41. 41
    Saturday, June 22, 13

    View Slide

  42. 42
    Saturday, June 22, 13

    View Slide

  43. 43
    Saturday, June 22, 13
    - yeah, we have a value for the payload

    View Slide

  44. 44
    Saturday, June 22, 13
    - uh oh, where are we?

    View Slide

  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? ...

    View Slide

  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...

    View Slide

  47. 47
    Saturday, June 22, 13
    - so instead of just one debugger statement, we would have five...

    View Slide

  48. 48
    Saturday, June 22, 13
    - however, there’s a better way. let’s make use of the capabilities provided by the debugger
    tool.

    View Slide

  49. 49
    Saturday, June 22, 13

    View Slide

  50. 50
    Saturday, June 22, 13

    View Slide

  51. 51
    Saturday, June 22, 13

    View Slide

  52. 52
    Saturday, June 22, 13

    View Slide

  53. 53
    Saturday, June 22, 13

    View Slide

  54. 54
    Saturday, June 22, 13

    View Slide

  55. 55
    Saturday, June 22, 13

    View Slide

  56. 56
    Saturday, June 22, 13

    View Slide

  57. 57
    Saturday, June 22, 13

    View Slide

  58. 58
    Saturday, June 22, 13

    View Slide

  59. 59
    Saturday, June 22, 13

    View Slide

  60. 60
    Saturday, June 22, 13

    View Slide

  61. 61
    Saturday, June 22, 13

    View Slide

  62. 62
    Saturday, June 22, 13

    View Slide

  63. 63
    Saturday, June 22, 13

    View Slide

  64. 64
    Saturday, June 22, 13

    View Slide

  65. 65
    Saturday, June 22, 13

    View Slide

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

    View Slide

  67. 67
    Saturday, June 22, 13
    - the crab payload in our display list hasn’t changed from 0x007

    View Slide

  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’...

    View Slide

  69. 69
    Saturday, June 22, 13

    View Slide

  70. 70
    Saturday, June 22, 13

    View Slide

  71. 71
    Saturday, June 22, 13

    View Slide

  72. 72
    Saturday, June 22, 13
    - hasn’t changed from 0x007.
    - but wait, what’s that?!?!

    View Slide

  73. 73
    Saturday, June 22, 13
    - string vs. symbol!

    View Slide

  74. 74
    Saturday, June 22, 13

    View Slide

  75. 75
    Saturday, June 22, 13

    View Slide

  76. 76
    Saturday, June 22, 13

    View Slide

  77. 77
    Saturday, June 22, 13

    View Slide

  78. 78
    Saturday, June 22, 13

    View Slide

  79. 79
    Saturday, June 22, 13

    View Slide

  80. 80
    Saturday, June 22, 13

    View Slide

  81. 81
    Saturday, June 22, 13

    View Slide

  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.

    View Slide

  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.

    View Slide

  84. Case Study Recap
    • debugger
    • display
    • step
    • break
    • next
    84
    Saturday, June 22, 13
    - also called watch

    View Slide

  85. Case Study Recap
    • debugger
    • display
    • step
    • break
    • next
    85
    Saturday, June 22, 13

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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?...

    View Slide

  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?...

    View Slide

  102. 102
    Saturday, June 22, 13
    - so instead of step, we use “finish” which execute code until the current stack has
    completed

    View Slide

  103. 103
    Saturday, June 22, 13

    View Slide

  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

    View Slide

  105. 105
    Saturday, June 22, 13

    View Slide

  106. What else did we miss?
    • which versions of ruby?
    106
    Saturday, June 22, 13

    View Slide

  107. 107
    Saturday, June 22, 13

    View Slide

  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

    View Slide

  109. DEBUGGERS STINK!
    109
    Saturday, June 22, 13
    provocative slide!

    View Slide

  110. Why?
    110
    Saturday, June 22, 13
    - why? coupling!
    - let’s take a look at the change log for the debugger gem...

    View Slide

  111. 111
    Saturday, June 22, 13

    View Slide

  112. 112
    Saturday, June 22, 13

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  118. 118
    Saturday, June 22, 13

    View Slide

  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

    View Slide

  120. 120
    Saturday, June 22, 13
    - add pry and pry-debugger to your Gemfile

    View Slide

  121. 121
    Saturday, June 22, 13

    View Slide

  122. 122
    Saturday, June 22, 13

    View Slide

  123. 123
    Saturday, June 22, 13
    - similar display, column numbers on the left, hash rocket indicates the current line
    - pretty colors

    View Slide

  124. 124
    Saturday, June 22, 13
    - binding.pry stops us before the binding.pry statement on
    line 10 so we don’t need “; true”

    View Slide

  125. 125
    Saturday, June 22, 13

    View Slide

  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

    View Slide

  127. 127
    Saturday, June 22, 13
    - after hitting enter, we see info about the break point...

    View Slide

  128. 128
    Saturday, June 22, 13
    - in addition we see the context too for the break point.

    View Slide

  129. 129
    Saturday, June 22, 13

    View Slide

  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...

    View Slide

  131. 131
    Saturday, June 22, 13
    - no shortcuts for commands unless you define them

    View Slide

  132. Debugger (+ Pry)
    Versions
    • 1.9 -- pry + pry-debugger
    132
    Saturday, June 22, 13

    View Slide

  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

    View Slide

  134. why byebug?
    134
    Saturday, June 22, 13

    View Slide

  135. 135
    Saturday, June 22, 13
    - only for ruby 2.0. otherwise works as debugger in terms of commands, etc.

    View Slide

  136. Others?
    • Rubinius?
    • JRuby?
    136
    Saturday, June 22, 13

    View Slide

  137. 137
    Saturday, June 22, 13

    View Slide

  138. 138
    Saturday, June 22, 13
    - for JRuby, feel free to use any of the Java tools for debugging

    View Slide

  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)

    View Slide

  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

    View Slide

  141. Get to know me!
    • http://blog.jonathanrwallace.com/about
    [email protected]
    • @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

    View Slide