我已经测试了我是否要执行特定操作,如果不这样做,我想记录。不做它的分支只包含一个返回零的日志操作。
我经常发现自己写的是:
(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的通用模式?每次解释都不是很好。
答案 0 :(得分:1)
在您的示例中,您的第一个示例是IMO最惯用且最简单的。你的第二个例子是不必要的复杂和丑陋,第三个例子让读者想知道,“为什么要使用when
和when-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
语句中一半块的同样重大变化。