如何处理库中需要在外部设置的变量?

7

我在几个项目中使用Datomic,现在是将所有通用代码移动到一个小的实用程序库的时候了。

其中一个挑战是处理共享数据库uri,大多数操作都依赖它,但必须由使用该库的项目设置。我想知道是否有一种成熟的方法来解决这个问题。以下是我考虑过的一些替代方案:

  • 在库中删除uri符号,并将uri添加为访问数据库的每个函数的参数

  • 通过alter-var-root或类似机制,在init函数中进行更改

  • 将其作为库中的动态变量*uri*,并在希望小的适配器层中覆盖值,例如:

    (def my-url ...bla...)

    (defn my-fun [args] (with-datomic-uri my-uri (apply library/my-fun args))

  • uri保留为库中的原子


你认为用户是否希望在运行时更改URI,还是对于给定项目只需定义一次就可以了? - Omri Bernstein
不是在运行时,@OmriBernstein。有一个用于测试的数据库和另一个用于生产的数据库。 - konr
2个回答

4
在上一届Clojure/West大会上,Stuart Sierra做了一个名为Clojure in the Large的演讲,介绍了针对较大的Clojure应用程序的设计模式。
其中之一就是您所描述的问题。
总结有关此问题的提示:
1.清晰的构造函数
这样您就可以拥有一个明确定义的初始状态。
  (defn make-connection [uri]
      {:uri uri
       ...}

2 明确依赖关系

  (defn update-db [connection] 
     ...

3 它更容易测试

(deftest t-update
  (let [conn (make-connection)]
    (is (= ... (update-db conn)))))

4 更安全的重新加载

 (require ... :reload)

uri保存在变量中以后绑定是非常常见的,但会引入隐藏的依赖关系,还假设body在单个线程上开始和结束。
观看演讲,了解更多设计技巧。

3

我的感觉是尽可能使大部分的datomic代码不涉及隐式状态。

查询函数需要使用数据库。写入函数(transact)需要使用数据库连接。这样可以最大限度地实现重用,并避免隐含假设,例如仅与一个数据库连接通信或意外地隐式编码查询函数仅适用于当前数据库值 - 而不是过去(as-of)或“未来”(with)数据库值。

协调标准库用例的单个公共连接,然后成为小型附加命名空间的工作。在这里使用原子(atom)来保存uri或连接是有意义的。一些方便的宏,可能称为with-connectionwith-current-db,可以包装主要的库函数,如果手动编码和传递连接和数据库值是一个麻烦。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接