This is a point of contention in the Julia ecosystem. Many users think the lack of a "good" debugger is the main drawback that prevents them from using Julia.
One common answer is: Yeah, debugging is kind of lousy at this point. Just write your code so you don't need a debugger much. This is pretty much what I do and I find that I don't miss the debugger much at all. Roughly, I work as follows.
- Where possible, I break code into lots of small functions. This is probably anyway a good idea (see Martin's famous "Clean Code" book). Then I write tests for the small functions.
- When I develop custom types, I write test setup functions that make instances of the types that can be used for testing.
- The test functions are placed into self-contained files that can be
included from the REPL. When something goes wrong, it is easy to inspect it there. See testing.
- When something goes wrong in the integrated code that was not found during tests, I start to sprinkle
@asserts into the code. If the code is not performance sensitive (95% of what I write), the
@asserts are never removed, even when the bug is fixed. This gets me closer to the source of the error.
In the vast majority of the cases, this process identifies errors without ever using a debugger. If this fails,
Exfiltrator.jl are helpful. They are a bit like
keyboard statements, but less powerful. The code essentially stops at a breakpoint. The user can inspect the state of the system, but cannot move around the call stack. But that's usually OK because the steps taken before invoking the debugger have gotten me close to the origin of the problem.