idiomati c вход в систему clojure - PullRequest
       4

idiomati c вход в систему clojure

3 голосов
/ 01 февраля 2020

Я новичок в clojure и хотел бы понять подходы регистрации в clojure, исходя из императивного фона . В производственной программе java я обычно использую LOG (debug / info) в start-end метода , что-то вроде этого:

public void foo(){
   logger.debug("starting method to embrace %s", rightIdioms);
   doSomething();
   logger.debug("successfully embraced %s idioms", idioms.length);
}

Я знаком с pro / con's ведения журнала и знание инструментов , доступных для этого в clojure,

Я также могу найти некоторые доводы , ведущие запись в подходе, упомянутом выше , который усиливает напряжение , которое я чувствую при входе в систему без необходимости:

  1. регистрация - это побочный эффект , и замыкание толкает в сторону эффекты.
  2. больше строк кода или «сложность кода»: в java - наличие больших классов является обычным явлением (геттеры, сеттеры, конструкторы), в clojure , выражения возвращают значения, ведение журнала «усложняет» процесс и укрепляет небольшие функции и пространства имен: (одним из примеров может быть необходимость перехода с if на if-let или if-do для ведения регистрации):

    (defn foo [x]
      (if (neg? x)
        (inc x)
        x))
    
    (defn foo [x]
      (if (neg? x)
        (let [new-x (inc x)] 
          (logger/debug (format "inc value, now %s" new-x)
          new-x))
        x))
    

Я прочитал протоколирование с помощью clojure/tap или tracing, но не уверен, что нашел его полезным.

Каковы подходы или идиоматический c способ сделать запись в clojure?

Ответы [ 3 ]

1 голос
/ 01 февраля 2020

Я думаю, что лучшая библиотека журналов в Clojure в настоящее время - Cambium . Я думаю, что это немного лучше, чем его (более старый) конкурент Тембр .

Чтобы помочь с потоком программ при регистрации или отладке выходных данных функции, я иногда использую небольшой макрос with-result из Библиотека Тупело . Например:

  (is= 42
    (with-result 42
      (spyx (+ 2 3))))

этот модульный тест показывает, что возвращается результат 42, хотя самое внутреннее выражение - 5. Инструмент отладки spyx (сокращение от «шпионский явный») печатает следующее при запуске теста:

(+ 2 3) => 5

Если вы хотите получить постоянный вывод журнала, используйте Cambium, например:

(log/info "Application started")
(log/info {:args (vec args) :argc (count args)} "Arguments received")

с результатом:

18:56:42.054 [main] INFO  myapp.main - Application started { ns=myapp.main, line=8, column=3 }
18:56:42.060 [main] INFO  myapp.main - Arguments received { args=["foo" "10"], argc=2, ns=myapp.main, line=9, column=3 }

Я бы немного переписал функцию, чтобы сохранить окончательный результат в переменную, а затем занялся бы регистрацией в одной из 2 форм:

(ns tst.demo.core
  (:use tupelo.core tupelo.test)
  (:require [cambium.core :as log]))


(defn foo-1 [x]
  (let [result (if (neg? x)
                 (inc x)
                 x)]
    (log/debug (format "foo-1 => %s" result))
    result))

(defn foo-2 [x]
  (let [new-x (if (neg? x)
                (inc x)
                x)]
    (with-result new-x
      (log/debug (format "foo-2 => %s" new-x)))))

(dotest
  (is= 42
    (with-result 42
      (spyx (+ 2 3))))

  (is=  2 (foo-1 2))
  (is= -1 (foo-1 -2))

  (is=  2 (foo-2 2))
  (is= -1 (foo-2 -2))
  )

, который дает вывод:

-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

Testing tst.demo.core
(+ 2 3) => 5
11:31:47.377 [main] DEBUG tst.demo.core - foo-1 => 2 { ns=tst.demo.core, line=15, column=5 }
11:31:47.378 [main] DEBUG tst.demo.core - foo-1 => -1 { ns=tst.demo.core, line=15, column=5 }
11:31:47.379 [main] DEBUG tst.demo.core - foo-2 => 2 { ns=tst.demo.core, line=23, column=7 }
11:31:47.379 [main] DEBUG tst.demo.core - foo-2 => -1 { ns=tst.demo.core, line=23, column=7 }

Ran 2 tests containing 7 assertions.
0 failures, 0 errors.

Для временных отладочных распечаток я бы сделал это так:

(defn foo [x]
  (if (neg? x)
    (spyx :foo-inc (inc x))
    (spyx :foo-noop x)))

с тестом:

  (is=  2 (foo 2))
  (is= -1 (foo -2))

и вывод

:foo-noop x => 2
:foo-inc (inc x) => -1

Пример проекта

Вы можете клонировать следующий репозиторий, чтобы увидеть, как все настроено:

1 голос
/ 06 февраля 2020

В этом сообщении в блоге дается несколько лучших практик , так как предложение регистрировать данные, а не строки, может быть очень полезным и соответствовать журналу в стиле clojure. событие в журнале может быть примерно таким:

{:service     :user.profile/update
 :level       :debug
 :time        "2020-01-01"
 :description {:before '0
               :after  '1}
 :metric       10ms}

Где metri c может быть чем угодно, со времени обновления до количества строк, извлеченных из базы данных.

Тогда когда у вас есть данные, вы можете делать с ними все что угодно - анализировать их, чтобы получать информацию или группировать для поиска и поиска. Вы всегда можете превратить структуру данных обратно в строку, если это необходимо для ведения журнала консоли.

0 голосов
/ 01 февраля 2020

Ведение журнала не будет иметь побочных эффектов для данных программы, поэтому Clojure ethi c не хмурится на них.

Чтобы избежать необходимости переделывать функцию для регистрации своих входов и выходов, быстрый взлом злоупотреблять пре- и постусловиями:

(defn foo [x]
  {:pre [(do (println "foo" x) 
             true)]
   :post [(do (println "foo" x "==>" %) 
              true)]}
  (if (neg? x)
    (inc x)
    x))

true делает условие успешным. В противном случае программа остановится.

Предварительные и последующие условия задокументированы здесь: https://clojure.org/reference/special_forms#_fn_name_param_condition_map_expr_2

Вот как выглядит расширенная запись foo в REPL:

user> (foo -7)
foo -7
foo -7 ==> -6
-6
...