从静态打字到动态打字

我一直致力于静态类型语言(C / C ++,Java)。 我一直在玩Clojure,我真的很喜欢它。

我担心的一件事是:假设我有一个窗口,需要3个模块作为参数,并且需求发生变化,我需要将另一个模块传递给函数。 我只是更改了函数,编译器在我使用它的任何地方都会抱怨。 但是在Clojure中,在调用函数之前不会抱怨。 我可以做一个正则表达式搜索和替换,但似乎有机会错过一个调用,它将被忽视,直到该函数实际被调用。 你们怎么处理这个?

这是动态类型语言中自动化测试/测试驱动开发更为重要的原因之一。 我没有使用Clojure(我主要使用Ruby),所以很遗憾我不推荐一个特定的测试框架。

我要提到的第一件事是,布鲁斯·埃克尔写了一篇非常有趣的文章,名为“ powershell打字与powershell测试” (目前这个链接已经失效,但不幸的是,它很快就会出现)。

他的想法是,在处理编译语言时,编译器只是自动测试的第一个自动步骤。 在转向动态语言时,您将失去第一级自动测试。 但在这两种情况下,第一个自动水平只是测试的一部分,甚至不是一个非常重要的部分。

他的观点是,如果你正在正确地开发程序,即进行某种forms的测试和回归测试,缺少编译器只会迫使你添加一些更基本的测试,这就是为什么它没有大的损失。

所以我想我给你的第一个答案是,专注于你的测试,你应该做的事情,这些改变不应该对你造成太大的影响。

我要提到的第二件事是我见过的许多动态语言(例如,Python)在不破坏现有代码的情况下有更好的方法来改变方法/类。

例如,使用Python,如果您的方法用于接受两个参数但现在需要第三个参数,则可以始终添加默认参数而不破坏任何现有代码,但现在可以使用。 这是一种非常基本的技术,但在Python的情况下(我还假设大多数其他动态语言),这些技术可以变得更有趣; 因为它们是动态的,你几乎可以改变特定模块的函数实现,改变变量的含义等等。

我建议看看Clojure有哪些技术允许类似的东西,并决定它们是否适用于你的情况。

如果该方法是您不是唯一用户的公共接口的一部分,那么您也会执行相同的操作。

您使用额外模块添加新方法,并更改旧方法以使用合适的默认值调用新方法。

哦,如果你的程序很大,请确保你有好的测试(测试 – 应该比Java更简单)

测试覆盖率绝对重要。 但是动态类型语言将允许您以不同的方式工作。 在强类型语言(如Java)中,接口的更改需要修改所有调用者。 在Ruby中,你可以这样做 – 但可能不会。 相反,您可能会通过以下几种方式之一为方法增加灵活性。 即:

  • 你倾向于使用很少的方法在Ruby中使用多达三个参数(而不是Java)。 因为您没有强大的Java类型接口,所以您可以将问题分解为更小的部分和步骤。 编写仅占用1个参数的方法更常见,然后在它变得更复杂时进行重构。
  • 在添加更多参数的同时保留旧行为是可能的 – 并且是常见的。 例如,如果必须向两个参数方法添加第三个参数,则将设置其默认值以保留旧行为(并保存重构)。 如果您熟悉jQuery这样的Javascript库,他们会利用“可选”参数随处可见。
  • 类似于可选参数,方法可以增长以获取灵活的参数列表。 通过可靠的测试覆盖,您可以非常轻松地向现有方法添加新行为,并安全地知道您没有破坏现有代码。 在Rails中,像“render”这样的方法有很多选择。

你在Clojure中完全没有编译器支持。 在您给出的具体示例中,它是更改的函数的arity,可以通过编译Clojure代码来获取。 我仍在进行强大的 – >动态的打字过渡,并找到这种安慰!

当您转向动态语言时,您会失去一定程度的重构和类型安全性。 编译器拥有的信息越多,编译时就能越多。

蒂姆布雷在这里讨论它,塞德里克在这里的批评,以及关于艺术的一篇文章详细讨论它。

如果你真的需要静态类型,你可以使用https://github.com/clojure/core.typed和它的leiningen模块来测试静态变量传递。