Json Media
Back to posts

Elixir v1.14 is released - dbg

디버깅을 하는 가장 우아한 방법


Elixir v1.14 is released - dbg

Elixir v1.14

이 문서는 Livebook 으로 작성되었습니다.

Run in Livebook

Elixir v1.14 가 출시되었다! 1

한동안 그래왔듯 이번 버전에서는 DX(Developer eXperience), 특히 디버깅과 관련된 발전에 집중했다고 한다.

“한동안 DX 에 집중해왔다니? 언어 발전은 없고 이거 망해가는 것 아닌가요?” 라고 생각할 수도 있겠지만, Elixir 는 v1.9 에서 이미 마지막으로 예정되어있던 기능인 Releases 를 완성했다.

“Releases was the last planned feature for Elixir. We don’t have any major user-facing feature in the works nor planned.”

- José Valim 2

그래서 이후로 6개월 마다 주기적으로 자잘한 개선과 버그 수정이 주가되어 새로운 버전이 출시되고 있다.

이번 글에서는 Elixir v1.14 의 가장 중요한 개선인 dbg 를 살펴본다.

dbg

Elixir 를 사용한다면 아마 디버깅을 위해 IO.inspect/2 를 자주 사용해 왔을 것이다. Kernel.dbg/2 는 디버깅을 위해 특화된 기능을 제공하여 IO.inspect/2 를 대체할 것으로 생각된다.

Debugging with IO.inspect/2

IO.inspect/2 는 인자의 값을 보기 좋게 출력하고 해당 값을 그대로 반환한다. 그래서 디버깅 할 때 자주 쓰이는데, 여기저기 쓸 때는 어느 인자의 값을 보여줬는지 알 수 없어서 :label option 을 사용해야 했다.

fun = fn str ->
  str
  |> String.trim_trailing("!")
  |> IO.inspect(label: 1)
  |> String.split()
  |> IO.inspect(label: 2)
  |> List.first()
  |> IO.inspect(label: 3)
end

fun.("Elixir is cool!")
1: "Elixir is cool"
2: ["Elixir", "is", "cool"]
3: "Elixir"
"Elixir"

Debugging with Kernel.dbg/2

Kernel.dbg/2 는 크게 두 가지로 사용법이 나뉜다. 먼저 arguments 없이 사용하면 해당 위치에서의 binding 을 출력한다.

fun = fn str ->
  dbg()

  str
  |> String.trim_trailing("!")
  |> String.split()
  |> List.first()
end

fun.("Elixir is cool!")
[/Users/json/workspace/project/json/json_corp/apps/json_corp/priv/posts/20220918_elixir_1_14.livemd#cell:2: (file)]
binding() #=> [fun: #Function<42.3316493/1 in :erl_eval.expr/6>, str: "Elixir is cool!"]

"Elixir"

fun/1 이 호출되었을 때 binding 되어있는 fun, str 을 출력하는 것을 확인할 수 있다.

Kernel.dbg/2 를 arguments(code pipeline) 와 함께 사용하면, 코드를 분석하여 매 단계 마다의 디버깅 정보를 출력한다.

fun = fn str ->
  str
  |> String.trim_trailing("!")
  |> String.split()
  |> List.first()
  |> dbg()
end

fun.("Elixir is cool!")
[/Users/json/workspace/project/json/json_corp/apps/json_corp/priv/posts/20220918_elixir_1_14.livemd#cell:6: (file)]
str #=> "Elixir is cool!"
|> String.trim_trailing("!") #=> "Elixir is cool"
|> String.split() #=> ["Elixir", "is", "cool"]
|> List.first() #=> "Elixir"

"Elixir"

|> String.trim_trailing("!") #=> "Elixir is cool" 와 같이 pipeline 의 각 코드와 그 결과가 모두 출력되기 때문에 디버깅 하기가 매우 수월하다.

IEx + dbg

dbg 는 backend 를 설정가능하다. 이 의미는 Kernel.dbg/2 로 전달되는 정보를 가지고 원하는 대로 동작을 구성할 수 있다는 것이다. 참고로 위에서 본 것은 default backend 인 Macro.dbg/3 의 동작이다.

IEx 에서는 dbg 에 자체적인 backend 로 코드를 단계별로 실행하며 디버깅 할 수 있는 prying 기능을 지원한다.

asciicast

Livebook + dbg

Livebook 에서도 kino 의 custom backend 를 이용해 interactive 하게 디버깅 할 수 있는 기능이 추가될 예정이다.

다음에는 이어서 Elixir v1.14 에 추가된 PartitionSupervisor 에 대해 다뤄보겠다.