Rails Masters' debugging techniques -> Rails Recipes?


#1

Hi,

This msg for Chad F. or anyone who fits the subject line.

I bought the Recipes book and really like the way it has been
progressing. There is one subject I’d like to see explored in detail.
Having come from Assembly and C background I find that a ‘must have’
tool in your collection is the debugger.

I find debugging a Rails App the most thorny issue inversely
proportional to its simplicity and beauty. I have tried breakpointer,
mr.guid, arachnoruby etc but they are either inadequate or slow or
both. What do you do when you set a breakpoint in your code and it
doesn’t hit and there are no messages in the log or in the browser.
What is going on in the framework? How can I learn the framework by
actually tracing through the code vs. simply reading it? These are
some of the issues I grapple with in daily development of Rails. Don’t
get me wrong, while for the most part Rails gives very meaningful
messages which makes development go smoothly, the rare occasions when
I hit one of the ‘bugs of the strange kind’ it can take me days to
figure it out!

I’d like to know what the methods/techniques core developers and other
ruby/rails gurus use and how they are able to be so productive…not
withstanding the fact that they by definition write better code than I
:slight_smile: It is incomprehensible to my average brain when I hear that DHH
wrote basecamp + rails in 6 weeks or so (rails first rails video) -or-
that Gosling cobbled up Java over a weekend -or- that Jim Fulton
wrote zope on a plane ride home
-http://www.plope.com/Books/2_7Edition/IntroducingZope.stx and other
such stories.

There seems to be precious little written on the subject in the wiki.

Thanks for the opportunity to vent,

-bakki


#2

Bakki K. wrote:

proportional to its simplicity and beauty. I have tried breakpointer,

+1


Jack C.
removed_email_address@domain.invalid


#3

Hi Jack,

If I might jump in and offer up what’s worked tremendously for me maybe
it
can help you. Test driven development in Rails using small discrete
steps
of both tests and code can ensure that you’ll never spend days debugging
something. It’s not fool proof but it’s pretty damn good.

I’ve developed some pretty complex features and interactions in Rails
and
I’ve never used the rails debugger or set a breakpoint, I don’t even
know
how to use them. I know it’s there but I’ve never used it nor felt the
need
to use it, I’m sure that someone will chime in that you should use all
the
tools that are available at your disposal, but I’ve never felt any pain
from
debugging Rails.

The reason for this is that I’m writing tests as I write code, and that
I
can test my way through all sorts of seemingly complex and impossible
problems. Rails offers up a testing environment that is just like
nothing
I’ve ever seen before, and for those coming from different environments
I
offer up the notion that Test Driven Development with Rails is so well
put
together that you can develop without a debugger, setting a breakpoint,
or
even opening the browser!

The reason for this is that the testing tools that Rails offers are so
handy
that you can get to virtually anything in the system that you want to
inspect or test. It’s not always easy and sometimes I wish I could just
skip testing but I never do because the tests give me confidence that
I’m
writing code that does what I espect.

Admittedly, I don’t think there has been anything written yet that quite
captures the power of Rails testing. AWDWROR, describes the basic Rails
testing features. Chad F.'s describes the new integration tests.
The
Rails wiki contains another document worth checking out: A guide to
testing
the rails. http://manuals.rubyonrails.com/read/book/5

While these books are excellant for presenting the nuts and bolts of how
you
can test in rails, they don’t really go into testing strategies or how
to
write code with tests. You don’t have to test everything. I think the
Prag
programmer’s books on unit testing C#/Java have some great things in
their
about the “Art of building code with tests”.

Developing with tests is different than developing with a debugger, I
think
Rails makes a good argument into looking at the former. That being
said, I
recognize that being so gung ho about tests makes me a little crazy and
I’ll
be learning the debugger and breakpoint stuff just to be open minded
about
them. (I think)

My two cents,

Tim C.
removed_email_address@domain.invalid


#4

Bakki,

My suggestion is: learn ruby! It seems to me lots of people don’t
bother getting deep into Ruby because Rails takes care of almost
everything. Ruby (I think someone else said that already) is nuclear
stuff
and can perform little miracles. Whenever I hit a bug I don’t
understand, I go to the Rails source code (it’s on your computer
anyway) and try to figure out what it does. I’m also constantly
building my own tools to help me with my work.

