像叔叔鲍勃那样的Clojure架构

Clojure Architecture like Uncle Bob did

我正在尝试实现Clojure体系结构,就像Bob叔叔在那里所做的那样:http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html,就像他在第07集"体系结构、用例和高级设计"的"干净代码"中所描述的那样。

Nothing in an inner circle can know anything at all about something in
an outer circle.

enter image description hereenter image description here

我想用所有的业务规则和测试来编写应用程序的核心。这个核心必须对数据库中的"对象"进行定义,比如用户、支付、广告等,但是如何实现这一点必须在更高的应用程序级别上进行。

所以问题是:你能给我一个在Github上很好的体系结构应用的例子吗,就像在带圆圈的图像上一样?我正在学习Clojure,我想看看它在技术上是如何做到的。我试着自己去做,但结果不好。简单的代码示例对我有很大帮助。我想知道如何在Clojure中逐步创建类似于图像的层。

我将很高兴有任何关于如何在Clojure中高质量地做到这一点的信息。可以是代码、视频或文章。可以是免费的,也可以买。


Bob叔叔干净架构的关键元素是依赖倒置。使用Clojure实现这一点有多种方法:使用高阶函数和协议可能是最相关的两种方法(我的blog post on dependency inversion on on Clojure中不知羞耻的插件)。例如,您可以为您的数据定义一个持久性协议,它完全不了解特定的实现:

1
2
3
 (defprotocol MyDataDao
    (load-data [])
    (save-data []))

然后,您可以使用数据库或普通文件系统实现上述协议(注意:使用reify只是一个选项):

1
2
3
4
5
6
7
 (defn make-mydata-db-dao []
    [... db-setup-code ... ]
    (reify MyDataDao
         (load-data []
            [... data-query-code ...])
         (save-data []
            [... data-save-code ...])))

而不是手工制作的make-mydata-db-dao,你可能想看看斯图尔特塞拉的优秀组件库。

但是,您还需要实现不同的循环:这基本上是一个使用名称空间并确保将协议定义放入正确的内部循环/层,并将实现放入正确的外部层的问题。

假设您的网关代码一般在名称空间app.gateway.*中。然后,协议MydataDao可能最终出现在名称空间app.gateway.dao中。不过,实现将属于一个不同的外部循环。假设您的所有DB代码都在名称空间app.db.*中,那么您可以将make-mydata-db-dao放入app.db.dao中。

不幸的是,我不知道Clojure中有任何现有的代码库能够彻底实现这一点。事实上,我希望看到一个用任何语言实现的真实例子,并且更多地了解使用它的好处和缺点或困难。