在clojure应用程序中放置数据库访问/功能的位置?
我正在编写一个小型Clojure应用程序,它与具有2-3个不同集合的MongoDB数据库有很多交互。
我来自OOP / Ruby / ActiveRecord背景,标准实践是为每个数据模型创建一个类,并让每个类访问数据库。 我在clojure项目中开始做同样的事情。 每个“数据模型”我有一个名称空间,每个都有自己的数据库连接和CRUD函数。 然而,这并没有感觉到非常的功能或类似clojure,我想知道是否有一种更习惯的方式来做到这一点,例如拥有带有get-post
类函数的data
或database
名称空间,并限制对数据库的访问只有该名称空间。
这看起来好像将数据库客户机依赖关系隔离为一个名称空间,并将纯功能与具有副作用的纯功能分开。
另一方面,我将会有更多的命名空间,我需要从我的应用程序的许多不同部分引用,并且名为“数据”的名称空间对我来说似乎很奇怪。
在Clojure中是否有一种常规的,习惯性的方式?
一个很好的,可以说是Clojure应用程序中最常用的(采用Clojure雷达的“采用”)方式是由Stuart Sierra伟大的组件库提出的。 简而言之,Component的哲学就是将所有的有状态资源存储在一个明确定义它们相互关系的system
映射中,然后以这样一种方式来构建代码,即你的功能只是将状态传递给对方。
连接/环境访问
你的系统的一部分将是管理你的应用程序的'机器':启动Web服务器,连接数据存储,检索配置等。将这部分放在与业务逻辑不同的命名空间中(业务逻辑命名空间应该不知道这个名字空间!)。 正如@superkondukr所说,Component是一个经过战斗测试并且有据可查的方式来做到这一点。
将数据库连接(以及其他环境依赖关系)与您的业务逻辑进行通信的推荐方式是通过函数参数,而不是全局变量。 这将使所有事情都变得更加可测试,REPL友好,并且明确谁取决于谁。
所以你的业务逻辑函数将接收连接作为参数并将其传递给其他函数。 但是,连接从哪里来呢? 我这样做的方式是在进入系统时将它附加到事件/请求上。 例如,当您启动HTTP服务器时,您将连接附加到每个进入的HTTP请求。
命名空间组织:
在OO语言中,对数据的常规支持是代表数据库实体的类的实例; 为了提供一个惯用的OO接口,业务逻辑被定义为这些类的方法。 正如Eric Normand在最近的通讯中所描述的,您将模型的“名称”定义为类,将“动词”定义为方法。
因为Clojure强调传递信息的简单数据结构,所以你实际上没有这些激励措施。 你仍然可以通过实体来组织你的命名空间来模仿这个,但我其实并不认为它是最优的。 您还应该说明,与大多数OO语言中的类不同,Clojure名称空间不允许循环引用。
我的策略是: 按用例组织您的名称空间 。
例如,假设您的域模型包含用户和帖子。 您可能拥有用于用户CRUD和核心业务逻辑的myapp.user
命名空间; 同样,你可能有一个myapp.post
命名空间。 也许在你的应用程序中,用户可以像帖子一样,在这种情况下,你可以在需要myapp.user
和myapp.posts
的myapp.like
命名空间中管理它。 也许你的用户可以在你的应用中成为朋友,你可以在myapp.friendship
命名空间中进行管理。 也许你有一个小型的后台应用程序,其中包含关于所有这些的数据可视化:例如,您可以将它放在myapp.aggregations
命名空间中。
上一篇: Where to put database access/functionality in clojure application?