Here’s something you might find useful, a universal method tracer.

class Trace
@@traces = {}

def self.cm_key(c, m); “#{c}.#{m}”; end

def self.traced?(c, m)
@@traces.include?(cm_key(c, m))
end

def self.def_trace(c, m)
Proc.new {|*args| puts(args ?
“#{c}.#{m}(#{args.map{|i|i.inspect}.join(’, ')})” : “{c}.#{m}”)}
end

def self.start(c, m, &block)
stop if traced?(c, m)

 @@traces[cm_key(c, m)] = om = "o_#{m}".to_sym
 tm = "t_#{m}".to_sym

 def_block = def_trace(c, m)
 c.class_eval {
   alias_method om, m
   define_method tm, (block || def_block)
 }
 c.class_eval "def #{m}(*args); #{tm}(*args); send(:#{om},

*args); end"
end

def self.stop(c, m)
om = “o_#{m}”.to_sym
tm = “t_#{m}”.to_sym
c.class_eval {
remove_method tm
alias_method m, om
}
@@traces.delete(cm_key(c, m))
end
end

I wrote it for my own purposes, so I can’t guarantee it works in all
situations, but you can probably use it for tracing method calls.

Usage:

Trace.start(MyClass, :method_name)

It will change your class so that everytime the specified method is
called, the call is printed along with any method parameters (you can
override the def_trace method if you wish.)

You can also pass it a block:

Trace.start(MyController, :login) {puts “login invoked”}

Hope this helps,
Sharon.


#5

Well, I hate to chime in with my suggestion, because its the lowest-brow
debugging suggestion of all time!

puts.

I have used many other forms of debugging in my time developing rails,
but I
find that 99% of the time writing my own ‘puts’ statements for all sorts
of
various tracing solves 99% of my problems.

Its not sophisticated, but it often works out. I just keep the
./script/server window open on my second monitor and I see what’s going
on
in the code.

-hampton.


#6

Sharon,

Thanks for you response. I have been learning Ruby but I still have a
ways to go. What you posted is exactly the sort of thing I was asking
about. Experts have their own tricks and tools which they use to poke
around. I thought this would make a great chapter in Rails Recipes
book…or a Wiki entry. I know there is a paradigm shift here for
traditional C programmers who depend on debuggers to inspect data,
call stacks, and step through code to find bugs. It appears that in
Ruby your write test cases as suggested by Tim C. or classes as you
have. I still have to get my mind around some of these concepts.

I too try and read the source when I hit a thorny bug. However my
preference would be to try and trace through it using a debugger as I
would in C, Java …or even in PHP(Zend Studio debugger). This way you
get a more dynamic view of the app/framework. Catching it in action as
it were. Up till now the debugger has always been the MOST IMPORTANT
tool in my toolbox. With a good debugger I can always catch a bug in a
relatively short time.

I am curious as to what other tricks people with deep experience in
Ruby use routinely to extract info from the app/framework. I will
certainly try your method tracer, thank you very much for that. After
I have used it a bit and gain some experience, would you mind if I
post it on the Wiki under debugging methods?

-bakki


#7

On Apr 15, 2006, at 10:19 AM, M. Edward (Ed) Borasky wrote:

Bakki K. wrote:

It is incomprehensible to my average brain when I hear that DHH
wrote basecamp + rails in 6 weeks or so (rails first rails video) -
or-
that Gosling cobbled up Java over a weekend -or- that Jim Fulton
wrote zope on a plane ride home

I couldn’t live without vim but I turn the syntax coloring off.

Interesting! I’m a bare bones guy myself, but I use syntax coloring!

I absolutely have to have version control even for something I’m
doing all by myself.

Best advice ever! People not using version control are missing the
best productivity increase I’ve ever run into!

Six weeks to build Basecamp and Rails sounds about right to me.
I’ve done projects of
equivalent size in less time in languages a lot less user-friendly
than Ruby. The key
to rapid development is to know the application domain and the
development environment
at the unconscious competence level, and to have small teams!

Agreed. There’s something magic about knowing what you want in
advance cold and being
honestly very excited about having a solution (as opposed to simply
being finished).


– Tom M.


#8

On 4/6/06, Bakki K. removed_email_address@domain.invalid wrote:

proportional to its simplicity and beauty. I have tried breakpointer,

There seems to be precious little written on the subject in the wiki.

Thanks for the opportunity to vent,

-bakki

Personally, I’ve never used the breakpointer or Ruby debugger on a Rails
app.
Occasionally I’ve used the Ruby debugger to help understand how a
piece of library code operated.

I’d like to reiterate the earlier advice about test-driven
development. If you test drive your code, you’ll forget debuggers
even exist. This isn’t limited to Ruby; you can (and should) do it in
C as well. It’s just that Ruby has some nice testing support.
Definitely look into RSpec, as well as the more common Test::Unit
library.
http://rspec.rubyforge.org/examples.html

If you feel like spending some money on books, here are some excellent
ones:
“Test-Driven Development by Example” by Kent Beck
“Test-Driven Development: A Practical Guide” by Dave A.
“Refactoring” by Martin F.
“Smalltalk Best Practice Patterns” by Kent Beck (amazing book)
“Practices of an Agile Developer” by Venkat S. and Andy H.


#9

Bakki K. wrote:

proportional to its simplicity and beauty. I have tried breakpointer,

There seems to be precious little written on the subject in the wiki.

Thanks for the opportunity to vent,

-bakki

Well … I’ve been programming since before there were text editors. My
experience has been that debuggers, IDEs, syntax coloring, etc., don’t
help me much in my own development projects, but they’re absolutely
necessary when you get a few thousand lines of someone else’s code
handed to you with a tight deadline! :slight_smile:

Basically, programmers tend to use the tools that work for them. I
couldn’t live without vim but I turn the syntax coloring off. I
absolutely have to have version control even for something I’m doing all
by myself. I over-comment and I’m proud of it. If some day someone comes
up with a programming language that can translate my comments from
English to code, I’ll ride off into the sunset with a big smile on my
face. :slight_smile:

Six weeks to build Basecamp and Rails sounds about right to me. I’ve
done projects of equivalent size in less time in languages a lot less
user-friendly than Ruby. The key to rapid development is to know the
application domain and the development environment at the unconscious
competence level, and to have small teams!


M. Edward (Ed) Borasky

http://linuxcapacityplanning.com


#10

“Personally, I’ve never used the breakpointer or Ruby debugger on a
Rails app.”

+1 Me either.

Yup, test-driven Rails has to be the single most overlooked feature of
Rails and is probably one of the biggest features that distinguishes
Rails from other environments. Test Driven Development has never been
easier or more powerful. Goodbye debugger.


#11

Am 15.04.2006 um 20:28 schrieb Tim C.:

Goodbye debugger.

How so? Why switch to “tracing” (i.e. a lot of “puts foo.inspect” for
finding an error if you can simply jump in on every thrown exception?

:slight_smile:

Really, Test Driven Development is orthogonal to using a debugger and
rather complements than replaces it.

*m


#12

Manuel H. wrote:

Am 15.04.2006 um 20:28 schrieb Tim C.:

Goodbye debugger.

How so? Why switch to “tracing” (i.e. a lot of “puts foo.inspect” for
finding an error if you can simply jump in on every thrown exception?

:slight_smile:

Really, Test Driven Development is orthogonal to using a debugger and
rather complements than replaces it.

*m

I just finished a week of debugging Rails framework / Ruby upgrade /
plugin interaction issues. In virtually every case, TDD (which we do)
was of absolutely no use. I used every trick in the book: console, puts,
logging, commenting out code, adding bogus code, you name it, in order
to resolve the issues. A fully fledged debugger would have really sped
things up for me.

While in general with Rails I find that the type of step-through
debugging I used to do in other languages is not generally needed, there
are times when you really do need to be able to just step through code.
TDD is great, and perhaps even necesssary, but not sufficient in all
cases.

Keith


#13

On 4/15/06, Manuel H. removed_email_address@domain.invalid wrote:

Really, Test Driven Development is orthogonal to using a debugger and
rather complements than replaces it.

*m

I disagree. If you need a debugger in order to find a bug in your
code, it means you don’t have enough test cases. I think that one of
the reasons why Linus refused to include a built-in debugger into
Linux kernel.


Kent

http://www.datanoise.com


#14

On Sat, Apr 15, 2006 at 01:25:43PM -0700, Tim C. wrote:

I’m not against the debugger, it’s just I feel I’ve found something better.
The two aren’t mutually exclusive. There is a minimum level of
granularity
you can achieve with even the most detailed of unit tests. What Unit
Testing can give you is a big, neon pointer to the small chunk of code
that
is the cause of your problem. You should be able to desk check the
failing
unit to find the cause, but sometimes you just can’t see the problem,
and so
you whip out the debugger and hunt the problem down in situ.

So the process is:

  • Receive bug report
  • Write test case that demonstrates the problem
  • Isolate the problem by writing finer and finer test cases until you
    can
    divide and conquer no more
  • Desk/head check the failing code
  • Can’t easily identify the problem
  • Fire up the debugger and hunt down the problem live
  • Dance!
  • Matt

#15

On Saturday 15 April 2006 04:25 pm, Tim C. wrote:

With TDD there is no tracing only assertions. Why find errors when
you can assert that your code does what you expect it to?

Tests are great. And I’m very test-infected, but I still find a
debugger
useful from time to time. Particularly when trying to isolate bugs in
code
that’s not mine and not very easy to write narrow, focused tests for
(like
AR, for example).


#16

With TDD there is no tracing only assertions. Why find errors when
you can assert that your code does what you expect it to?

First:

def test_sum_a_and_b
assert_equal 3, object.sum_two_numbers(1, 2)
end

Second:
def sum_two_numbers(a, b)
a.abs + b.abs
end

Test Passes, great but:

Later on we get a report of a bug:
“Something is wrong, when I try to sum negative numbers like -3 and -5
I get 8 instead of -8, I’m not getting the right answer”

Okay, now you could use a debugger insert a breakpoint and inspect the
variables
and see that -3 + -5 == 8
so you do this:
(a.abs*-1) + (b.abs*-1)

which is a valid solution to -3 + -5 == -8 but as we see you’ve
broken the original assertion. With tests you get a snapshot in time
of what you’re code is supposed to do, that you can turn around and
reuse for the future.

Instead of the debugger, do this:

def test_sum_two_numbers
assert_equal 3, object.sum_two_numbers(1, 2)
assert_equal -8, object.sub_two_numbers(-3, -5)
end

Now you are forced to write code that matches both conditions and you
get a very handy comment about what the code should do without having
to write a comment that may become outdated.

This is an EXTREMELY contrived and stupid example, but the point is
that I’ve found my entire way of development is much better with TDD
than it was with the debugger. This doesn’t even capture all of the
benefits having tests provides there are much more. While the the
user of a debugger and writing tests may very well be orthagonal I
prefer not to use the debugger because I feel that it would lead me to
skipping the tests, and personally my whole outlook on development has
changed dramatically in the positive because of TDD and I wouldn’t
want to go back to what I had before with debugs and breakpoints.

I’m not against the debugger, it’s just I feel I’ve found something
better.


#17

Mathew,

My feelings exactly. Test driven development is great but on those
occsasions when failure doesn’t leave any clues, it is nice to be able
to trace through the code.

The second case for the debugger arises when you want to trace through
the framework , (Ed Borasky - but they’re absolutely necessary when
you get a few thousand lines of someone else’s code handed to you with
a tight deadline! :slight_smile: which IS someone else’s code.

I have been playing with mr_guid which is pretty close to what I’d
like to see in a debugger except for stablility/speed issues. It is
still usable though at v0.3. Just type in mr-buid script/server and
away it goes, you can single step through the framework code or set
breakpoints in your code. You can inspect all the variables, request
objects etc. I only wish it was an order of magnitude faster…but I
think it may be a problem with the Ruby debugger itself which mr_guid
wraps.

-bakki