💾 Archived View for dioskouroi.xyz › thread › 29441653 captured on 2021-12-04 at 18:04:22. Gemini links have been rewritten to link to archived content

View Raw

More Information

➡️ Next capture (2021-12-05)

-=-=-=-=-=-=-

Three Ways to Debug Code in Elixir

Author: clessg

Score: 104

Comments: 18

Date: 2021-12-04 16:01:09

Web Link

________________________________________________________________________________

marcus_cemes wrote at 2021-12-04 17:43:15:

After seeing Elixir pop up so many times on Hacker News these last few months, I deicded to give it a go for the Advent of Code.

It's been pretty amazing actually, it takes a little getting used to, but it really feels like a language that was designed in every way possible to be ergonomic and productive. I'm still not sure whether it's easier to read purely functional code over a few mutable variables and simple loops, especially with a lot of filter, reduce, scan, zip, etc.

It's been pretty amazing so far, I haven't gotten further than IO.inspect()ing yet. The language server is still leagues even behind something like Rust analyzer (even renaming symbols is still a work in progress), but it's amazing that such a language already has one of the leading web frameworks (Phoenix), and despite being very network orientated, it's also excellent at solving AoC problems that involve a lot of clever manipulation of strings, binary, integers, and the sorts!

peoplefromibiza wrote at 2021-12-04 18:47:03:

My 2 cents

I've been an Elixir developer for years now, loved it immediately and still loving it after all this time.

About refactoring: I've been working as a Java developer for the past couple of years and I must admit thaat Intellij does a pretty impressive job at helping you refactoring code and their code sense is top notch.

But, there's a but.

I've never found myself having to make nuclear refactorings in Elixir, not because I don't refactor my code, but because modules are self contained and not tied with anything else, most of the times it is faster to abstract something over what you already have than to refactor all the things.

For example, if you decide that you need a struct instead of the old map, you advd a new function that pattern matches on the struct and pass it down.

If the struct has a different structure, you process it and pass it down.

The "treat data as something that is constantly transformed" mentality can take you a long way.

When I can code in java in a way similar to what I do in Elixir, things get easier in Java as well.

I miss symbol renaming in Elixir too, but it's never been a big stopper in the 6 years I've used it as a primary language.

edit: biggest strength of Elixir is Jose Valim himself.

If you watch his videos you can see him finding a bug while doing something, actually explaining why that's a bug in Elixir (or some library) open an issue and ask for PRs

All while showing you complex software patterns that I though I could never face before using Elixir.

marcus_cemes wrote at 2021-12-04 20:08:56:

I understand, but a lot of my refactoring is within functions to simplify and improve legibility once they work, renaming variables with generic names from "result" or "data".

It's a lot faster to do a cheeky F2, knowing that it's not a blind find/replace but a static code analysis with the ability to understand variable shadowing. Definitely not a show stopper though, and it feels more old-school, where every letter you type is more meaningful, if that makes sense.

And a huge +1 for José Valim and the whole community behind him!

michaelterryio wrote at 2021-12-04 19:09:37:

Ah, yes, this is how I refactor in Elixir too. I feel icky about it from a DRY standpoint but I’m training myself to ignore the scolds that held me back from being productive for so long.

clessg wrote at 2021-12-04 18:44:24:

> I deicded to give it a go for the Advent of Code.

That reminds me: in case anyone is curious how that looks in practice, it just so happens the creator of Elixir (José Valim) has been streaming Advent of Code exercises using Elixir (and Livebook):

https://www.twitch.tv/josevalim

dnautics wrote at 2021-12-04 22:08:50:

> It's been pretty amazing so far

Wait till you learn about async tests that are pinned to single database checkouts. And -- how async is composable with respect to resource pinning. AFAICT no other language does this (not even erlang).

brightball wrote at 2021-12-04 17:50:36:

