I highly suggest reading "Erlang in Anger" by ferd/MononQC. It (and his recon library) are indispensable tools for people running Erlang or Elixir in prod.
Am I missing out? AFAIK step-back debuggers are still more research (I think Elm has something like this), but otherwise I just want to have system snapshots and there print($foobar) works very well for me across languages.
This is really, really easy to do well when every function is pure and every data structure is immutable, and you use an MVC/Event-sourced/FRP architecture for (more-or-less) all control flow. Of course, Elm enforces all of these things.
I've written / worked on other systems (e.g. accounting / transaction pipelines) in other, less safe languages and implementing a shoddy version of this is really straightforward and immensely useful.
That said, with pure functions and immutable data structures, you don't really need a debugger for the same reasons, or indeed nearly as often, as in less safe languages.
[0]: http://debug.elm-lang.org/ [1]: http://elm-lang.org/blog/the-perfect-bug-report
Print statement style debugging can (with effort) get a lot of stuff figured out.
But :), it's often fairly slow to go through that iteration cycle with non-trivial bugs, compared to using a debugger.
With a debugger, you start from the same place in your code you'd put your print statements. But instead of modifying the code to spit out values, the debugger will pass control of the running program to you. You can then go forwards through your program, seeing how the variable values change, which branches are taken, etc.
It'll get you to the same end result as the print statements, but faster.
Also, for complicated/hairy/weird bugs, being able to follow the actual execution can be enlightening which print statements don't really do.
Some time ago I did more Java and used Eclipse heavily and its debugger was really nice, so I share your opinion that you get nice features.
However if you are working on a project (at least that has been my experience so far) that does a lot of multiprocessing (let's say a web service with a processing scheduler in the background calling into processes implemented by different languages) and you may have bugs on several layers using different programming languages, I like the fact that I can use the same concept for all of them and write some custom "debug.log" that I can later analyze (obviously good logging in the first place can help a lot).
But I may check them again: Do modern debuggers work across languages (assuming available source), let's say web-request -> Python -> FFI -> C++?
Previously such scenarios have been non-trivial to debug (although there are some pretty advanced multithreaded code analyzers now), but maybe it has changed for the better.
Gah... no idea. I'm still doing mostly doing single language stuff. :D
The kind of request path you're mentioning there... yeah, I'd probably go back to using print statements too, as I'd have no idea how to hand off from one language to another in some kind of meta-language-debugger. Which would actually be nifty if it exists.
Erlang/Elixir work with immutable values, so when you call a function, assuming it's side-effect free, you always get the same result.
Add to that the fact that there are no global variables (outside of table-like things like ETS), and that you can jump on the running system in an Erlang/Elixir shell and call any exported function and immediately see the results, debugging becomes much, much easier. I can honestly say that I have not needed a stepping-style symbolic debugger since 2008.
And when you find and fix a bug, you can copy the fixed code file (.beam file) to the server, start a remote shell, and do this:
> l(my_module).
and the new code is running, with no perceptible perturbation to the system.There are also other tools like dbg that let you monitor calls to specific module/functions based on pattern matches. The representation of these pattern matches is powerful but not so pretty - but it gets the job done.
Nothing's a panacea, and Erlang/Elixir undoubtedly have their warts, but for the Erlang VM's use case - soft real-time, extremely robust, highly concurrent distributed systems - I believe they are peerless.
One of the warts may be that the ecosystem doesn't have a library for every possible scenario, but that's improving rapidly, and in many cases, some of these are trivial to write. On the plus side, the quality of code is generally pretty good.
It is very challenging to describe what a massive level of confidence a hybrid-functional, battle-tested language and environment like this affords a system designer.
So debugging in this environment is very different and hard to compare directly to a line-by-line stepping debugger. Even if such a tool may be available (and things change so quickly these days, I probably missed that), it's easier to do without it.
It's so difficult to convey the experience of using this ecosystem, one cannot do it justice in a HN comment. T be fair, there are so many mature tools in more heavily used ecosystems like (I suppose) Java, that some may give up on Erlang/Elixir prematurely if used to that level of tooling.
Anyhow there are different reason to learn a new languange if ir change the way you think.
For me those languanges were
1. C learn to code
2. Python learn that there are more way to write code than C
3. Clojure keep everything as simple as possible
4. Elixir stuff fail, find a way to deal with it
5. Rust get as much help as possible as soon as possible from the tools that you use (namely the compiler.)
Now in whatever languange I write I bring with me those experiences. So I search to solve the problem in the simplest possible way keeping an eye on the reliability and I let my tools do as much as possible of all the heavy lifting...
All this just to say to give elixir a run that will make you a better r developer :)
Now my code in any languange
http://blog.plataformatec.com.br/2016/04/debugging-technique...
It supports stepping, etc.