<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Stan Lo</title>
    <description>The latest articles on DEV Community by Stan Lo (@st0012).</description>
    <link>https://dev.to/st0012</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F238727%2F9cabf22f-2f6a-44d5-b823-6c8319c288d4.jpg</url>
      <title>DEV Community: Stan Lo</title>
      <link>https://dev.to/st0012</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/st0012"/>
    <language>en</language>
    <item>
      <title>From byebug to ruby/debug</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Wed, 10 Aug 2022 15:38:25 +0000</pubDate>
      <link>https://dev.to/st0012/from-byebug-to-rubydebug-339g</link>
      <guid>https://dev.to/st0012/from-byebug-to-rubydebug-339g</guid>
      <description>&lt;p&gt;Switching to a new debugger and potentially changing your debugging process could be scary. So I hope this post can help you get familiar with &lt;a href="https://github.com/ruby/debug" rel="noopener noreferrer"&gt;&lt;code&gt;ruby/debug&lt;/code&gt;&lt;/a&gt; and determine whether to switch to it.&lt;/p&gt;

&lt;p&gt;(In the rest of the article, I'll use &lt;code&gt;debug&lt;/code&gt; to refer to &lt;code&gt;ruby/debug&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Disclaimers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I'm not as experienced with &lt;code&gt;byebug&lt;/code&gt; as with &lt;code&gt;debug&lt;/code&gt;. So please let me know if I listed incorrect/outdated information.&lt;/li&gt;
&lt;li&gt;Its purpose is to give a higher-level comparison. To learn more about &lt;code&gt;debug&lt;/code&gt;'s specific usages, please check its &lt;a href="https://github.com/ruby/debug" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It doesn't contain all the features but should already cover most of them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Advantages of &lt;code&gt;debug&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Before we get into individual features, I want to quickly mention some advantages of &lt;code&gt;debug&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Colorized output&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fir3yykmwcaw3ct6h7y54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fir3yykmwcaw3ct6h7y54.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Backtrace with method/block arguments&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F5079556%2F183871321-b2feb33e-4733-41d5-9266-3e4c1f1daa29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F5079556%2F183871321-b2feb33e-4733-41d5-9266-3e4c1f1daa29.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Immune from the &lt;a href="https://github.com/deivid-rodriguez/byebug/issues/564" rel="noopener noreferrer"&gt;compatibility issue with Zeitwerk&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Powerful breakpoints and tracers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Convenient remote debugging and VSCode integration&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://st0012.dev/setup-ruby-debug-with-vscode" rel="noopener noreferrer"&gt;Setting it up with VSCode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Disadvantages of &lt;code&gt;debug&lt;/code&gt;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Less flexible on thread control
&lt;/li&gt;
&lt;li&gt;Doesn't work well with Fiber yet&lt;/li&gt;
&lt;li&gt;Doesn't have &lt;code&gt;pry&lt;/code&gt; integration like &lt;code&gt;pry-byebug&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;No per-project configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  &lt;code&gt;byebug&lt;/code&gt; vs &lt;code&gt;debug&lt;/code&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;(Although Ruby &lt;code&gt;3.1&lt;/code&gt; comes with &lt;code&gt;debug&lt;/code&gt; &lt;code&gt;v1.4&lt;/code&gt;, I recommend always using its latest release)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Supported Ruby version&lt;/td&gt;
&lt;td&gt;2.5+&lt;/td&gt;
&lt;td&gt;2.6+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gem install&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gem install byebug&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gem install debug&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bundler&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gem "byebug"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;gem "debug"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;irb&lt;/code&gt;, &lt;code&gt;reline&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Has C extension&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Start Debugging
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Via executable&lt;/td&gt;
&lt;td&gt;&lt;code&gt;byebug foo.rb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rdbg foo.rb&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Via debugger statement&lt;/td&gt;
&lt;td&gt;&lt;code&gt;byebug&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;binding.break&lt;/code&gt;, &lt;code&gt;binding.b&lt;/code&gt;, &lt;code&gt;debugger&lt;/code&gt; (the same)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Via requiring&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;require "debug/start"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  User Experience Features
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Colorizing&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Command history&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Help command&lt;/td&gt;
&lt;td&gt;&lt;code&gt;h[elp]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;h[elp]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edit source file&lt;/td&gt;
&lt;td&gt;&lt;code&gt;edit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;edit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Evaluation
&lt;/h2&gt;

&lt;p&gt;Code evaluation in REPL is more or less the same between &lt;code&gt;byebug&lt;/code&gt; and &lt;code&gt;debug&lt;/code&gt;, that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the expression doesn't match a console command, like &lt;code&gt;my_method(arg)&lt;/code&gt;, it'll be evaluated as Ruby code&lt;/li&gt;
&lt;li&gt;If the expression matches a console command, like &lt;code&gt;n&lt;/code&gt;, you can use console commands to evaluate it&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Execute debugger commands&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;cmd&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avoid expression/command conflicts&lt;/td&gt;
&lt;td&gt;&lt;code&gt;eval &amp;lt;expr&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pp &amp;lt;expr&amp;gt;&lt;/code&gt;, &lt;code&gt;p &amp;lt;expr&amp;gt;&lt;/code&gt;, or &lt;code&gt;eval &amp;lt;expr&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Flow Control &amp;amp; Frame Navigation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;debug&lt;/code&gt; provides the same stepping commands as &lt;code&gt;byebug&lt;/code&gt; does. So &lt;code&gt;byebug&lt;/code&gt; users can switch to &lt;code&gt;debug&lt;/code&gt; without learning new behaviors.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Step in&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s[tep]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;s[tep]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Step over&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n[ext]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;n[ext]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finish&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fin[ish]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fin[ish]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Move to &lt;code&gt;&amp;lt;id&amp;gt;&lt;/code&gt; frame&lt;/td&gt;
&lt;td&gt;&lt;code&gt;f[rame] &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;f[rame] &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Move up a frame&lt;/td&gt;
&lt;td&gt;&lt;code&gt;up&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;up&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Move down a frame&lt;/td&gt;
&lt;td&gt;&lt;code&gt;down&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;down&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Move up n frames&lt;/td&gt;
&lt;td&gt;&lt;code&gt;up &amp;lt;n&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Move down n frames&lt;/td&gt;
&lt;td&gt;&lt;code&gt;down &amp;lt;n&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Continue the program&lt;/td&gt;
&lt;td&gt;&lt;code&gt;c[ontinue]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;c[ontinue]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quit the debugger&lt;/td&gt;
&lt;td&gt;&lt;code&gt;q[uit]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;q[uit]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kill the program&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kill&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;kill&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Thread Control
&lt;/h2&gt;

&lt;p&gt;As previously mentioned, &lt;code&gt;debug&lt;/code&gt; stops all threads when suspended and doesn't allow per-thread management at the moment. So it has simpler thread-related commands.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Thread suspension&lt;/td&gt;
&lt;td&gt;Only the current thread&lt;/td&gt;
&lt;td&gt;All threads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;List all threads&lt;/td&gt;
&lt;td&gt;&lt;code&gt;th[read] l&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;th[read]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switch to thread&lt;/td&gt;
&lt;td&gt;&lt;code&gt;th[read] switch &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;th[read] &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop a thread&lt;/td&gt;
&lt;td&gt;&lt;code&gt;th[read] stop &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resume a thread&lt;/td&gt;
&lt;td&gt;&lt;code&gt;th[read] resume &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Breakpoint
&lt;/h2&gt;

&lt;p&gt;Although &lt;code&gt;byebug&lt;/code&gt; already has decent breakpoints support, &lt;code&gt;debug&lt;/code&gt; takes it to another level by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allowing breakpoints to execute commands with &lt;code&gt;pre:&lt;/code&gt; and &lt;code&gt;do:&lt;/code&gt; options&lt;/li&gt;
&lt;li&gt;Supporting call-location-based triggering condition with the &lt;code&gt;path:&lt;/code&gt; option&lt;/li&gt;
&lt;li&gt;Supporting specialized &lt;code&gt;catch&lt;/code&gt; and &lt;code&gt;watch&lt;/code&gt; breakpoints&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setting Breakpoints
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;On line&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] &amp;lt;line&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] &amp;lt;line&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On file:line&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] &amp;lt;file&amp;gt;:&amp;lt;line&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] &amp;lt;file&amp;gt;:&amp;lt;line&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On a method&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] &amp;lt;class&amp;gt;#&amp;lt;method&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] &amp;lt;class&amp;gt;#&amp;lt;method&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;With a condition&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] ... if &amp;lt;expr&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] ... if: &amp;lt;expr&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;With a path condition&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] ... path: /path/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;To run a command and continue&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] ... do: &amp;lt;cmd&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;To run a command before stopping&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] ... pre: &amp;lt;cmd&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exception breakpoint&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;catch &amp;lt;ExceptionClass&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instance variable watch breakpoint&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;watch &amp;lt;@ivar&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Managing Breakpoints
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List all breakpoints&lt;/td&gt;
&lt;td&gt;&lt;code&gt;info breakpoints&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set a breakpoint&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] ...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;b[reak] ...&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete a breakpoint&lt;/td&gt;
&lt;td&gt;&lt;code&gt;del[ete] &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;del[ete] &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete all breakpoints&lt;/td&gt;
&lt;td&gt;&lt;code&gt;del[ete]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;del[ete]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Information
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Backtrace
&lt;/h3&gt;