Yea, my experience has been that after getting deep with Elixir and understanding how and why it (and the BEAM) works the way it does, everything else feels very limiting. Like I know all of the problems I’m willingly setting myself up for long term.

dnautics wrote at 2021-12-04 21:58:15:

for anyone using Elixir + vscode, this snippet is invaluable:

{
     "Inspect": {
      "prefix": "ins",
      "body": "|> IO.inspect(label: \"$0$TM_LINE_NUMBER\")",
      "description": "Adds a pipeline with a labelled `IO.inspect`",
     }
    }

when you type ins<tab> it injects a labelled IO.inspect that makes it easy to track where the data came from; usually in a debugging session the line numbers will be sufficient to track, and more importantly, it's almost always easy to ninja out these IO.inspects in one shot, because they are almost always the same number of characters long (since contiguous line numbers are usually in the same decade). Credit goes to one of my former junior devs who built this.

video demo:

https://www.youtube.com/watch?v=JXQZhyPK3Zw&t=1410s

(note slickbits doesn't seem to exist anymore)

mmartinson wrote at 2021-12-04 17:49:10:

Recon trace is a worthwhile addition. I've used it for some hairy production bugs that don't reproduce locally. Allows you to unobtrusively instrument a running system and echo back function calls with their params, including process targeting if needed.

There are a number of powerful tools for BEAM runtime tracing. I prefer this one because the API is simple enough to commit to memory, and it protects against some common foot guns.

https://ferd.github.io/recon/recon_trace.html

michaelterryio wrote at 2021-12-04 19:12:58:

Yep, and here’s a nice intro video from this year’s ElixirConf:

https://m.youtube.com/watch?v=F7YtYTMud-Y

jetpackjoe wrote at 2021-12-04 19:51:44:

I recently wrote a port of the python IceCream project[

https://github.com/gruns/icecream

].

Feel free to check it out for easier IO.inspect ergonomics:

https://github.com/joseph-lozano/ice_cream

ketzo wrote at 2021-12-04 19:04:20:

It can’t be emphasized enough how good IEx is.

Maybe it’s because it is my first experience with a language like Elixir, but man, it just feels like I’m _living inside_ the program while it’s running in a way that an IDE debugger doesn’t. It’s so cool and so powerful.

derefr wrote at 2021-12-04 22:10:36:

Give a remsh connection to a production cluster, you’ll find IEx really does mean “living inside” the process—you can reach out and add a live trace hook to e.g. a Phoenix Controller function, and then immediately see traces from _your live prod users_ hitting that trace point. Without recompiling or restarting the app—their _existing_ in-memory session state, local in-memory caches, etc. are suddenly exposed to you, without needing to discard any of it via a redeploy/restart and then wait for new user sessions to reproduce the problem.

(You can even redefine the module in-place in memory to see how changes affect what you see. Brings a whole new meaning to “hotfix”: you can do hotfixes that don’t even exist on disk!)

marcus_cemes wrote at 2021-12-04 20:12:51:

I will never forget the first time I started IEx from within a Phoenix project, and found that I had a live shell into the running application, while the Phoenix development server was running and reachable from the browser, all with hot code reloading... No need to create a dummy REST endpoint to try running a function.

My mind was blown.

zorbash wrote at 2021-12-04 20:59:42:

Another thing worth trying, is connecting a Livebook instance (see:

https://livebook.dev/

) to a running application.

Keep in mind Livebook allows for multiple users to work on the same notebook at once so this can come handy in pair-programming / debugging situations.

dnautics wrote at 2021-12-04 21:47:03:

It's like you are in bash, except you can run real functions, and your variables aren't stringly typed.

arthurcolle wrote at 2021-12-04 20:35:18:

:observer.start is awesome too

enraged_camel wrote at 2021-12-04 19:23:37:

I don't think I've ever used `IO.puts` for anything. As the article notes, `IO.inspect` is far superior.

Also, the Erlang observer is super neat. One really cool thing you can do with it is attach it to a _remote_ machine, which comes in real handy.