如何有效管理Clojure代码库?

Mat*_*ick 22 unit-testing clojure

我和同事是Clojure的新手.几个月前我们开始了一个项目,但很快发现我们在处理我们的代码库时遇到了困难 - 通过500 LOC我们基本上不知道从哪里开始调试,当出现问题时(通常是这样).而不是成对,功能是获取列表,数字,或什么是你.

现在我们开始一个新的但相关的项目,并将大量旧代码迁移过来.但我们又一次撞墙了.

我们想知道,我们如何有效地管理Clojure项目,尤其是在我们对现有代码进行更改时?

我们提出了什么:

  • 自由使用单元测试
  • 自由使用前,后条件
  • 函数注释中的非正式类型声明
  • 使用defrecord/defstruct/defprotocol实现数据模型,这将真正简化测试

但后期,前置条件似乎不经常使用.单元测试+评论只会对此有所帮助.似乎Clojure程序员通常不会实现正式的数据模型.

我们不是得到Clojure吗? Clojure程序员如何知道他们的代码是健壮且正确的?

Art*_*ldt 9

简单的可组合抽象

"最好让100个函数在一个数据结构上运行,而不是让10个函数在10个数据结构上运行." - Alan J. Perlis

对我来说,这完全是关于编写简单的函数.尝试将每个功能分解为最小的单位,然后使用另一个功能组合它们来完成您需要的工作.你知道你的状态很好,每个功能都可以独立测试.如果你在宏观上过于沉重,那么它可以使这一步更难,因为宏的组成不同.

干,说真的,不要重复自己

从一堆命名空间中的良好分解函数开始; 每当我需要其他地方的可组合部分之一时,我"提升"该功能,直到两个命名空间包含的库.通过这种方式,您常用的抽象类型会在项目过程中演变为"足够的框架".除非你真的有离散的可组合抽象,否则很难做到这一点.


mik*_*era 9

我认为这实际上是一个不断发展的领域--Clojure并没有真正存在足够长的时间来管理所有用于管理大型代码库的最佳实践和相关工具.

我的经验提出了一些建议:

  • 以"自下而上"的方式构建代码 - 通常,您希望构建代码的方式将在文件顶部(或从另一个命名空间导入)和"业务逻辑"代码中使用"实用程序"代码在文件末尾使用这些实用程序功能.如果这看起来很难做,那么可能暗示您的代码需要进行一些重构.

  • 测试作为示例 - clojure中的测试代码非常适用于检查代码的完整性以及文档(例如"此函数期望的参数类型是什么?").如果您遇到错误,请参考您的测试来检查您的假设,并编写一些新的测试来清除出错的地方.

  • 保持函数简单并组合它们 - 这是对函数式编程的" 单一责任原则 " 的扩展.我认为在Clojure函数中有超过5-10行是一个主要的代码气味(如果这看起来很极端,请记住,你可以在5-10行Clojure中实现尽可能多的50-100行Java/C#)

  • 注意"命令式习惯" - 当我第一次使用Clojure时,我在Clojure中编写了许多伪命令式代码.一个例子是用"dotimes"模拟一个for循环并在一个原子中累积一些结果.这可能是痛苦的 - 它不是惯用的,它令人困惑,通常有一个更聪明,更简单,更不容易出错的功能方式.这需要练习,但从长远来看它是值得的...

  • 在REPL上调试 - 通常当我遇到问题时,在REPL编码是最简单的方法来清除它.通常这意味着运行较大算法的某些特定部分来检查假设等.

  • 重构常见的实用功能 - 你可能会在许多功能中找到一堆常见的或结构重复的.非常值得将其推广到您可以在其他地方或项目中重复使用的功能或宏 - 这样您就可以更严格地测试它并在多个地方获得好处.如果你可以一路上到Clojure本身就可以获得奖励积分!如果你做得这么好,那么你的主代码库将非常简洁,因此易于管理,只包含真正的特定于域的代码.