탭을 사용하여 REPL에서 Clojure 디버깅>

3568 단어 debuggingclojure
때로는 오래된 습관이 죽습니다. 오랫동안 저는 prn 를 사용하여 REPL의 Clojure 코드에서 많은 디버깅을 수행했습니다.

Clojure를 사용하면 콘솔에 작성하여 디버깅하는 것이 들리는 것처럼 원시적이지 않습니다. 물론, 디버거를 실행하고 중단점을 설정할 수 있지만, 올바른 위치에 prn를 삽입하고 올바른 데이터만 있으면 종종 문제를 진단하는 데 필요한 유용한 데이터를 정확히 얻을 수 있습니다.

다른 경우에는 더 많은 데이터 구조를 사용하여 clojure.pprint/pprint ... 하지만 이것은 네임스페이스를 가져오기 위해 더 많은 작업이 필요하며 ns 선언도 정리해야 함을 의미합니다.

이제 나는 Clojure 1.10에 tap> 기능이 추가되었다는 것을 알게 되었고, 이런 종류의 일에 도움이 될 것이라는 것을 막연하게 알고 있었습니다. 마침내 Lacinia 에서 털이 많은 NullPointerException 버그를 디버그하기 위해 시도해 보았습니다.
tap>는 무엇을 합니까? 기본적으로 ... 아무것도. 값을 전달할 수 있는 함수일 뿐이지만 전달해도 아무 일도 일어나지 않습니다(또한 true를 반환함).
tap>add-tap으로 탭을 추가할 때까지 거의 유용하지 않습니다. 탭은 단일 인수를 취하는 모든 함수입니다.
tap>를 호출하면 함수(또는 add-tap가 여러 번 호출되는 경우 함수)가 비동기적으로 호출됩니다.

따라서 예를 들어 (add-tap clojure.pprint/pprint) tap>에 대한 각 후속 호출은 콘솔에 예쁘게 인쇄됩니다. 그리고 tap> 기능은 코어에 있으므로 필요하지 않습니다.

단일 값은 내가 해결하려는 문제에 대해 많은 컨텍스트를 제공하지 않기 때문에 간단한 값을 원하지 않습니다tap>. 대신 하나의 단위로 탭되는 지도를 만듭니다.

(defn fn-i-want-to-debug 
  [simple-arg sometimes-nil-but-too-large-to-print-arg]
  (tap> {:in `fn-i-want-to-debug
         :simple simple-arg
         :nil? (nil? sometimes-nil-but-too-large-to-print-arg})
   ...)


물론 Clojure에서는 즉시 새 지도를 만드는 것이 항상 쉽습니다. 여기서 역따옴표(syntax quote )는 함수 이름이 완전한 네임스페이스 정규화된 기호임을 보장합니다.

위의 예에서 알 수 있듯이 때로는 인수가 너무 커서 효과적으로 인쇄할 수 없지만 디버깅을 위해 그것이 nil인지 아닌지 알 필요가 있습니다. 출력되는 데이터. 괜찮습니다. REPL 지향 개발이 디버거를 실행하는 것보다 더 빠르고 더 나은 이유입니다.

디버거는 한 번에 한 가지만 보여줄 수 있습니다. 그리고 Cursive를 사용하더라도 정확히 무슨 일이 일어나고 있는지 보기 위해 많은 클릭과 많은 눈을 가늘게 뜨고 있을 수 있습니다.

그에 비해 콘솔 출력(dissoc을 통해)은 프로그램에서 문제를 일으키는 상황에 대한 약간의 기록이 될 수 있습니다.

또한 디버거와 tap>를 함께 사용하는 것을 막을 수 있는 것은 없습니다(그러나 생각만큼 자주 필요하지 않을 수도 있습니다).
tap>tap> 또는 prn를 직접 호출하는 것보다 낫습니다. 코드에서 pprint에 대한 호출을 거의 또는 전혀 비용 없이 그대로 둘 수 있기 때문입니다. 필요할 때 tap> 할 수 있으며 ... 실제로 REPL을 다시 시작하지 않고 추가 출력 없이 개발을 계속하려는 경우에도 add-tap 할 수 있습니다.

이것은 매우 고전적인 Clojure입니다... Clojure와 REPL이 서로 잘 결합되어 훨씬 더 유용해지는 최소한의 실용적인 도구입니다.

좋은 웹페이지 즐겨찾기