Clojure中if-else no-ops的样式

时间:2017-03-03 18:15:29

标签: clojure

我已经测试了我是否要执行特定操作,如果不这样做,我想记录。不做它的分支只包含一个返回零的日志操作。

我经常发现自己写的是:

(if-not (need-to-do-it?)
  (log "Don't need to do it")
  (do
    (log "Doing it")
    (do-something)))

这个弱点类似于经典的C if错误。有人可以删除log并完全更改程序的语义(尽管这会导致语法错误)。

所以我可以通过包含一个带有显式nil的'块'来表示无操作。但这看起来很混乱。

(if-not (need-to-do-it?)
  (do
    (log "Don't need to do it")
    nil)
  (do
    (log "Doing it")
    (do-something)))

替代方案是这样,更清楚但需要额外的结合...

(let [need-to (need-to-do-it?)]
  (when-not need-to
    (log "Don't need to do it"))

  (when need-to
    (log "Doing it")
    (do-something)))

但它更冗长。

if分支中的if分支或类似的副作用函数中是否存在表达此类日志记录no-op的通用模式?每次解释都不是很好。

4 个答案:

答案 0 :(得分:1)

在您的示例中,您的第一个示例是IMO最惯用且最简单的。你的第二个例子是不必要的复杂和丑陋,第三个例子让读者想知道,“为什么要使用whenwhen-not,而不只是if?”

由于没有花括号可以处理,并且由于clojure的语法比其他语言简单得多(例如,95%的clojure形式是(function args),因此有人无意中删除了“then”部分如果他们这样做,那将是一个很好的教训,并且试图防止这种情况将导致代码对于绝大多数的clojure人群而言不太可读(你的第二个和第三个例子),为了节省少数人自己。

顺便说一下,当涉及到日志等跨领域问题时,请考虑使用Robert Hook library。它非常小巧,易于使用,是使用面向方面编程原理的一个很好的例子:您不会污染代码以适应重要的事情,但与业务逻辑无关。

答案 1 :(得分:1)

我认为你最关心的问题应该是让你的代码清晰明了 可能。关注bug的类型是错误的 不同的语言 - 特别是那些不同或担心的语言 关于其他人修改代码和意外更改语义 你的程序(这是测试的目的)。我也会对日志记录保持警惕 太多了。这是我经常看到的一个错误。

无论您使用何种语言,记录活动的语句都倾向于 分散了代码实际做的事情。开发人员经常相信他们 让事情更清楚。然而,实际上,它们只是在创造 使基础算法模糊不清的干扰。

如果你做了太多的日志记录,那么你会产生大量的日志输出 没有人看过。现实是只有日志才能看到 出现问题或验证某些关键行为已经发生。保持你的 记录到最低限度。记录做和不做的通常是代码气味 除非你在开发或调试过程中暂时这样做 流程。

而不是记录决策,记录操作。缺少预期的日志消息 可以告诉你一条消息说没有发生任何事情。如果重要的话 要知道是否发生了某个操作,请记录该操作并将其留在该操作中。别 还记录该操作未发生。如果知道一个重要的话 没有发生任何操作,请记录该操作,并且在执行操作时不要记录操作 发生。

将您的日志记录绑定到操作。如果需要记录调用函数, 然后把这一点记录放在动作本身而不是 分别。这将防止有人修改过的误导性日志记录 代码并删除了日志消息,给出了错误的信念,但操作没有 它发生时。

通过你的例子,我会做

(when need-to-do-it?
  (do-something)) ;; do-something can log if necessary

(if need-to-do-it?
  (do-something) ;; which itself may log what it does
  (log "Not doing it"))

我更喜欢 if over if-not ,因为那时焦点在于算法。同 if-not 重点是日志记录而不是代码实际上是什么 意味着要做。

答案 2 :(得分:0)

在我看来,您的第二个解决方案是最干净,最直观的。在这里,明确有助于理解。这也很容易发现,嵌套排列很好。

在第三个解决方案中,您依赖when返回nil,就像您依靠log在第一个解决方案中返回nil一样。第三个解决方案也有与第一个解决方案相同的问题:语义可能会被意外更改,因为" if / else"是隐含的。

答案 3 :(得分:0)

我会坚持95%的时间使用第一种形式。毕竟,如果有人认为他们可以从程序中随机删除行而不改变行为,那么你可以做的就是防御它。

我确实认为清晰度通常是额外明确的,所以有时我可能倾向于第三种形式。在这种情况下,我没有看到中间版本增加了很多价值。

由于Clojure已经明确界定了开头和& (...)中每个表达式的结尾,在{...}中包含或不包含单行的C错误并不存在。实际上,C版看起来像:

if need-to-do-it() {
  log("Don't need to do it")
} else {
  log("Doing it")
  do-something()
}

VS

if need-to-do-it() {
  log("Doing it")
  do-something()
}

在Clojure中,删除if表达式中的一半子句与删除C中if-else语句中一半块的同样重大变化。