&lt;p&gt;Backtrace in &lt;code&gt;debug&lt;/code&gt; contains values of method call or block arguments. This small improvement can save you from inspecting them manually between frames.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F5079556%2F183871321-b2feb33e-4733-41d5-9266-3e4c1f1daa29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F5079556%2F183871321-b2feb33e-4733-41d5-9266-3e4c1f1daa29.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The filtering support can help you focus on relevant frames and ignore the ones from frameworks or libraries.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Show backtrace&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;where&lt;/code&gt;, &lt;code&gt;backtrace&lt;/code&gt;, &lt;code&gt;bt&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;backtrace&lt;/code&gt;, &lt;code&gt;bt&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Displaying method/block arguments in backtrace&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter backtrace&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bt /regexp/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Limit the number of backtraces&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bt &amp;lt;n&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Varibles/Constants
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Show local varibales&lt;/td&gt;
&lt;td&gt;&lt;code&gt;var local&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;info l&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show instance variables&lt;/td&gt;
&lt;td&gt;&lt;code&gt;var instance&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;info i&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show global varibales&lt;/td&gt;
&lt;td&gt;&lt;code&gt;var global&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;info g&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show constants&lt;/td&gt;
&lt;td&gt;&lt;code&gt;var const&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;info c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show only arguments&lt;/td&gt;
&lt;td&gt;&lt;code&gt;var args&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No (included in &lt;code&gt;info l&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter variables/constants by names&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;info ... /regexp/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Methods
&lt;/h3&gt;

&lt;p&gt;While &lt;code&gt;debug&lt;/code&gt; doesn't have a dedicated command to list an object's methods, it has a &lt;code&gt;ls&lt;/code&gt; command that's similar to&lt;br&gt;
&lt;code&gt;irb&lt;/code&gt; or &lt;code&gt;pry&lt;/code&gt;'s.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;obj.methods&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;method instance obj&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;obj.methods(false)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;method obj.class&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ls obj&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Tracing
&lt;/h2&gt;

&lt;p&gt;I will write another dedicated article to introduce &lt;code&gt;debug&lt;/code&gt;'s tracing functionalities, but I encourage you to already give them a try from time to time, especially:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;trace exception&lt;/code&gt; - to monitor exceptions raised in your code. You may be surprised by the exceptions raised and rescued in your application under the surface.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;trace object &amp;lt;expr&amp;gt;&lt;/code&gt; - to observe an object's activities: receiving a method call or being passed to a method call.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F5079556%2F183893134-f7e3e26b-c5ef-49cb-9c6b-9595c373c8c1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F5079556%2F183893134-f7e3e26b-c5ef-49cb-9c6b-9595c373c8c1.png" alt="trace object"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Line tracer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;set linetrace&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trace line&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global variable tracer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tarcevar&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Allow multiple tracers&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Method call tracer&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trace call&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exceptions tracer&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trace exception&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ruby object tracer&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trace object &amp;lt;expr&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Filter tracing output&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trace ... /regexp/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disable tracer&lt;/td&gt;
&lt;td&gt;&lt;code&gt;set linetrace false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trace off [tracer type]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Disable the specific tracer&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;trace off &amp;lt;id&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;debug&lt;/code&gt; supports a &lt;a href="https://github.com/ruby/debug#configuration" rel="noopener noreferrer"&gt;wide range of configurations&lt;/a&gt; to make it fit your needs. But it doesn't support per-project RC files due to security concerns.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;List all configs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;&lt;code&gt;config&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Show a config&lt;/td&gt;
&lt;td&gt;&lt;code&gt;show &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;config show &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set a config&lt;/td&gt;
&lt;td&gt;&lt;code&gt;set &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;config set &amp;lt;name&amp;gt; &amp;lt;value&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RC file name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;.byebugrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.rdbgrc&lt;/code&gt; (or &lt;code&gt;.rdbgrc.rb&lt;/code&gt; for Ruby script)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RC file locations&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;$HOME&lt;/code&gt; and project root&lt;/td&gt;
&lt;td&gt;&lt;code&gt;$HOME&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Remote Debugging
&lt;/h2&gt;

&lt;p&gt;Remote debugging functionality is becoming crucial as we start containerizing our development environment and don't always have direct standard IO access.&lt;br&gt;
It's also crucial for connecting to different debugger clients like VSCode or Chrome.&lt;/p&gt;

&lt;p&gt;So if you have needs in this area, migrating to &lt;code&gt;debug&lt;/code&gt; is your best option.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;byebug&lt;/th&gt;
&lt;th&gt;debug&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Connect via TCP/IP&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connect via Unix Domain Socket&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VSCode integration through &lt;a href="https://microsoft.github.io/debug-adapter-protocol/specification" rel="noopener noreferrer"&gt;Debug Adapter Protocol (DAP)&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Chrome integration through &lt;a href="https://chromedevtools.github.io/devtools-protocol/" rel="noopener noreferrer"&gt;Chrome DevTools Protocol (CDP)&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Wrapping Up
&lt;/h1&gt;

&lt;p&gt;To most users, switching from &lt;code&gt;byebug&lt;/code&gt; to &lt;code&gt;debug&lt;/code&gt; should take little effort. But the potential productivity gain from &lt;code&gt;debug&lt;/code&gt;'s features could be significant.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;byebug&lt;/code&gt; is a great debugger and has served the community well for many years.&lt;br&gt;
But as its development slows down (last release was 2 years ago) and &lt;code&gt;debug&lt;/code&gt; receives constant updates from the Ruby core, the gap between them will only widen.&lt;/p&gt;

&lt;p&gt;So adding &lt;code&gt;debug&lt;/code&gt; to your toolbelt and exploring its powerful features will be a great productivity investment for the long term.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.google.com/spreadsheets/d/1TlmmUDsvwK4sSIyoMv-io52BUUz__R5wpu-ComXlsw0/edit#gid=0" rel="noopener noreferrer"&gt;Debugger commands comparison sheet&lt;/a&gt; by &lt;a href="https://github.com/ko1" rel="noopener noreferrer"&gt;@ko1&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/deivid-rodriguez/byebug/blob/master/GUIDE.md" rel="noopener noreferrer"&gt;Byebug's official guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ruby/debug" rel="noopener noreferrer"&gt;ruby/debug's official documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Setup ruby/debug with VSCode</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Sat, 09 Jul 2022 11:32:10 +0000</pubDate>
      <link>https://dev.to/st0012/setup-rubydebug-with-vscode-1b7c</link>
      <guid>https://dev.to/st0012/setup-rubydebug-with-vscode-1b7c</guid>
      <description>&lt;p&gt;Do you know Ruby's official debugger &lt;a href="https://github.com/ruby/debug" rel="noopener noreferrer"&gt;&lt;code&gt;ruby/debug&lt;/code&gt;&lt;/a&gt; provides out-of-box integration with VSCode? If you haven't tried it yet or having difficulty making it work, I hope this short post will help you set it up.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=KoichiSasada.vscode-rdbg" rel="noopener noreferrer"&gt;VSCode rdbg extension&lt;/a&gt; in VSCode&lt;/li&gt;
&lt;li&gt;Create the &lt;code&gt;launch.json&lt;/code&gt; file

&lt;ol&gt;
&lt;li&gt;Click &lt;code&gt;Run and Debug&lt;/code&gt; button on the left side&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;create a launch.json file&lt;/code&gt; - this is quite small and under &lt;code&gt;To customize Run and Debug&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Save the created &lt;code&gt;launch.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Put &lt;code&gt;gem "debug", require: false&lt;/code&gt; in your &lt;code&gt;Gemfile&lt;/code&gt; and run &lt;code&gt;bundle install&lt;/code&gt;
&lt;/li&gt;

&lt;/ol&gt;

&lt;h3&gt;
  
  
  Debug Simple Ruby Script
&lt;/h3&gt;

&lt;p&gt;If you want to debug a simple Ruby script, you can follow &lt;a href="https://github.com/ruby/debug#using-vscode" rel="noopener noreferrer"&gt;these steps&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debug Rails/Web Applications
&lt;/h3&gt;

&lt;p&gt;If you want to debug a Rails/web application, do these instead:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the files in VSCode and add some breakpoints.&lt;/li&gt;
&lt;li&gt;Start your program with the &lt;code&gt;rdbg&lt;/code&gt; executable - &lt;code&gt;bundle exec rdbg --open -n -c -- bundle exec rails s&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--open&lt;/code&gt; or &lt;code&gt;-O&lt;/code&gt; means starting the debugger in server mode&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-n&lt;/code&gt;  means don't stop at the beginning of the program, which is usually somewhere at rubygems, not helpful&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c&lt;/code&gt;  means you'll be running a Ruby-based command&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Go back to VSCode's &lt;code&gt;Run and Debug&lt;/code&gt; panel, you should see a grean play button&lt;/li&gt;
&lt;li&gt;Click the dropdown besides the button and select &lt;code&gt;Attach with rdbg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click the play button&lt;/li&gt;
&lt;li&gt;It should now connect the VSCode to the debugger

&lt;ul&gt;
&lt;li&gt;If it stops at somewhere in your web server (like &lt;a href="https://github.com/puma/puma" rel="noopener noreferrer"&gt;puma&lt;/a&gt;). Hit &lt;code&gt;continue&lt;/code&gt; or &lt;code&gt;F5&lt;/code&gt;. This will be resolved in the next &lt;code&gt;1.6.0&lt;/code&gt; release.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Send some requests and it should stop at your breakpoints&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Video&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0elr5otucfojq1vdoyz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0elr5otucfojq1vdoyz.gif" alt="Connect the debugger with your Rails server"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also have built this &lt;a href="https://replit.com/@st0012/rubydebug-demo?v=1" rel="noopener noreferrer"&gt;&lt;code&gt;repl.it&lt;/code&gt;&lt;/a&gt; to let you try out &lt;a href="https://github.com/ruby/debug" rel="noopener noreferrer"&gt;&lt;code&gt;ruby/debug&lt;/code&gt;&lt;/a&gt;'s console commands in your browser (it'll only take you 5 minutes).&lt;/p&gt;

&lt;p&gt;If you want to see more articles/tips about the powerful features &lt;a href="https://github.com/ruby/debug" rel="noopener noreferrer"&gt;&lt;code&gt;ruby/debug&lt;/code&gt;&lt;/a&gt; has, you can follow me on &lt;a href="https://twitter.com/_st0012" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; 🙂&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>debugger</category>
      <category>vscode</category>
    </item>
    <item>
      <title>A Sneak Peek of Ruby's New Debugger!</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Thu, 29 Jul 2021 15:22:16 +0000</pubDate>
      <link>https://dev.to/st0012/a-sneak-peek-of-ruby-s-new-debugger-5caa</link>
      <guid>https://dev.to/st0012/a-sneak-peek-of-ruby-s-new-debugger-5caa</guid>
      <description>&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ruby" rel="noopener noreferrer"&gt;
        ruby
      &lt;/a&gt; / &lt;a href="https://github.com/ruby/debug" rel="noopener noreferrer"&gt;
        debug
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Debugging functionality for Ruby
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;&lt;a href="https://github.com/ruby/debug" rel="noopener noreferrer"&gt;&lt;code&gt;debug&lt;/code&gt;&lt;/a&gt; is Ruby's new debugger and will be included in Ruby 3.1. Since I've been both contributing to and using it for a while, I feel it's time to give you guys a sneak peek before its &lt;code&gt;1.0&lt;/code&gt; release 🙂&lt;/p&gt;

&lt;p&gt;(&lt;em&gt;Since it's not officially released yet, any feature mentioned in this article could still be modified/removed in the released version&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;Update&lt;/strong&gt;: The project's lead developer &lt;a class="mentioned-user" href="https://dev.to/ko1"&gt;@ko1&lt;/a&gt; has started a blog series about the debugger. Please also check it 😉)&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/ko1" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F676878%2F1cfe5671-4e9b-4cb5-b5b8-da31f6af6107.png" alt="ko1"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/ko1/debug-gem-blog-initial-commit-3ip" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;debug.gem blog: initial commit&lt;/h2&gt;
      &lt;h3&gt;Koichi Sasada ・ Jul 31 '21&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#ruby&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#debugger&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As I have mentioned, it's planned to be a standard library of Ruby 3.1. And currently, you can install it as a gem, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ gem install debug --pre
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="c1"&gt;# it's under active development, so I suggest using GitHub as source when possible&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"debug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;github: &lt;/span&gt;&lt;span class="s2"&gt;"ruby/debug"&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Functionality-wise, &lt;code&gt;debug&lt;/code&gt; is similar to the famous &lt;code&gt;GDB&lt;/code&gt; debugger and Ruby's &lt;code&gt;byebug&lt;/code&gt; gem. It provides a rich set of &lt;a href="https://github.com/ruby/debug#debug-command-on-the-debug-console" rel="noopener noreferrer"&gt;debug commands&lt;/a&gt; and has some unique features. &lt;/p&gt;

&lt;p&gt;Quoted from its README:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;New debug.rb has several advantages:

-   Fast: No performance penalty on non-stepping mode and non-breakpoints.
-   Remote debugging: Support remote debugging natively.
    -   UNIX domain socket
    -   TCP/IP
    -   VSCode/DAP integration (VSCode rdbg Ruby Debugger - Visual Studio Marketplace)
-   Extensible: application can introduce debugging support with several ways:
    -   By `rdbg` command
    -   By loading libraries with `-r` command line option
    -   By calling Ruby's method explicitly
-   Misc
    -   Support threads (almost done) and ractors (TODO).
    -   Support suspending and entering to the console debugging with `Ctrl-C` at most of timing.
    -   Show parameters on backtrace command.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And these are my favorite features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's colorized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxc3ylweoqelut9rddsi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhxc3ylweoqelut9rddsi.png" alt="Colorize Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When showing backtrace with the &lt;code&gt;backtrace&lt;/code&gt; command, it also shows method arguments, block arguments, and the return value.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=&amp;gt;#0    Foo#forth_call(num1=20, num2=10) at target.rb:20 #=&amp;gt; 30
  #1    block {|ten=10|} in second_call at target.rb:8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;It's possible to script your debug commands with &lt;code&gt;binding.break&lt;/code&gt; and reduce manual operations. (See the combinations section for examples)&lt;/li&gt;
&lt;li&gt;There are several commands to set breakpoints that trigger under different conditions, like &lt;code&gt;break&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt;, and &lt;code&gt;watch&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;binding.break&lt;/code&gt; (alias: &lt;code&gt;binding.b&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;If you're a heavy &lt;code&gt;pry&lt;/code&gt; user like me, you can use a familiar &lt;code&gt;binding.break&lt;/code&gt; (or just &lt;code&gt;binding.b&lt;/code&gt;) to kick off the debug session as usual.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;binding.break&lt;/code&gt; is actually more powerful than &lt;code&gt;binding.pry&lt;/code&gt;, because it can take commands! &lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;binding.b(do: "catch CustomException")&lt;/code&gt; - debugger will execute the command (&lt;code&gt;catch customExeption&lt;/code&gt;) and continue the program.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;binding.b(pre: "catch CustomException")&lt;/code&gt; - debugger will execute the command (&lt;code&gt;catch customExeption&lt;/code&gt;) and stop at the line.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(To execute multiple commands, use &lt;code&gt;;;&lt;/code&gt; as the separator: &lt;code&gt;"cmd1 ;; cmd2 ;; cmd3"&lt;/code&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Fequently Used Commands
&lt;/h2&gt;

&lt;p&gt;The new debugger has many powerful commands. And here are the ones I use the most:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;break&lt;/code&gt; (alias: &lt;code&gt;b&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;A&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;C&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;A&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;
&lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;

&lt;span class="n"&gt;b1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;b2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;C&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

&lt;span class="n"&gt;b1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;
&lt;span class="n"&gt;b2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Basic Usages
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;b A#foo&lt;/code&gt; - stops when &lt;code&gt;b1.foo&lt;/code&gt;, &lt;code&gt;b2.foo&lt;/code&gt;, and &lt;code&gt;c.foo&lt;/code&gt; is called&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b A.bar&lt;/code&gt; - stops when &lt;code&gt;B.bar&lt;/code&gt; and &lt;code&gt;C.bar&lt;/code&gt; is called&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b B#foo&lt;/code&gt; - stops when &lt;code&gt;b1.foo&lt;/code&gt; and &lt;code&gt;b2.foo&lt;/code&gt; is called&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b B.bar&lt;/code&gt; - stops when &lt;code&gt;B.bar&lt;/code&gt; is called&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b b1.foo&lt;/code&gt; - stops when &lt;code&gt;b1.foo&lt;/code&gt; is called&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Commands
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;b b1.foo do: cmd&lt;/code&gt; - executes &lt;code&gt;cmd&lt;/code&gt; when &lt;code&gt;b1.foo&lt;/code&gt; is called but doesn't stop&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;b b1.foo pre: cmd&lt;/code&gt; - executes &lt;code&gt;cmd&lt;/code&gt; when &lt;code&gt;b1.foo&lt;/code&gt; is called and stops&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;catch&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FooException&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BarException&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;StandardError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;raise_foo&lt;/span&gt;
  &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;FooException&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;raise_bar&lt;/span&gt;
  &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;BarException&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;


&lt;span class="n"&gt;raise_foo&lt;/span&gt;
&lt;span class="n"&gt;raise_bar&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;catch StandardError&lt;/code&gt; - stops when any instance of &lt;code&gt;StandardError&lt;/code&gt; is raised, including &lt;code&gt;FooException&lt;/code&gt; and &lt;code&gt;BarException&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;catch FooException&lt;/code&gt; - stops when &lt;code&gt;FooException&lt;/code&gt; is raised&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;backtrace&lt;/code&gt; (alias &lt;code&gt;bt&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Example Output&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=&amp;gt;#0    Foo#forth_call(num1=20, num2=10) at target.rb:20 #=&amp;gt; 30
  #1    block {|ten=10|} in second_call at target.rb:8
  #2    Foo#third_call_with_block(block=#&amp;lt;Proc:0x00007f9283101568 target.rb:7&amp;gt;) at target.rb:15
  #3    Foo#second_call(num=20) at target.rb:7
  #4    Foo#first_call at target.rb:3
  #5    &amp;lt;main&amp;gt; at target.rb:23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bt&lt;/code&gt; - shows all frames on the stack&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bt 10&lt;/code&gt; - only shows the first 10 frames&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bt /my_lib/&lt;/code&gt; - only shows the frames with path that matches &lt;code&gt;my_lib&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;outline&lt;/code&gt; (alias &lt;code&gt;ls&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Similar to the &lt;code&gt;ls&lt;/code&gt; command in &lt;code&gt;irb&lt;/code&gt; or &lt;code&gt;pry&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;binding.b&lt;/code&gt; + Command Combinations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;binding.b(do: "b Foo#bar do: bt")&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;It allows you to inspect a method call's backtrace without touching the method definition or typing commands manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Script&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;do: &lt;/span&gt;&lt;span class="s2"&gt;"b Foo#bar do: bt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_method&lt;/span&gt;
  &lt;span class="no"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;some_method&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEBUGGER: Session start (pid: 75555)
[1, 10] in target.rb
=&amp;gt;    1| binding.b(do: "b Foo#bar do: bt")
      2|
      3| class Foo
      4|   def bar
      5|   end
      6| end
      7|
      8| def some_method
      9|   Foo.new.bar
     10| end
=&amp;gt;#0    &amp;lt;main&amp;gt; at target.rb:1
(rdbg:binding.break) b Foo#bar do: bt
uninitialized constant Foo
#0  BP - Method (pending)  Foo#bar do: bt
DEBUGGER:  BP - Method  Foo#bar at target.rb:4 do: bt is activated.
[1, 10] in target.rb
      1| binding.b(do: "b Foo#bar do: bt")
      2|
      3| class Foo
=&amp;gt;    4|   def bar
      5|   end
      6| end
      7|
      8| def some_method
      9|   Foo.new.bar
     10| end
=&amp;gt;#0    Foo#bar at target.rb:4
  #1    Object#some_method at target.rb:9
  # and 1 frames (use `bt' command for all frames)

Stop by #0  BP - Method  Foo#bar at target.rb:4 do: bt
(rdbg:break) bt
=&amp;gt;#0    Foo#bar at target.rb:4
  #1    Object#some_method at target.rb:9
  #2    &amp;lt;main&amp;gt; at target.rb:12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;binding.b(do: "b Foo#bar do: info")&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;It allows you to inspect a method's environment (e.g. argument) when called:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Script&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;do: &lt;/span&gt;&lt;span class="s2"&gt;"b Foo#bar do: info"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; 
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;some_method&lt;/span&gt;
  &lt;span class="no"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;some_method&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEBUGGER: Session start (pid: 75924)
[1, 10] in target.rb
=&amp;gt;    1| binding.b(do: "b Foo#bar do: info")
      2|
      3| class Foo
      4|   def bar(a)
      5|     a
      6|   end
      7| end
      8|
      9| def some_method
     10|   Foo.new.bar(10)
=&amp;gt;#0    &amp;lt;main&amp;gt; at target.rb:1
(rdbg:binding.break) b Foo#bar do: info
uninitialized constant Foo
#0  BP - Method (pending)  Foo#bar do: info
DEBUGGER:  BP - Method  Foo#bar at target.rb:4 do: info is activated.
[1, 10] in target.rb
      1| binding.b(do: "b Foo#bar do: info")
      2|
      3| class Foo
      4|   def bar(a)
=&amp;gt;    5|     a
      6|   end
      7| end
      8|
      9| def some_method
     10|   Foo.new.bar(10)
=&amp;gt;#0    Foo#bar(a=10) at target.rb:5
  #1    Object#some_method at target.rb:10
  # and 1 frames (use `bt' command for all frames)

Stop by #0  BP - Method  Foo#bar at target.rb:4 do: info
(rdbg:break) info
%self = #&amp;lt;Foo:0x00007fdac491c200&amp;gt;
a = 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm a Rails developer, so I usually put the combination code at the beginning of a controller action, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="nb"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;pre: &lt;/span&gt;&lt;span class="s2"&gt;"b User#buggy_method do: info"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# other code&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then the debugger would execute the command and/or stops at the method I expected. &lt;br&gt;
I don't need to jump between multiple files for adding &lt;code&gt;binding.pry&lt;/code&gt; or &lt;code&gt;puts&lt;/code&gt; anymore 😎&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;del&gt;A Small Drawback&lt;/del&gt;
&lt;/h3&gt;

&lt;p&gt;However, the new debugger isn't all perfect (yet). Unlike in &lt;code&gt;byebug&lt;/code&gt; or &lt;code&gt;pry&lt;/code&gt;, you can't directly evaluate a Ruby expression in the debug session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(rdbg) 1 + 1
unknown command: 1 + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To evaluate an expression, you need to use &lt;code&gt;p&lt;/code&gt; or &lt;code&gt;pp&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(rdbg) p 1 + 1
=&amp;gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But according to the project's maintainer &lt;a href="https://github.com/ko1" rel="noopener noreferrer"&gt;@ko1&lt;/a&gt;'s '&lt;a href="https://github.com/ruby/debug/issues/148#issuecomment-887687532" rel="noopener noreferrer"&gt;comment&lt;/a&gt;, expression evaluation may be supported before the official &lt;code&gt;1.0&lt;/code&gt; release.&lt;/p&gt;

&lt;h4&gt;
  
  
  Update
&lt;/h4&gt;

&lt;p&gt;With &lt;a href="https://github.com/ruby/debug/pull/227" rel="noopener noreferrer"&gt;https://github.com/ruby/debug/pull/227&lt;/a&gt; being merged, this problem doesn't exist anymore 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Although it's not officially released yet, I've started using it at work daily. And I believe it'll soon become an must-have tool in every Rubyists' toolbox. So if you're curious about its capability, I encourage to give it a try 😉&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>debug</category>
      <category>rails</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Fixing issues in OSS is easier than you think</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Thu, 12 Nov 2020 07:17:28 +0000</pubDate>
      <link>https://dev.to/st0012/fixing-issues-in-oss-is-easier-than-you-think-1m2e</link>
      <guid>https://dev.to/st0012/fixing-issues-in-oss-is-easier-than-you-think-1m2e</guid>
      <description>&lt;p&gt;Issue fixing is the most common way to contribute to open source projects. And I believe many of you want to contribute to OSS projects in this way. But the idea of solving an issue on your own can also be intimidating. For example, when you open up an issue report and try to work on it, you may find it difficult to start because&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't have sufficient information about the bug&lt;/li&gt;
&lt;li&gt;You don't know how to reproduce it&lt;/li&gt;
&lt;li&gt;You are not sure if that's really a bug of the project or just an unsupported use case&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't know if the above scenarios have happened to you before, but I surely experienced it a lot in my earlier days as a contributor. At that time, it prevented me from committing to an issue because I was afraid that I couldn't finish on my own.&lt;/p&gt;

&lt;p&gt;But who said that we need to fix an issue alone? Although solving an issue on your own is surely a great thing. However, it's also often to see people solving issues collaboratively. So in this post, I want to show you how to break down an issue and make your contribution in different ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  So you want to fix an issue?
&lt;/h2&gt;

&lt;p&gt;Regardless of the issue's subject, here are the first few things you should do in most of the projects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone the project&lt;/li&gt;
&lt;li&gt;Follow the contributing guideline to set up the project (install dependencies, required services...etc.)&lt;/li&gt;
&lt;li&gt;Run the test suite and make sure they pass locally. If some of them failed, it could mean:

&lt;ul&gt;
&lt;li&gt;You haven't completed the setup or didn't do it correctly&lt;/li&gt;
&lt;li&gt;There's a compatibility issue between your environment and the project, which could be another contributing opportunity&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then depending on the issue, you might be able to start working on it right away. But it's also possible that you meet some obstacles and don't know how to proceed, as I mentioned earlier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don't have sufficient information about the issue&lt;/li&gt;
&lt;li&gt;You don't know how to reproduce it&lt;/li&gt;
&lt;li&gt;You are not sure if that's really a bug of the project or just an unsupported use case&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those obstacles, however, are actually the thing you can and should contribute to. Just answering any of the questions will make the issue one step further to be solved, either by you or others. &lt;/p&gt;

&lt;h2&gt;
  
  
  But what if I don't get any credits from it
&lt;/h2&gt;

&lt;p&gt;I know most people contribute to open source projects with the hope of helping their career growth with some nice showcases to put on the CV. I'm no exception. So I understand that spending dozens of hours to help others landing a bug fix PR doesn't feel like a good investment.&lt;/p&gt;

&lt;p&gt;But here's how I look at this: Many companies still use whiteboard interviews or homework assignments to test their candidates' problem-solving skills. However, since most of the companies aren't so great or have enough resources at hiring, those processes designed by them don't necessarily demonstrate your real capability.&lt;/p&gt;

&lt;p&gt;So why not using the issues you helped solving as evidence? Any issue you help solving can be a great proof of your conversation and coordination skills, whether it's a reproductions script you wrote or a comment to express your opinion on the solution. Sometimes, those non-coding contributions are as valuable as your PRs. Like this &lt;a href="https://github.com/getsentry/sentry-ruby/issues/738#issuecomment-592720365"&gt;comment&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you agree with my point above, let me show you how to contribute to an issue under different scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not having sufficient information about the issue
&lt;/h3&gt;

&lt;p&gt;Sometimes, the issue description may not provide sufficient information about the issue itself or the requirements to reproduce it. And if the project maintainer(s) don't have time to go after them one by one, the issue could remain unhandled for a while.&lt;/p&gt;

&lt;p&gt;Usually, a ready-to-solve issue should contain the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user's environment when encountering the issue, including

&lt;ol&gt;
&lt;li&gt;Project version (e.g., sentry-raven 3.1)&lt;/li&gt;
&lt;li&gt;Language version (e.g., Ruby 2.6)&lt;/li&gt;
&lt;li&gt;Operating system (e.g., MacOS 10.15.6)&lt;/li&gt;
&lt;li&gt;The version of other important libraries (e.g., Rails 6.0)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;The expected behavior&lt;/li&gt;
&lt;li&gt;The actual behavior&lt;/li&gt;
&lt;li&gt;Reproduction steps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if you found any issue that lacks the above information, you can kindly ask the issue author to provide more info to let you start working on it. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hello &lt;a class="mentioned-user" href="https://dev.to/st0012"&gt;@st0012&lt;/a&gt;, I'm interested in investigating this issue further, but I need more information to do so. Can you also tell me what Ruby version did you use when seeing the error? Thanks 😄&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usually, the author will reply rather quickly to move the issue forward. And once he/she has provided more information, you or other people can start working on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Not sure how to reproduce the issue
&lt;/h3&gt;

&lt;p&gt;If an issue can't be reproduced, it can't be solved with confidence. So if you find the reproduction steps are missing from the issue, you can be the one that provides one by&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a minimal app that can reproduce the issue with the given (or fewer) reproduction steps so other people can have an actual app to see the bug happens.&lt;/li&gt;
&lt;li&gt;Or writing a reproduction script that can demonstrate the problem just by executing it. A great example of this is &lt;a href="https://github.com/rails/rails/tree/master/guides/bug_report_templates"&gt;Rails' bug report templates&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Best scenario: writing a new test case for it

&lt;ul&gt;
&lt;li&gt;If you're certain the cause of the issue locates inside the project, this will be the most helpful thing to do.&lt;/li&gt;
&lt;li&gt;This could be hard because you'll also need to set up the project locally and make it runnable. But if you managed to do it, to you, the issue is more than halfway through!&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even if the author already provided reproduction steps, you can still try to reproduce the issue with a different setup, such as using a newer version of a library or Ruby to see if it still happens. This can help you and others find out the potential cause of the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate the issue's cause
&lt;/h3&gt;

&lt;p&gt;Even if the issue can be constantly reproduced, it doesn't necessarily mean it needs to be "fixed" for reasons like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not the expected usage of the project&lt;/li&gt;
&lt;li&gt;Caused by something else:

&lt;ul&gt;
&lt;li&gt;a conflict with other projects&lt;/li&gt;
&lt;li&gt;a bug in the dependencies&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So you need to validate the issue by understanding the project's scope, its dependencies, and the user's use case. Sometimes this also requires having a discussion with the project maintainer and other users of the project.&lt;/p&gt;

&lt;p&gt;You might feel like doing broad research in the step. But if you do it thoroughly, this will be the step you'll learn the most from. Here're the things you can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dive into the codebase and locate the root cause and report what you've found in the comments&lt;/li&gt;
&lt;li&gt;If the issue is caused by the project's bug, find the commit/PR that introduced it and share it in the comments. This will help tremendously. If it's a complicated issue, I also suggest you write down the paths you've visited during the investigation.&lt;/li&gt;
&lt;li&gt;If you're already familiar with the project (e.g., you're a heavy user), provides your opinion about the issue. This will help the maintainer decide whether to fix it or not or how to fix it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Fix It!
&lt;/h3&gt;

&lt;p&gt;If the issue you're looking at already has a detailed description, a reproduction script, and has been verified as the bug of the project, why not be the one that fixes the issue? Especially when you're the one that completed the previous steps, you can now call yourself the expert on the issue should be the best candidate to fix it!&lt;/p&gt;

&lt;p&gt;This part is pretty straightforward, as most of us fix bugs for a living 🙂. But I still want to provide some tips for you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Since it's a bug fix, you should add test case(s) that will fail without the fix (unless there's a reason not to so). I suggest you write the test cases before making any code changes. TDD works pretty well when fixing bugs for open source projects.&lt;/li&gt;
&lt;li&gt;Don't mix refactoring with bug fixes in the same commit. I know some refactorings might be inevitable for fixing the issue properly. So make sure you give the refactoring a standalone commit, which makes the code review a lot easier.&lt;/li&gt;
&lt;li&gt;Be patient. Every maintainer will be grateful to see you help them fix a bug and will try to merge the fix as soon as possible. But most of the maintainers maintain the project in their free time (which is very limited), and they could be busy reviewing other PRs or fixing other issues. So you may not get a quick response to the PR you just opened. I know how frustrating it could be, but it doesn't mean they don't cherish the hard work you just made.&lt;/li&gt;
&lt;li&gt;Make sure the maintainers can review your PR as easily as possible. This can be done by:

&lt;ol&gt;
&lt;li&gt;Making sure your PR pass the CI&lt;/li&gt;
&lt;li&gt;Making sure your code follows the coding style guide of the project&lt;/li&gt;
&lt;li&gt;Explaining the cause of the issue in detail. Like:

&lt;ul&gt;
&lt;li&gt;because &lt;code&gt;method_a&lt;/code&gt; called &lt;code&gt;method_b&lt;/code&gt; at &lt;code&gt;file.rb:120&lt;/code&gt; with the string &lt;code&gt;"foo"&lt;/code&gt; under certain circumstances, it caused the &lt;code&gt;baz&lt;/code&gt; method in &lt;code&gt;Bar&lt;/code&gt; class to return the incorrect &lt;code&gt;"xyz"&lt;/code&gt; result and caused this issue.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Depending on the nature of that issue, there could be multiple ways to fix it. So you may want to explain the approach you chose and why you think it's the best approach

&lt;ul&gt;
&lt;li&gt;since the &lt;code&gt;method_b&lt;/code&gt; is a private method that is only called by &lt;code&gt;method_a&lt;/code&gt;, I figure adding an argument check in &lt;code&gt;method_a&lt;/code&gt; will be sufficient to prevent this from happening again.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key concept is: make your PR's purpose clear, so even a busy maintainer can easily review the content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Note
&lt;/h2&gt;

&lt;p&gt;I'm not sure if you have noticed them, but the steps above actually make a full process of solving an issue. Each one of them helps understanding the project better from a different aspect. This means that even if you only make a partial contribution at a time, sooner or later, you'll be capable of solving an issue by yourself.&lt;/p&gt;

&lt;p&gt;So I hope after reading this post, you're now more confident about making your first or next contribution to open source projects. It's really not that hard to do. And as a community, we really need your contribution to keep the projects moving forward!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Completely Remove Ruby 2.7's Default Bundler</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Sun, 09 Aug 2020 06:26:34 +0000</pubDate>
      <link>https://dev.to/st0012/completely-remove-the-default-bundler-from-ci-environment-j0c</link>
      <guid>https://dev.to/st0012/completely-remove-the-default-bundler-from-ci-environment-j0c</guid>
      <description>&lt;p&gt;Ruby 2.7 comes with the default &lt;code&gt;bundler&lt;/code&gt; gem, which always has &lt;code&gt;2.0+&lt;/code&gt; version. This is a great default in general, especially to the beginners. But in some cases, like when using &lt;code&gt;Rails 4&lt;/code&gt;, we want to keep the &lt;code&gt;bundler&lt;/code&gt; version under &lt;code&gt;2.0&lt;/code&gt; to avoid conflicts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bundler could not find compatible versions for gem "bundler":
  In Gemfile:
    rails (~&amp;gt; 4.2) was resolved to 4.2.11.3, which depends on
      bundler (&amp;lt; 2.0, &amp;gt;= 1.3.0)
  Current Bundler version:
    bundler (2.1.4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;However, it's not easy to rollback to a older version of &lt;code&gt;bundler&lt;/code&gt;. Since the &lt;code&gt;2.0+&lt;/code&gt; version will be installed as a default gem, simply uninstall it won't work:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gem uninstall bundler
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; Gem bundler-2.1.4 cannot be uninstalled because it is a default gem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And these tricks won't work either (at least they didn't work for me):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nt"&gt;-v&lt;/span&gt;
Bundler version 2.1.4

&lt;span class="nv"&gt;$ &lt;/span&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;bundler:1.17.3 &lt;span class="nt"&gt;--default&lt;/span&gt;
Successfully installed bundler-1.17.3 as a default gem
Done installing documentation &lt;span class="k"&gt;for &lt;/span&gt;bundler after 0 seconds
1 gem installed

&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nt"&gt;-v&lt;/span&gt;
Bundler version 2.1.4

&lt;span class="nv"&gt;$ &lt;/span&gt;bundle config default 1.17.3
&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nt"&gt;-v&lt;/span&gt;
Bundler version 2.1.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;From all the references I can find, the only way to remove it is to delete the &lt;code&gt;bundler-2.1.4.gemspec&lt;/code&gt; file from the gem path. The following commands did the trick for me:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;gem &lt;span class="nb"&gt;env &lt;/span&gt;gempath
/Users/st0012/.gem/ruby/2.7.0:/Users/st0012/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; /Users/st0012/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/specifications/&lt;span class="k"&gt;**&lt;/span&gt;/bundler-&lt;span class="k"&gt;*&lt;/span&gt;.gemspec
/Users/st0012/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/specifications/default/bundler-2.1.4.gemspec
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; /Users/st0012/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/specifications/&lt;span class="k"&gt;**&lt;/span&gt;/bundler-2.1.4.gemspec
&lt;span class="nv"&gt;$ &lt;/span&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;bundler:1.17.3 &lt;span class="nt"&gt;--default&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nt"&gt;-v&lt;/span&gt;
Bundler version 1.17.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;But what if we want to perform the same cleanup on CI (like &lt;code&gt;travis-ci&lt;/code&gt;) too? Well, I wrote a script for you:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env ruby&lt;/span&gt;

&lt;span class="n"&gt;gempaths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`gem env gempath`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;gempaths&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;gempath&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# lookup bundler-*.gemspec files and delete them&lt;/span&gt;
  &lt;span class="c1"&gt;# this is the only way to completely cleanup default bundler&lt;/span&gt;
  &lt;span class="c1"&gt;# Note: the bundler gemspecs' paths are different for CRuby and JRuby&lt;/span&gt;
  &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gempath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"/specifications/**/bundler-*.gemspec"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Remember to make this file executable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then you can add this to your CI config file (&lt;code&gt;.travis.yml&lt;/code&gt; for example):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;before_install&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./cleanup_bundler&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gem install bundler -v '1.17'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And that's it! I hope this short post can save you from pulling your hair for a few hours 😉&lt;/p&gt;

&lt;p&gt;If you're a Rubyist and you like this post, please also check the debugging tools I wrote:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/st0012"&gt;
        st0012
      &lt;/a&gt; / &lt;a href="https://github.com/st0012/object_tracer"&gt;
        object_tracer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ObjectTracer tracks objects and records their activities
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/st0012"&gt;
        st0012
      &lt;/a&gt; / &lt;a href="https://github.com/st0012/power_trace"&gt;
        power_trace
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Buff exception backtrace with local variables, passed in arguments and instance variables!
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>ruby</category>
      <category>ci</category>
      <category>bundler</category>
    </item>
    <item>
      <title>Replace A Rails Initializer</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Sun, 31 May 2020 05:59:38 +0000</pubDate>
      <link>https://dev.to/st0012/how-to-replace-a-rails-initializer-30n0</link>
      <guid>https://dev.to/st0012/how-to-replace-a-rails-initializer-30n0</guid>
      <description>&lt;p&gt;Rails uses a series of initializers to initialize your application. While some of them might come from the gems you use, most of them are the Rails' built-in ones. And in some rare cases, you might need to customize some of them for special usages. &lt;/p&gt;

&lt;p&gt;For example, I had to replace my app's &lt;code&gt;set_routes_reloader_hook&lt;/code&gt; initializer (the one that generates routes for your application) to benchmark our route generation logic. And it took a while to figure out how to do it the right way.&lt;/p&gt;

&lt;p&gt;So if you don't need to do this, that's totally normal. But if you do, this post is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Steps
&lt;/h2&gt;

&lt;p&gt;In this post, I'll use the &lt;code&gt;set_routes_reloader_hook&lt;/code&gt; initializer as our example. And the replacement will be done in 3 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify the Initializer's Source&lt;/li&gt;
&lt;li&gt;Register the New Initializer&lt;/li&gt;
&lt;li&gt;Drop the Old Initializer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And finally, I'll show you how to reuse the original initializer's body instead of copy&amp;amp;paste the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Identify the Initializer's Source
&lt;/h3&gt;

&lt;p&gt;When talking about replacing a Rails initializer, your first thought might be modifying the &lt;code&gt;Rails::Application#initializers&lt;/code&gt; directly. But that won't work.&lt;/p&gt;

&lt;p&gt;In Rails, &lt;code&gt;Rails::Application#initializers&lt;/code&gt; actually consists of 3 initializer sources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initializers&lt;/span&gt; &lt;span class="c1"&gt;#:nodoc:&lt;/span&gt;
  &lt;span class="no"&gt;Bootstrap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializers_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="n"&gt;railties_initializers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="no"&gt;Finisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializers_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;So every time you call &lt;code&gt;Rails::Application#initializers&lt;/code&gt;, it returns a new array of initializers, and the change made on it won't be applied to the rest of the app.&lt;/p&gt;

&lt;p&gt;What we need to do instead, is to identify which source that our target initializer belongs to:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Bootstrap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializers_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:set_routes_reloader_hook&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; false&lt;/span&gt;
&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializers_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:set_routes_reloader_hook&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; false&lt;/span&gt;
&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Finisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializers_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:set_routes_reloader_hook&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now we can see that the &lt;code&gt;set_routes_reloader_hook&lt;/code&gt; is defined in &lt;code&gt;Rails::Application::Finisher&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Register the New Initializer
&lt;/h3&gt;

&lt;p&gt;Because Rails executes initializers in the order they are defined, we need to make sure the new initializer is placed in the right place. So we need to use the target initializer as our index before dropping it. To do this, we can use the &lt;code&gt;before&lt;/code&gt; or &lt;code&gt;after&lt;/code&gt; argument when registering the new initializer:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/application.rb&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails/all'&lt;/span&gt;

&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Finisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializer&lt;/span&gt; &lt;span class="ss"&gt;:set_routes_reloader_hook_with_benchmark&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;after: :set_routes_reloader_hook&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# ....&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Drop the Old Initializer
&lt;/h3&gt;

&lt;p&gt;And then the last step: drop the target initializer&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/application.rb&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails/all'&lt;/span&gt;

&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Finisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializer&lt;/span&gt; &lt;span class="ss"&gt;:set_routes_reloader_hook_with_benchmark&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;after: :set_routes_reloader_hook&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# ....&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Finisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:set_routes_reloader_hook&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Additional Tip: Reuse the Old Initializer
&lt;/h3&gt;

&lt;p&gt;Since we're "replacing" the initializer instead of just dropping it or adding a new one, it means the new initializer may be very similar to the old one or just an extension of it. But because initializers aren't methods, we can't use &lt;code&gt;super&lt;/code&gt; like&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;set_routes_reloader_hook&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;
  &lt;span class="c1"&gt;# other stuff you want to do&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If this is bothering you, here's a trick: We can extract the old initializer's block, and use &lt;code&gt;instance_eval&lt;/code&gt; to evaluate it inside the new initializer&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;
&lt;span class="n"&gt;original_initializer_block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Finisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;detect&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target_initializer&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;block&lt;/span&gt;

&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Finisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializer&lt;/span&gt; &lt;span class="ss"&gt;:new_initializer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;after: &lt;/span&gt;&lt;span class="n"&gt;target_initializer&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;instance_eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;original_initializer_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# other stuff you want to do&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Finisher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reject!&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target_initializer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Thank you for reading this post. If you like it, I also wrote some articles about debugging Rails applications/Ruby programs&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/appsignal" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F232%2F7dc003c2-662a-43dd-a72d-59b6ce86cdb3.png" alt="AppSignal"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F238727%2F9cabf22f-2f6a-44d5-b823-6c8319c288d4.jpg" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/appsignal/changing-the-approach-to-debugging-in-ruby-with-tracepoint-45k9" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Changing the Approach to Debugging in Ruby with TracePoint&lt;/h2&gt;
      &lt;h3&gt;Stan Lo for AppSignal ・ Apr 9 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#ruby&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rails&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;




&lt;div class="ltag__link"&gt;
  &lt;a href="/st0012" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F238727%2F9cabf22f-2f6a-44d5-b823-6c8319c288d4.jpg" alt="st0012"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/st0012/optimize-your-debugging-process-with-object-oriented-tracing-and-tappingdevice-39c6" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Optimize Your Debugging Process With Object-Oriented Tracing and tapping_device&lt;/h2&gt;
      &lt;h3&gt;Stan Lo ・ Jan 21 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#showdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rails&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#ruby&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#tutorial&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I'm also working on a gem called &lt;a href="https://github.com/st0012/tapping_device" rel="noopener noreferrer"&gt;tapping_device&lt;/a&gt;. It can help you debug Ruby programs more easily by making objects tell you what they do. &lt;br&gt;
Not sure what it means? There are examples in the readme 👇&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/st0012" rel="noopener noreferrer"&gt;
        st0012
      &lt;/a&gt; / &lt;a href="https://github.com/st0012/object_tracer" rel="noopener noreferrer"&gt;
        object_tracer
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      ObjectTracer tracks objects and records their activities
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>rails</category>
      <category>tutorial</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Changing the Approach to Debugging in Ruby with TracePoint</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Thu, 09 Apr 2020 14:54:28 +0000</pubDate>
      <link>https://dev.to/appsignal/changing-the-approach-to-debugging-in-ruby-with-tracepoint-45k9</link>
      <guid>https://dev.to/appsignal/changing-the-approach-to-debugging-in-ruby-with-tracepoint-45k9</guid>
      <description>&lt;p&gt;Ruby has always been known for the productivity it brings to its developers. Alongside features such as elegant syntax, rich meta-programming support, etc. that make you productive when writing code, it also has another secret weapon called &lt;code&gt;TracePoint&lt;/code&gt; that can help you "debug" faster.&lt;/p&gt;

&lt;p&gt;In this post, I'll use a simple example to show you 2 interesting facts I found out about debugging:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Most of the time, finding the bug itself isn't hard, but understanding how your program works in detail is. Once you have a deep understanding of this, you can usually spot the bug right away.&lt;/li&gt;
&lt;li&gt;Observing your program down to the method call level is time-consuming, and is the major bottleneck of our debugging process.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then, I'll show you how &lt;code&gt;TracePoint&lt;/code&gt; could change the way we approach debugging by making the program "tell us" what it's doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Is about Understanding Your Program and Its Design
&lt;/h2&gt;

&lt;p&gt;Let's assume we have a Ruby program called &lt;code&gt;plus_1&lt;/code&gt; and it's not functioning correctly. How do we debug this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# plus_1.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="n"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ideally, we should be able to address the bug in 3 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Learn the expectations from the design&lt;/li&gt;
&lt;li&gt;Understand the current implementation&lt;/li&gt;
&lt;li&gt;Trace the bug&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Learning the Expectations from the Design
&lt;/h3&gt;

&lt;p&gt;What's the expected behavior here? &lt;code&gt;plus_1&lt;/code&gt; should add &lt;code&gt;1&lt;/code&gt; to its argument, which is our input from the command line. But how do we "know" this?&lt;/p&gt;

&lt;p&gt;In a real-world case, we can understand the expectations by reading test cases, documents, mockups, asking other people for feedback, etc. Our understanding depends on how the program is "designed".&lt;/p&gt;

&lt;p&gt;This step is the most crucial part of our debugging process. If you don't understand how the program should work, you'll never be able to debug it.&lt;/p&gt;

&lt;p&gt;However, there are many factors that can be part of this step, such as team coordination, development workflow, etc. &lt;code&gt;TracePoint&lt;/code&gt; won't be able to help you with those, so we won't dwell on these problems today.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the Current Implementation
&lt;/h3&gt;

&lt;p&gt;Once we've understood the expected behavior of the program, we need to learn how it functions at the moment.&lt;/p&gt;

&lt;p&gt;In most cases, we need the following information to fully understand how a program works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The methods called during the program's execution&lt;/li&gt;
&lt;li&gt;The call and return order of the method calls&lt;/li&gt;
&lt;li&gt;Arguments passed to each method call&lt;/li&gt;
&lt;li&gt;Values returned from each method call&lt;/li&gt;
&lt;li&gt;Any side effects that happened during each method call, e.g. data mutation or database requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's describe our example with the above information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# plus_1.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="n"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Defines a method called &lt;code&gt;plus_1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Retrieves the input (&lt;code&gt;"1"&lt;/code&gt;) from &lt;code&gt;ARGV&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;to_i&lt;/code&gt; on &lt;code&gt;"1"&lt;/code&gt;, which returns &lt;code&gt;1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Assigns &lt;code&gt;1&lt;/code&gt; to local variable &lt;code&gt;input&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;plus_1&lt;/code&gt; method with &lt;code&gt;input&lt;/code&gt;(&lt;code&gt;1&lt;/code&gt;) as its argument. The parameter &lt;code&gt;n&lt;/code&gt; now carries a value of &lt;code&gt;1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;+&lt;/code&gt; method on &lt;code&gt;1&lt;/code&gt; with an argument &lt;code&gt;2&lt;/code&gt;, and returns the result &lt;code&gt;3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;3&lt;/code&gt; for step 5&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;puts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;to_s&lt;/code&gt; on &lt;code&gt;3&lt;/code&gt;, which returns &lt;code&gt;"3"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Passes &lt;code&gt;"3"&lt;/code&gt; to the &lt;code&gt;puts&lt;/code&gt; call from step 8, which triggers a side effect that prints the string to Stdout. Then it returns &lt;code&gt;nil&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The description isn't 100% accurate, but it's enough for a simple explanation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Addressing the Bug
&lt;/h3&gt;

&lt;p&gt;Now that we've learned how our program should work and how it actually works, we can start looking for the bug. With the information we have, we can search for the bug by following the method calls upward (start from step 10) or downward (start from step 1). In this case, we can do it by tracing back to the method that returned 3 in the first place⁠—which is the &lt;code&gt;1 + 2&lt;/code&gt; in &lt;code&gt;step 6&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  This Is Far from Reality!
&lt;/h3&gt;

&lt;p&gt;Of course, we all know that real debugging isn't as simple as the example makes it out to be. The critical difference between real-life programs and our example is the size. We used 10 steps to explain a 5-line program. How many steps would we need for a small Rails app? It's basically impossible to break down a real program as detailed as we did for the example.&lt;br&gt;
Without a detailed understanding of your program, you won't be able to track down the bug through an obvious path, so you'll need to make assumptions or guesses.&lt;/p&gt;
&lt;h2&gt;
  
  
  Information Is Expensive
&lt;/h2&gt;

&lt;p&gt;As you probably already noticed, the key factor in debugging is how much information you have. But what does it take to retrieve that much information? Let's see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# plus_1_with_tracing.rb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"n = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;raw_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"raw_input: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"input: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"result of plus_1 &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ ruby plus_1_with_tracing.rb 1
raw_input: 1
input: 1
n = 1
result of plus_1: 3
3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we only get 2 types of information here: values of some variables and the evaluation order of our &lt;code&gt;puts&lt;/code&gt; (which implies the program's execution order).&lt;/p&gt;

&lt;p&gt;How much does this information cost us?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt; def plus_1(n)
&lt;span class="gi"&gt;+  puts("n = #{n}")
&lt;/span&gt;   n + 2
 end

-input = ARGV[0].to_i
&lt;span class="gd"&gt;-puts(plus_1(input))
&lt;/span&gt;&lt;span class="gi"&gt;+raw_input = ARGV[0]
+puts("raw_input: #{raw_input}")
+input = raw_input.to_i
+puts("input: #{input}")
+
+result = plus_1(input)
+puts("result of plus_1: #{result}")
+
+puts(result)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only do we need to add 4 &lt;code&gt;puts&lt;/code&gt; into the code, but, in order to print values separately, we also need to split our logic in order to access the intermediate states of some values. In this case, we got 4 additional outputs for the internal states with 8 lines of changes. That's 2 lines of changes for 1 line of output, on average! And since the number of changes grows linearly with the size of the program, we can compare it to an &lt;code&gt;O(n)&lt;/code&gt; operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Is Debugging Expensive?
&lt;/h3&gt;

&lt;p&gt;Our programs can be written with many goals in mind: maintainability, performance, simplicity, etc. but usually not for "Traceability", meaning, getting the values for inspection, which usually requires a modification of the code, e.g. splitting chained method calls.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The more the information you get, the more additions/changes you need to make to the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, once the amount of information you get reaches a certain point, you won't be able to process it efficiently. So we either need to filter the information out or label it to help us understand it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The more precise the information, the more additions/changes you need to make to the code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, because the work involves touching the codebase⁠—which can be very different between bugs (e.g. controller vs. model logic)⁠—it's hard to automate it. Even if your codebase is tracing-friendly (e.g. it follows "Law of Demeter" strictly), most of the time, you'll need to type different variable/method names manually.&lt;/p&gt;

&lt;p&gt;(Actually, in Ruby, there are some tricks to avoid this⁠—like &lt;code&gt;__method__&lt;/code&gt;. But let's not complicate things here.)&lt;/p&gt;

&lt;h2&gt;
  
  
  TracePoint: The Savior
&lt;/h2&gt;

&lt;p&gt;However, Ruby provides us an exceptional tool that can largely reduce the cost: &lt;code&gt;TracePoint&lt;/code&gt;. I bet most of you have already heard of it or used it before. But in my experience, not many people use this powerful tool in daily debugging practices.&lt;/p&gt;

&lt;p&gt;Let me show you how to use it to collect information quickly. This time, we don't need to touch any of our existing logic, we just need some code before it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:return&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:c_call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:c_return&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/(.+(call|return))/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'\2'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;rjust&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; of &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defined_class&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;#&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callee_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; on &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="c1"&gt;# if you call `return` on any non-return events, it'll raise error&lt;/span&gt;
  &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s2"&gt;" =&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;return_value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;event&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:return&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;event&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:c_return&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;to_i&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plus_1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run the code, you'll see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return of #&amp;lt;Class:TracePoint&amp;gt;#trace on TracePoint =&amp;gt; #&amp;lt;TracePoint:c_return `trace'@plus_1_with_trace_point.rb:1&amp;gt;
  call of Module#method_added on Object
return of Module#method_added on Object =&amp;gt; nil
  call of String#to_i on "1"
return of String#to_i on "1" =&amp;gt; 1
  call of Object#plus_1 on main
return of Object#plus_1 on main =&amp;gt; 3
  call of Kernel#puts on main
  call of IO#puts on #&amp;lt;IO:&amp;lt;STDOUT&amp;gt;&amp;gt;
  call of Integer#to_s on 3
return of Integer#to_s on 3 =&amp;gt; "3"
  call of IO#write on #&amp;lt;IO:&amp;lt;STDOUT&amp;gt;&amp;gt;
3
return of IO#write on #&amp;lt;IO:&amp;lt;STDOUT&amp;gt;&amp;gt; =&amp;gt; 2
return of IO#puts on #&amp;lt;IO:&amp;lt;STDOUT&amp;gt;&amp;gt; =&amp;gt; nil
return of Kernel#puts on main =&amp;gt; nil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our code is much more readable now. Isn't it amazing? It prints out most of the program execution with lots of details! We can even map it with my earlier execution breakdown:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Defines a method called &lt;code&gt;plus_1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Retrieves the input (&lt;code&gt;"1"&lt;/code&gt;) from &lt;code&gt;ARGV&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;to_i&lt;/code&gt; on &lt;code&gt;"1"&lt;/code&gt;, which returns &lt;code&gt;1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Assigns &lt;code&gt;1&lt;/code&gt; to local variable &lt;code&gt;input&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;plus_1&lt;/code&gt; method with &lt;code&gt;input&lt;/code&gt;(&lt;code&gt;1&lt;/code&gt;) as its argument. The parameter &lt;code&gt;n&lt;/code&gt; now carries a value &lt;code&gt;1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;+&lt;/code&gt; method on &lt;code&gt;1&lt;/code&gt; with an argument &lt;code&gt;2&lt;/code&gt;, and returns the result &lt;code&gt;3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;3&lt;/code&gt; for step 5&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;puts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Calls &lt;code&gt;to_s&lt;/code&gt; on &lt;code&gt;3&lt;/code&gt;, which returns &lt;code&gt;"3"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Passes &lt;code&gt;"3"&lt;/code&gt; to the &lt;code&gt;puts&lt;/code&gt; call from step 8, which triggers a side effect that prints the string to Stdout. And then it returns &lt;code&gt;nil&lt;/code&gt;.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ignore this, it's TracePoint tracing itself ;D
return of #&amp;lt;Class:TracePoint&amp;gt;#trace on TracePoint =&amp;gt; #&amp;lt;TracePoint:c_return `trace'@plus_1_with_trace_point.rb:1&amp;gt;

  call of Module#method_added on Object         # 1. Defines a method called `plus_1`.
return of Module#method_added on Object =&amp;gt; nil
  call of String#to_i on "1"                    # 3-1. Calls `to_i` on `"1"`
return of String#to_i on "1" =&amp;gt; 1               # 3-2. which returns `1`
  call of Object#plus_1 on main                 # 5. Calls `plus_1` method with `input`(`1`) as its argument.
return of Object#plus_1 on main =&amp;gt; 3            # 7. Returns `3` for step 5
  call of Kernel#puts on main                   # 8. Calls `puts`
  call of IO#puts on #&amp;lt;IO:&amp;lt;STDOUT&amp;gt;&amp;gt;
  call of Integer#to_s on 3                     # 9. Calls `to_s` on `3`, which returns `"3"`
return of Integer#to_s on 3 =&amp;gt; "3"
  call of IO#write on #&amp;lt;IO:&amp;lt;STDOUT&amp;gt;&amp;gt;            # 10-1. Passes `"3"` to the `puts` call from step 8
                                                # 10-2. which triggers a side effect that prints the string to Stdout
3 # original output
return of IO#write on #&amp;lt;IO:&amp;lt;STDOUT&amp;gt;&amp;gt; =&amp;gt; 2
return of IO#puts on #&amp;lt;IO:&amp;lt;STDOUT&amp;gt;&amp;gt; =&amp;gt; nil
return of Kernel#puts on main =&amp;gt; nil            # 10-3. And then it returns `nil`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can even say it's more detailed than what I said earlier! However, you may notice that steps 2, 4 and 6 are missing from the output. Unfortunately, they are not trackable by &lt;code&gt;TracePoint&lt;/code&gt; for the following reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2. Retrieves the input (&lt;code&gt;"1"&lt;/code&gt;) from &lt;code&gt;ARGV&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ARGV&lt;/code&gt; and the following &lt;code&gt;[]&lt;/code&gt; aren't considered as call/c_call at the moment&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;4. Assigns &lt;code&gt;1&lt;/code&gt; to local variable &lt;code&gt;input&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Currently, there's no event for variable assignments. We can (sort of) track it with &lt;code&gt;line&lt;/code&gt; event + regex, but it won't be accurate&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;6. Calls &lt;code&gt;+&lt;/code&gt; method on &lt;code&gt;1&lt;/code&gt; with an argument &lt;code&gt;2&lt;/code&gt;, and returns the result &lt;code&gt;3&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Certain method calls like built-in &lt;code&gt;+&lt;/code&gt; or attributes accessor methods aren't trackable at the moment&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  From O(n) to O(log n)
&lt;/h3&gt;

&lt;p&gt;As you can see from the previous example, with proper usage of &lt;code&gt;TracePoint&lt;/code&gt;, we can almost make the program "tell us" what it's doing. Now, because of the number of lines we need, &lt;code&gt;TracePoint&lt;/code&gt; doesn't grow linearly with the size of our program. I'd say the whole process becomes an &lt;code&gt;O(log(n))&lt;/code&gt; operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;In this article, I've explained the main difficulty with debugging. Hopefully, I've also convinced you of how &lt;code&gt;TracePoint&lt;/code&gt; could be a game-changer. But if you try &lt;code&gt;TracePoint&lt;/code&gt; right now, it'll probably frustrate you more than help you.&lt;/p&gt;

&lt;p&gt;With the amount of information that comes from &lt;code&gt;TracePoint&lt;/code&gt;, you'll soon be swamped by the noise. The new challenge is to filter out the noise, leaving valuable information. For example, in most cases, we only care about specific models or service objects. In these cases, we can filter calls by the receiver's class, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# tracing logic&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another thing to keep in mind is that the block you define for &lt;code&gt;TracePoint&lt;/code&gt; could be evaluated tens of thousands of times. At this scale, how you implement the filtering logic can have a great impact on your app's performance. For example, I don't recommend this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;trace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;caller&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"app"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# tracing logic&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For these 2 problems, I've prepared another article to let you know of some tricks and gotchas I found with some useful boilerplates for typical Ruby/Rails applications.&lt;/p&gt;

&lt;p&gt;And if you find this concept interesting, I also created a gem called &lt;a href="https://github.com/st0012/tapping_device"&gt;tapping_device&lt;/a&gt; that hides all the implementation hassles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Debugger and tracing are both great tools for debugging, and we have been using them for many years. But as I've demonstrated in this article, using them requires many manual operations during the debugging process. However, with the help of &lt;code&gt;TracePoint&lt;/code&gt;, you can automate many of them and thus boost your debugging performance. I hope you can now add &lt;code&gt;TracePoint&lt;/code&gt; to your debugging toolbox and give it a try.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Our guest writer Stan is a Senior Software Engineer @ticketsolve. He loves cats, Ruby on Rails and boxing. He created Goby and works on tapping_device during the weekends.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Optimize Your Debugging Process With Object-Oriented Tracing and tapping_device</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Tue, 21 Jan 2020 13:15:50 +0000</pubDate>
      <link>https://dev.to/st0012/optimize-your-debugging-process-with-object-oriented-tracing-and-tappingdevice-39c6</link>
      <guid>https://dev.to/st0012/optimize-your-debugging-process-with-object-oriented-tracing-and-tappingdevice-39c6</guid>
      <description>&lt;p&gt;As programmers, debugging is one of our daily tasks. And it’s important to sharpen our debugging skills along with other programming skills. But have you ever noticed that, when we’re getting better and better at refactoring, testing, and other coding skills, our debugging skill doesn’t grow as fast as them? In fact, I found myself still using the same debugging tool and process I used 2, 3 years ago.&lt;/p&gt;

&lt;p&gt;In the past few weeks, I tried to find a way to debug more effectively. In this post, I will share the reason why it is so hard to improve our debugging skills and how I come up with another approach to tackle this issue.&lt;/p&gt;

&lt;p&gt;(To make it easier to explain, the “Bug” here only refers to &lt;strong&gt;a piece of code that breaks a previously working program&lt;/strong&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Content
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;How Do We Debug Our Program - Path Comparison Debugging

&lt;ol&gt;
&lt;li&gt;Build Execution Paths&lt;/li&gt;
&lt;li&gt;Compare Execution Paths&lt;/li&gt;
&lt;li&gt;The Technical Challenge of This Technic&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Object-Oriented Tracing

&lt;ol&gt;
&lt;li&gt;What Is It&lt;/li&gt;
&lt;li&gt;What Problem Does It Solve&lt;/li&gt;
&lt;li&gt;TappingDevice&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Conclusion&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  How Do We Debug Our Program
&lt;/h2&gt;

&lt;p&gt;The way we usually debug our program is actually very primitive: “Compare”. We do it by comparing how the program should work with how it actually works, and find the places that act differently during the program execution. Most of the time, those places are the keys to finding the bug, if not the bug itself. It’s a 3-steps process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the Expected Execution Path&lt;/li&gt;
&lt;li&gt;Build the Actual Execution Path&lt;/li&gt;
&lt;li&gt;Compare Both Paths&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FEXf9URA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FEXf9URA.png" alt="code paths image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Build the Execution Paths
&lt;/h3&gt;

&lt;p&gt;The “Execution Path” of a program can somehow be thought of as its path of method/function calls, or simply call it "call path". But depends on the size of the program, it might perform many method calls. So usually, we only mean “the call path of business logic related methods”. For example, during a request to &lt;code&gt;OrdersController#create&lt;/code&gt;, there can be many method calls like, &lt;code&gt;Array#[]&lt;/code&gt;, &lt;code&gt;Object#inspect&lt;/code&gt;…etc. But when we’re building the execution paths, we only care about those related to Order’s creation and ignore others.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compare Execution Paths
&lt;/h3&gt;

&lt;p&gt;Under most conditions, the bug of the program can be found in the first place that acts differently (returning a different value, calls different methods…etc.). So in the following case, the bug is probably inside the &lt;code&gt;bar&lt;/code&gt; method or its dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FTO3Bcb6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FTO3Bcb6.png" alt="bug in bar method's example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Challenge of This Technique
&lt;/h3&gt;

&lt;p&gt;I believe most people debug like this approach, but not exactly the same. Ideally, we should build the execution paths as detailed as possible, so we can have enough information to make an accurate comparison. However, in reality, for reasons like the limit amount of time, or laziness..etc., we usually just pick some methods that we “guess” are related to the bug, and hope we made the right guess. 🤞&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FpBmZf0u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FpBmZf0u.png" alt="ideal vs reality"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It means that the effectiveness of our debugging practices are determined by the method we pick to build the paths. And that can be affected by &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Our experience in the language/framework&lt;/li&gt;
&lt;li&gt;How well do we understand the codebase&lt;/li&gt;
&lt;li&gt;Luck?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why we still debug faster over time, even though we don’t put too much attention on our debugging skills.&lt;/p&gt;

&lt;p&gt;In my opinion, the root cause of this phenomenon is that we don’t have an efficient tool to work with our debugging strategy. Whether you’re a &lt;code&gt;puts&lt;/code&gt; debugger or a &lt;code&gt;pry&lt;/code&gt;-debugger. For most of the time, inspecting the program’s behavior is an overwhelming job, for several reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;We need to collect  arguments manually&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# super annoying&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"var1: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;var1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"var2: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;var2&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# …&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We need to collect return values manually&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# eithr&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new_cart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;tap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# or &lt;/span&gt;
&lt;span class="n"&gt;cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_cart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need to jump between different methods, or even files to place the &lt;code&gt;puts&lt;/code&gt; or breakpoints.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The more manual job it needs to collect information, the more likely we’ll just make a guess and take a chance. Despite being annoying, manually collecting these different kinds of information also creates other problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To collect the information we need effectively (e.g., at the right place, call the right method), we need to understand the program well enough. So the less experienced you are, the harder you can understand the program.&lt;/li&gt;
&lt;li&gt;Adding breakpoints or tracing methods is a kind of code pollution. For example, if a method changes an object’s state and you call it when tracing the code (to get its return value or something), it’d change the program’s behavior.&lt;/li&gt;
&lt;li&gt;In my personal experience, when messing around with the code, it’s easy to forget my original purpose is just to inspect the method call and start digging deeper.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Object-Oriented Tracing
&lt;/h2&gt;

&lt;p&gt;But if we look at our debugging behavior close enough, we can find some patterns that we might take advantage of. For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you’re debugging a web application’s feature, we can start from a specific endpoint’s logic (e.g., particular controller action). Which gives us a perfect position to start the debugging process.&lt;/li&gt;
&lt;li&gt;In an object-oriented programming language like Ruby, a feature can usually be linked to 1 or a few classes. For example, you know you should look for something like &lt;code&gt;OrderCreationService&lt;/code&gt; when there’s a bug about orders. So you can build the most of the execution paths by observing one or a few object’s method calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And the concept “Object-Oriented Tracing” is built upon the above assumptions and Ruby’s powerful &lt;code&gt;TracePoint&lt;/code&gt; feature. Let me explain it with examples.&lt;/p&gt;

&lt;p&gt;Assume we have an &lt;code&gt;OrdersController#create&lt;/code&gt; endpoint for creating orders&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:cart_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;promotion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Promotion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:promotion_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OrderCreationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@cart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promotion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="err"&gt;……&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we want to build the execution path of Order’s creation. We can write&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:cart_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;promotion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Promotion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:promotion_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"OrderCreationService"&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Called :&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callee_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lineno&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OrderCreationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@cart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promotion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which would print&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Called :initialize from /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:2
Called :perform from /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:6
Called :validate_cart from /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:17
Called :apply_discount from /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:23
Called :create_order from /Users/st0012/projects/tapping_device-demo/app/services/order_creation_service.rb:27
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we know what the &lt;code&gt;OrderCreationService&lt;/code&gt; does to create an Order, we have a pretty clear execution path immediately. But with some of Ruby’s meta-programming tricks, we can get more information, like each method call’s arguments!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:cart_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;promotion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Promotion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:promotion_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"OrderCreationService"&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Called :&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callee_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lineno&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local_variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local_variable_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  Arg &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OrderCreationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@cart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promotion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:initialize&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;options: &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:perform&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;cart: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 10, customer_id: 1, promotion_id: nil, reserved_until: nil, created_at: "2020-01-19 08:41:51", updated_at: "2020-01-19 08:41:51"&amp;gt;&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;promotion: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-19 08:41:51", updated_at: "2020-01-19 08:41:51"&amp;gt;&lt;/span&gt;

&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:validate_cart&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;cart: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 10, customer_id: 1, promotion_id: nil, reserved_until: nil, created_at: "2020-01-19 08:41:51", updated_at: "2020-01-19 08:41:51"&amp;gt;&lt;/span&gt;

&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:apply_discount&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;cart: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 10, customer_id: 1, promotion_id: nil, reserved_until: nil, created_at: "2020-01-19 08:41:51", updated_at: "2020-01-19 08:41:51"&amp;gt;&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;promotion: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-19 08:41:51", updated_at: "2020-01-19 08:41:51"&amp;gt;&lt;/span&gt;

&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:create_order&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;27&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;cart: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-19 08:41:51", updated_at: "2020-01-19 08:41:51"&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isn’t this super cool? Now we know what method got called and what arguments they took. Let’s add the last piece of information: the return value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:cart_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;promotion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Promotion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:promotion_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:return&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"OrderCreationService"&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Called :&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callee_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lineno&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local_variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local_variable_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  Arg &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  =&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;return_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OrderCreationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@cart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promotion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:initialize&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;options: &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:validate_cart&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;cart: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 10, customer_id: 1, promotion_id: nil, reserved_until: nil, created_at: "2020-01-19 08:59:13", updated_at: "2020-01-19 08:59:13"&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;

&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:apply_discount&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;cart: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-19 08:59:13", updated_at: "2020-01-19 08:59:13"&amp;gt;&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;promotion: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-19 08:59:13", updated_at: "2020-01-19 08:59:13"&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;

&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:create_order&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;cart: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-19 08:59:13", updated_at: "2020-01-19 08:59:13"&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Order:0x00007f91455ebd10&amp;gt;&lt;/span&gt;

&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:perform&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;cart: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-19 08:59:13", updated_at: "2020-01-19 08:59:13"&amp;gt;&lt;/span&gt;
  &lt;span class="no"&gt;Arg&lt;/span&gt; &lt;span class="ss"&gt;promotion: &lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-19 08:59:13", updated_at: "2020-01-19 08:59:13"&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Order:0x00007f91455ebd10&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you read the above example carefully, you’ll notice that there are other changes in the code and output, except for the return value:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;TracePoint&lt;/code&gt; now tracks &lt;code&gt;return&lt;/code&gt; event, instead of the &lt;code&gt;call&lt;/code&gt; event like other 2 examples.&lt;/li&gt;
&lt;li&gt;The output’s order is somewhat different from the previous ones.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is because we need to wait for a method call to finish (return) before we can retrieve its return value. So the output is ordered by the time the method is returned, instead of called. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform&lt;/span&gt;
  &lt;span class="c1"&gt;# …&lt;/span&gt;
  &lt;span class="n"&gt;create_order&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# call order: perform -&amp;gt; create_order&lt;/span&gt;
&lt;span class="c1"&gt;# return order: create_order -&amp;gt; perform&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we understand this small difference, this small change in the output won’t confuse us that much. In fact, I sometimes find it more useful in some instances. e.g., when I want to observe how different methods update and return the same value, ordering them with return value makes more sense.&lt;/p&gt;

&lt;p&gt;With Object-Oriented Tracing, now we can know the program’s call path, each call’s arguments, and even their return values in a glance. Other than being super-efficient, object-oriented tracing also avoids some problems I mentioned earlier:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the past, we need to understand what &lt;code&gt;OrderCreationService&lt;/code&gt; would call, in order to get inside those methods and collect the information we need. Now we only need to know where would &lt;code&gt;OrderCreationService#perform&lt;/code&gt; be called (which is super easy to find).&lt;/li&gt;
&lt;li&gt;Unless we need more detailed information or perform some tests on the logic of &lt;code&gt;OrderCreationService&lt;/code&gt;, we don’t need to touch any line of its code. So we can keep it clean even while debugging.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  TappingDevice
&lt;/h3&gt;

&lt;p&gt;Although &lt;code&gt;TracePoint&lt;/code&gt; is already capable of doing what we want, there still are things we can do to make it easier:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The boilerplate code is quite long (~10 lines). It’s not so easy to remember.&lt;/li&gt;
&lt;li&gt;If you’re not familiar with &lt;code&gt;TracePoint&lt;/code&gt;, it could take you some time to deal with some edge cases (trust me, I’ve been there before). This means the boilerplate code might end up getting longer to work around those cases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is why I created &lt;a href="https://github.com/st0012/tapping_device" rel="noopener noreferrer"&gt;tapping_device&lt;/a&gt; to make this easier for you! Do you still remember the code we wrote in the last example? Well, I don’t. And I don’t want to remember it! How about making that piece of code into just one method call? Instead of&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:cart_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;promotion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Promotion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:promotion_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OrderCreationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

    &lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:return&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"OrderCreationService"&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Called :&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callee_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; from &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lineno&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local_variables&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;local_variable_get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  Arg &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  =&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;return_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@cart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promotion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="c1"&gt;# …&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We only need to add 2 lines now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TappingDevice&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Trackable&lt;/span&gt; &lt;span class="c1"&gt;# include this&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:cart_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;promotion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Promotion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:promotion_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OrderCreationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

    &lt;span class="n"&gt;print_calls&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;— and you only need this now&lt;/span&gt;
    &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@cart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promotion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# …&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can get the same information!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="ss"&gt;:validate_cart&lt;/span&gt; &lt;span class="c1"&gt;# OrderCreationService&lt;/span&gt;
    &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:cart&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 10, customer_id: 1, promotion_id: nil, reserved_until: nil, created_at: "2020-01-20 07:09:22", updated_at: "2020-01-20 07:09:22"&amp;gt;}&lt;/span&gt;
    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;span class="ss"&gt;:apply_discount&lt;/span&gt; &lt;span class="c1"&gt;# OrderCreationService&lt;/span&gt;
    &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:cart&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-20 07:09:22", updated_at: "2020-01-20 07:09:22"&amp;gt;, :promotion=&amp;gt;#&amp;lt;Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-20 07:09:22", updated_at: "2020-01-20 07:09:22"&amp;gt;}&lt;/span&gt;
    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="ss"&gt;:create_order&lt;/span&gt; &lt;span class="c1"&gt;# OrderCreationService&lt;/span&gt;
    &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:cart&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-20 07:09:22", updated_at: "2020-01-20 07:09:22"&amp;gt;}&lt;/span&gt;
    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Order id: 1, number: nil, total: 5, customer_id: 1, promotion_id: 1, created_at: "2020-01-20 07:09:22", updated_at: "2020-01-20 07:09:22"&amp;gt;&lt;/span&gt;
&lt;span class="ss"&gt;:perform&lt;/span&gt; &lt;span class="c1"&gt;# OrderCreationService&lt;/span&gt;
    &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;controllers&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;orders_controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;:cart&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="c1"&gt;#&amp;lt;Cart id: 1, total: 5, customer_id: 1, promotion_id: 1, reserved_until: nil, created_at: "2020-01-20 07:09:22", updated_at: "2020-01-20 07:09:22"&amp;gt;, :promotion=&amp;gt;#&amp;lt;Promotion id: 1, amount: 0.5e1, customer_id: nil, created_at: "2020-01-20 07:09:22", updated_at: "2020-01-20 07:09:22"&amp;gt;}&lt;/span&gt;
    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;Order id: 1, number: nil, total: 5, customer_id: 1, promotion_id: 1, created_at: "2020-01-20 07:09:22", updated_at: "2020-01-20 07:09:22"&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition to &lt;code&gt;print_calls&lt;/code&gt;, &lt;a href="https://github.com/st0012/tapping_device" rel="noopener noreferrer"&gt;tapping_device&lt;/a&gt; also provides different level’s of APIs for different kind of information, like &lt;code&gt;print_traces&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Assume we don’t find anything wrong on the &lt;code&gt;OrderCreationService&lt;/code&gt;’s method calls. And we suspect it’s something wrong on the &lt;code&gt;@cart&lt;/code&gt; object. We can use &lt;code&gt;print_traces&lt;/code&gt;  to see how it interacts with other parts of the program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TappingDevice&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Trackable&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@cart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:cart_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;promotion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Promotion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;order_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:promotion_id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OrderCreationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

    &lt;span class="n"&gt;print_traces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@cart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;exclude_by_paths: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;/gems/&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="c1"&gt;# exclude gems so we don’t see ActiveRecord’s internal method calls&lt;/span&gt;
    &lt;span class="vi"&gt;@order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@cart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promotion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Passed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="s1"&gt;'cart'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s1"&gt;'OrderCreationService#perform'&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;controllers&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;orders_controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;
&lt;span class="no"&gt;Passed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="s1"&gt;'cart'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s1"&gt;'OrderCreationService#validate_cart'&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:reserved_until&lt;/span&gt; &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;
&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:errors&lt;/span&gt; &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;
&lt;span class="no"&gt;Passed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="s1"&gt;'cart'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s1"&gt;'OrderCreationService#apply_discount'&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:apply_discount&lt;/span&gt; &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;
&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:total&lt;/span&gt; &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:update!&lt;/span&gt; &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;span class="no"&gt;Passed&lt;/span&gt; &lt;span class="n"&gt;as&lt;/span&gt; &lt;span class="s1"&gt;'cart'&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s1"&gt;'OrderCreationService#create_order'&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;
&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:total&lt;/span&gt; &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;
&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:customer&lt;/span&gt; &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;
&lt;span class="no"&gt;Called&lt;/span&gt; &lt;span class="ss"&gt;:promotion&lt;/span&gt; &lt;span class="ss"&gt;from: &lt;/span&gt;&lt;span class="sr"&gt;/Users/s&lt;/span&gt;&lt;span class="n"&gt;t0012&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;projects&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tapping_device&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;demo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;order_creation_service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can not only see what’s been called on &lt;code&gt;@cart&lt;/code&gt;, but we can also see what methods took it as its arguments! This can save you some time when debugging. 😉&lt;/p&gt;

&lt;p&gt;If you want to know more about how to use &lt;a href="https://github.com/st0012/tapping_device" rel="noopener noreferrer"&gt;tapping_device&lt;/a&gt; to optimize your debugging workflow, you can read its  &lt;a href="https://github.com/st0012/tapping_device/blob/master/README.md" rel="noopener noreferrer"&gt;readme&lt;/a&gt; to explore different types of useful helpers! You can also see how I used it to address the cause of a Rails issue in &lt;a href="https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c"&gt;Debug Rails issues effectively with tapping_device&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Debugging is mostly about collecting information about how our program works (or used to work). And doing this manually is pretty overwhelming. So as humans, it’s tempting to cheat by guessing how it works in our head and ends up spending more time on the issue.&lt;/p&gt;

&lt;p&gt;But with the help of Object-Oriented Tracing, we can take advantage of the paradigm of OOP, and Ruby’s super powerful &lt;code&gt;TracePoint&lt;/code&gt; to enhance our efficiency on inspecting our programs. I believe this can reduce debugging’s painfulness for junior developers, while allows experienced developers to speed up their debugging process largely.&lt;/p&gt;

&lt;p&gt;If you have any opinions on this post or &lt;a href="https://github.com/st0012/tapping_device" rel="noopener noreferrer"&gt;tapping_device&lt;/a&gt;, please feel free to leave a comment below, I’d love to discuss them with you! Also, if you have a different or better strategy on debugging, please let me know as well ;-)&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>rails</category>
      <category>ruby</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Debug Rails issues effectively with tapping_device</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Sun, 22 Dec 2019 11:07:37 +0000</pubDate>
      <link>https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c</link>
      <guid>https://dev.to/st0012/debug-rails-issues-effectively-with-tappingdevice-c7c</guid>
      <description>&lt;h1&gt;
  
  
  Debug Rails issues effectively with tapping_device
&lt;/h1&gt;

&lt;p&gt;Hello everyone, 👋 I’m the author of the &lt;a href="https://github.com/st0012/tapping_device"&gt;&lt;code&gt;tapping_device&lt;/code&gt;&lt;/a&gt; gem, a debugging tool I created a while ago. I'm also a &lt;a href="https://contributors.rubyonrails.org/contributors/stan-lo/commits"&gt;Rails contributor&lt;/a&gt; that helps people solve their issues from time to time. Today I want to use a real-world example to demonstrate how did the  &lt;a href="https://github.com/st0012/tapping_device"&gt;&lt;code&gt;tapping_device&lt;/code&gt;&lt;/a&gt;  gem help me find the cause of a Rails issue in an hour ;-)&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Intro of tapping_device
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/st0012/tapping_device"&gt;&lt;code&gt;tapping_device&lt;/code&gt;&lt;/a&gt;  is built on top of Ruby’s &lt;code&gt;TracePoint.&lt;/code&gt; It has several helpers that provide a high-level point of view of how your program runs. For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;tap_on!(target)&lt;/code&gt; - you can use it to track all method calls performed on the target&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tap_sql!(target)&lt;/code&gt; - this is a Rails-specific helper. You can use it to track on method calls that generate SQL queries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tap_passed!(target)&lt;/code&gt; - you can use it to track what method takes target as its argument&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For more info, here’s a &lt;a href="https://dev.to/st0012/want-to-know-more-about-your-rails-app-tap-on-your-objects-bd3"&gt;post&lt;/a&gt; contains some useful examples that you can use in your Rails apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Issue (#38041)
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/rails/rails/issues/38041"&gt;issue&lt;/a&gt; is about a behavioral change on &lt;code&gt;DateTime&lt;/code&gt; calculation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Rails 5.2.4.1: OK&lt;/span&gt;
&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="mi"&gt;2019&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_datetime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;BigDecimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hour&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Thu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="no"&gt;Dec&lt;/span&gt; &lt;span class="mi"&gt;2019&lt;/span&gt; &lt;span class="mi"&gt;09&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mo"&gt;0000&lt;/span&gt;
&lt;span class="c1"&gt;# OK&lt;/span&gt;

&lt;span class="c1"&gt;# Rails 6.0.2.1: WRONG&lt;/span&gt;
&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="mi"&gt;2019&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_datetime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="no"&gt;BigDecimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hour&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;Thu&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt; &lt;span class="no"&gt;Dec&lt;/span&gt; &lt;span class="mi"&gt;2019&lt;/span&gt; &lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mo"&gt;0000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s clear that something has been changed between version &lt;code&gt;5.2.4&lt;/code&gt; and &lt;code&gt;6.0.2&lt;/code&gt;. But we don’t know where's the change nor when it’s been made.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I’d do, in the past
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Check if &lt;code&gt;“2019-12-19 10:00”.to_datetime&lt;/code&gt; returns the same result in both versions&lt;/li&gt;
&lt;li&gt;Check if &lt;code&gt;BigDecimal(1).hour&lt;/code&gt; returns the same result in both versions&lt;/li&gt;
&lt;li&gt;Digging into what happens when calling &lt;code&gt;DateTime#-&lt;/code&gt; in both versions&lt;/li&gt;
&lt;li&gt;(Jumping between files and adding breakpoints or &lt;code&gt;puts&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What I did instead, with tapping_device
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;I wrote a script that prints out how the objects are used by tracking their method calls. The first thing I’d check is that what’s returned in each method call so I can locate what’s been changed. And it’s also important to see where the calls were performed.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"active_support/all"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"tapping_device"&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Rails: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2019-12-19 10:00"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_datetime&lt;/span&gt;
&lt;span class="n"&gt;one_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BigDecimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hour&lt;/span&gt;

&lt;span class="n"&gt;device_for_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TappingDevice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;device_for_one_h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TappingDevice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

&lt;span class="n"&gt;device_for_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tap_on!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;device_for_one_h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tap_on!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;one_h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;one_h&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Calls on time&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;device_for_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name_and_location&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;" =&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;return_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"=============================="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Calls on one_h&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;device_for_one_h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name_and_location&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;" =&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;return_value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Then I ran the same script on both versions. Here are the outputs:&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Output - Rails 5.2
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rails: 5.2.4
Calls on time
Method: :acts_like?, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-5.2.4/lib/active_support/duration.rb:404 =&amp;gt; true
Method: :+, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-5.2.4/lib/active_support/core_ext/date_time/calculations.rb:113 =&amp;gt; 2019-12-19T09:00:00+00:00
Method: :since, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-5.2.4/lib/active_support/duration.rb:410 =&amp;gt; 2019-12-19T09:00:00+00:00
Method: :plus_with_duration, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-5.2.4/lib/active_support/core_ext/date/calculations.rb:102 =&amp;gt; 2019-12-19T09:00:00+00:00
Method: :-, line: time_test.rb:15 =&amp;gt; 2019-12-19T09:00:00+00:00
==============================
Calls on one_h
Method: :is_a?, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-5.2.4/lib/active_support/duration.rb:145 =&amp;gt; true
Method: :-@, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activesupport-5.2.4/lib/active_support/core_ext/date/calculations.rb:102 =&amp;gt; -3600.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Output - Rails 6
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Rails: 6.0.2
Calls on time
Method: :acts_like?, line: /Users/st0012/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.2/lib/active_support/duration.rb:405 =&amp;gt; true
Method: :+, line: /Users/st0012/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.2/lib/active_support/core_ext/date_time/calculations.rb:113 =&amp;gt; 2019-12-19T08:59:59+00:00
Method: :since, line: /Users/st0012/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.2/lib/active_support/duration.rb:411 =&amp;gt; 2019-12-19T08:59:59+00:00
Method: :plus_with_duration, line: /Users/st0012/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.2/lib/active_support/core_ext/date/calculations.rb:102 =&amp;gt; 2019-12-19T08:59:59+00:00
Method: :-, line: time_test.rb:15 =&amp;gt; 2019-12-19T08:59:59+00:00
==============================
Calls on one_h
Method: :is_a?, line: /Users/st0012/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.2/lib/active_support/duration.rb:144 =&amp;gt; true
Method: :-@, line: /Users/st0012/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activesupport-6.0.2/lib/active_support/core_ext/date/calculations.rb:102 =&amp;gt; -3600.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the &lt;code&gt;+&lt;/code&gt; method call’s results were different in the 2 versions. Version &lt;code&gt;5.2.4&lt;/code&gt; returned &lt;code&gt;2019-12-19T09:00:00+00:00&lt;/code&gt; while &lt;code&gt;6.0.2&lt;/code&gt; returned &lt;code&gt;2019-12-19T08:59:59+00:00&lt;/code&gt;. Let’s check what’s defined in &lt;code&gt;active_support/core_ext/date_time/calculations.rb:113&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="no"&gt;Rational&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing weird. Maybe it has been changed recently?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git blame lib/active_support/core_ext/date_time/calculations.rb | grep 113
c85e3f65f34 (Edouard CHIN        2018-10-09 13:36:56 -0400 113)     self + Rational(seconds, 86400)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;commit c85e3f65f3409fc329732912908c3601d8e5fac9
Author: Edouard CHIN &amp;lt;edouard.chin@shopify.com&amp;gt;
Date:   Tue Oct 9 13:36:56 2018 -0400

    Fix issue where duration where always rounded up to a second:

    - Adding a Float as a duration to a datetime would result in the Float
      being rounded. Doing something like would have no effect because the
      0.45 seconds would be rounded to 0 second.

      ```

ruby
        time = DateTime.parse("2018-1-1")
        time += 0.45.seconds


      ```

      This behavior was intentionally added a very long time ago, the
      reason was because Ruby 1.8 was using `Integer#gcd` in the
      constructor of Rational which didn't accept a float value.

      That's no longer the case and doing `Rational(0.45, 86400)` would
      now perfectly work fine.

    - Fixes #34008
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bingo! There was a &lt;code&gt;round&lt;/code&gt; call in &lt;code&gt;5.2&lt;/code&gt; but it has been removed &lt;code&gt;6.0&lt;/code&gt; via this &lt;a href="https://github.com/rails/rails/commit/c85e3f65f3409fc329732912908c3601d8e5fac9"&gt;commit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Isn’t this a super-easy way to debug an issue 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  What does this mean to me (and you)?
&lt;/h2&gt;

&lt;p&gt;As you can see from the above example, what  &lt;a href="https://github.com/st0012/tapping_device"&gt;&lt;code&gt;tapping_device&lt;/code&gt;&lt;/a&gt;  provides is a new way to spot behavioral changes in your program. &lt;/p&gt;

&lt;p&gt;Whether you’re a &lt;code&gt;pry&lt;/code&gt;/&lt;code&gt;bye bug&lt;/code&gt; debugger or a &lt;code&gt;put&lt;/code&gt; debugger, you always need to go through files so you can build a rough execution path of the program in your mind before actually adding breakpoints or &lt;code&gt;puts&lt;/code&gt;  to the right location. The downsides of this are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you’re not familiar with the codebase or it’s not written in an easily-understandable way, there could be a lot of trial-and-error before you actually found the right place to inspect your program.&lt;/li&gt;
&lt;li&gt;And it’ll be very easy to lose the big picture when you dive into individual method calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But if you use &lt;a href="https://github.com/st0012/tapping_device"&gt;&lt;code&gt;tapping_device&lt;/code&gt;&lt;/a&gt;, you can inspect the program &lt;strong&gt;from an object’s point of view&lt;/strong&gt;. This means you won’t need to know which way it’ll go to intercept it. You just need to know where it’ll start its journey! It can save you hours when debugging a large application/library. &lt;/p&gt;

&lt;p&gt;I hope you can give &lt;a href="https://github.com/st0012/tapping_device"&gt;&lt;code&gt;tapping_device&lt;/code&gt;&lt;/a&gt; a try after reading this post. And if you do try it, please don't be shy to give me any feedback! I’d love to fix any issue or add any feature that can help people debug more happily!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>[Ruby Trick] Retrieve an object's private method without calling its `method`</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Fri, 13 Dec 2019 16:34:55 +0000</pubDate>
      <link>https://dev.to/st0012/ruby-trick-retrieve-an-object-s-method-without-calling-its-method-12f</link>
      <guid>https://dev.to/st0012/ruby-trick-retrieve-an-object-s-method-without-calling-its-method-12f</guid>
      <description>&lt;p&gt;Goal: Get the &lt;code&gt;bar&lt;/code&gt; method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Foo&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bar&lt;/span&gt;
    &lt;span class="s2"&gt;"hey!"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Foo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;

&lt;span class="c1"&gt;# foo.method(:bar) will cause error cause it's been overridden&lt;/span&gt;
&lt;span class="c1"&gt;# foo.public_method(:bar) won't work cause :bar is private&lt;/span&gt;

&lt;span class="n"&gt;method_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:method&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;unbind&lt;/span&gt;
&lt;span class="n"&gt;bar_method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;method_method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;bar_method&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; "hey!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>ruby</category>
    </item>
    <item>
      <title>Want to know more about your Rails app? Tap on your objects!</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Mon, 09 Dec 2019 10:09:37 +0000</pubDate>
      <link>https://dev.to/st0012/want-to-know-more-about-your-rails-app-tap-on-your-objects-bd3</link>
      <guid>https://dev.to/st0012/want-to-know-more-about-your-rails-app-tap-on-your-objects-bd3</guid>
      <description>&lt;p&gt;Have you ever looked at a controller action like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And wonder who’ll eventually use the &lt;code&gt;@posts&lt;/code&gt; variable? Is there an easy way to do that without going through multiple files and write &lt;code&gt;puts&lt;/code&gt; everywhere?&lt;/p&gt;

&lt;p&gt;Well, with the help of the &lt;a href="https://github.com/st0012/tapping_device"&gt;&lt;code&gt;tapping_device&lt;/code&gt;&lt;/a&gt; gem, it’s not just possible, it’s also super easy (with only 3 lines of code!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Install &lt;code&gt;tapping_device&lt;/code&gt; and include &lt;code&gt;TappingDevice::Trackable&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;First, add &lt;a href="https://github.com/st0012/tapping_device"&gt;&lt;code&gt;tapping_device&lt;/code&gt;&lt;/a&gt; into your Gemfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"tapping_device"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;group: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:development&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And include &lt;code&gt;TappingDevice::Trackable&lt;/code&gt; in your controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TappingDevice&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Trackable&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The &lt;code&gt;tap_on!&lt;/code&gt; helper
&lt;/h2&gt;

&lt;p&gt;Now let’s get the most basic information: who’s calling methods on &lt;code&gt;@posts&lt;/code&gt;? To do this, you need to use the &lt;code&gt;tap_on!&lt;/code&gt; method and define a callback. The block will be executed every time a &lt;code&gt;@posts&lt;/code&gt; ’s method is being called.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
  &lt;span class="n"&gt;tap_on!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name_and_location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then send a request to &lt;code&gt;/posts&lt;/code&gt;, you’ll see &lt;strong&gt;everything&lt;/strong&gt; that’s been called on the &lt;code&gt;@posts&lt;/code&gt; object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Method: :eager_load_values, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/relation.rb:668
Method: :includes_values, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/relation.rb:669
Method: :eager_loading?, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/relation/calculations.rb:226
Method: :includes_values, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/relation/calculations.rb:226
Method: :has_include?, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/relation/calculations.rb:128
Method: :distinct_value, line: /Users/st0012/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-6.0.0/lib/active_record/relation/calculations.rb:234
......
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apparently, most of the methods are called by &lt;code&gt;ActiveRecord&lt;/code&gt; and it’s not helping us here. Let’s filter them out with the &lt;code&gt;exclude_by_paths&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
  &lt;span class="n"&gt;tap_on!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;exclude_by_paths: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;/activerecord/&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name_and_location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can see who’s using the &lt;code&gt;@posts&lt;/code&gt; object inside our application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Method: :count, line: /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:3
Method: :each, line: /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:16
Method: :where, line: /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:31
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;# index.html.erb

&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Posts (&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;)&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
......
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    ......
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
......
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Posts created by you: &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="vi"&gt;@current_user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isn’t this super easy?&lt;/p&gt;

&lt;p&gt;However, in most cases, we don’t really care about who calls methods on &lt;code&gt;@posts&lt;/code&gt;. What we care about is “who calls @posts and generates sql queries?”. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;tap_sql!&lt;/code&gt; to the rescue!
&lt;/h2&gt;

&lt;p&gt;To see what queries &lt;code&gt;@posts&lt;/code&gt; generates, we need to use the &lt;code&gt;tap_sql!&lt;/code&gt; method instead. It runs the callback every time a sql query is generated from the object. &lt;/p&gt;

&lt;p&gt;Let’s change our setup a little bit to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;tap_sql!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;exclude_by_paths: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;/activerecord/&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Method `&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;` generates sql: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sql&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  From &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filepath&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;line_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it prints out the method’s name, the sql it generated and the location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Method `count` generates sql: SELECT COUNT(*) FROM "posts"
  From /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:3
Method `each` generates sql: SELECT "posts".* FROM "posts"
  From /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:16
Method `count` generates sql: SELECT COUNT(*) FROM "posts" WHERE "posts"."user_id" = ?
  From /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:31
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you look at the output very carefully, you may notice something isn’t quite right: The last query &lt;code&gt;SELECT COUNT(*) FROM “posts” WHERE “posts”. “user_id” = ?&lt;/code&gt; wasn’t actually generated from &lt;code&gt;@posts&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Well, this is a hidden feature of the &lt;code&gt;tap_sql!&lt;/code&gt; method. It also tracks the scopes created from &lt;code&gt;@posts&lt;/code&gt;, so if you call scope chaining methods like &lt;code&gt;order&lt;/code&gt; or &lt;code&gt;where&lt;/code&gt; on &lt;code&gt;@posts&lt;/code&gt;, the queries generated from the new scopes will also be recorded!&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus: what’s passed into the method?
&lt;/h3&gt;

&lt;p&gt;Sometimes, only knowing which method is called isn’t enough. What’s passed into the method is also very important. For example, assume we want to know which user was passed into the &lt;code&gt;where&lt;/code&gt; call, we can do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
  &lt;span class="vi"&gt;@posts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;
  &lt;span class="n"&gt;tap_on!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;exclude_by_paths: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;/activerecord/&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="ss"&gt;:where&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method_name_and_location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  Arguments: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arguments&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Method: :where, line: /PROJECT_PATH/rails-6-sample/app/views/posts/index.html.erb:31
  Arguments: {:opts=&amp;gt;{:user=&amp;gt;#&amp;lt;User id: 20, name: "Stan", age: 25, created_at: "2019-12-09 09:06:29", updated_at: "2019-12-09 09:06:29"&amp;gt;}, :rest=&amp;gt;[]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we know it’s the “Stan” user, and we don’t even need to leave the controller!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/st0012/tapping_device"&gt;tapping_device&lt;/a&gt; is a new project, but I already use it very often on my day job. So I believe it’ll be helpful for others too! If you want to know more about it, please visit the &lt;a href="https://github.com/st0012/tapping_device"&gt;repo&lt;/a&gt; and read the readme for more features. And if you have any feature requests, please feel free to open an issue, and we can discuss it! Any other feedback is welcomed as well 😄&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>contributorswanted</category>
    </item>
    <item>
      <title>tapping_device - a gem for tacking method calls</title>
      <dc:creator>Stan Lo</dc:creator>
      <pubDate>Sun, 20 Oct 2019 15:57:21 +0000</pubDate>
      <link>https://dev.to/st0012/tappingdevice-a-gem-for-tacking-method-calls-3jbg</link>
      <guid>https://dev.to/st0012/tappingdevice-a-gem-for-tacking-method-calls-3jbg</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/st0012/tapping_device"&gt;tapping_device&lt;/a&gt; is a gem built on top of Ruby’s &lt;code&gt;TracePoint&lt;/code&gt; class that allows you to tap method calls of specified objects. The purpose of this gem is to make debugging Rails applications easier. &lt;/p&gt;

&lt;p&gt;For example, you can use it to see who calls methods on your &lt;code&gt;Post&lt;/code&gt; records&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PostsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;TappingDevice&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Trackable&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
    &lt;span class="vi"&gt;@post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;tap_on!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@post&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Method: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:method_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; line: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:filepath&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:line_number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you can see these in log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Method: name line: /PROJECT_PATH/sample/app/views/posts/show.html.erb:5
Method: user_id line: /PROJECT_PATH/sample/app/views/posts/show.html.erb:10
Method: to_param line: /RUBY_PATH/gems/2.6.0/gems/actionpack-5.2.0/lib/action_dispatch/routing/route_set.rb:236
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or you can track all association calls with &lt;code&gt;tap_assoc!&lt;/code&gt;. This is very useful for tracking potential n+1 query calls, here’s a sample from my work project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;tap_assoc!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Assoc: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:method_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; line: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:filepath&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:line_number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Assoc: payments line: /RUBY_PATH/gems/2.6.0/gems/jsonapi-resources-0.9.10/lib/jsonapi/resource.rb:124
Assoc: line_items line: /MY_PROJECT/app/models/line_item_container_helpers.rb:44
Assoc: effective_line_items line: /MY_PROJECT/app/models/line_item_container_helpers.rb:110
Assoc: amending_orders line: /MY_PROJECT/app/models/order.rb:385
Assoc: amends_order line: /MY_PROJECT/app/models/order.rb:432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Although I've been using similar ways on my work for a while, my use cases might be quite limited. So I'd love to hear any feedback or suggestions on this tool 😄&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>showdev</category>
      <category>contributorswanted</category>
    </item>
  </channel>
</rss>
