厌倦了用非语义测试来弥补动态类型 - 建议吗?

发布于 2024-10-06 04:21:59 字数 2785 浏览 3 评论 0原文

在开始学习计算机工程之前,我曾经使用 Rails(之前是 PHP)进行了大量的 Web 编程。

从那时起,我用 C 完成了很多学校作业,并用 Objective-C(Mac 的东西)完成了一些个人工作。我学会了喜欢静态类型。

但现在我不得不做一些专业的 Web 开发(自由职业),并再次选择了 Rails。我发现编写非语义类型检查测试真的很烦人。我从 C 和 Objective-C 编译器免费获得这些。我喜欢点击“构建”,让系统检查我的所有代码,看看 A 可以调用 B,B 可以调用一些晦涩的库 C,等等。我所要做的就是测试语义。但对于 Rails,我是编译器。 :(

有没有人走过同样的道路?我使用 C# 和 Java + x 框架进行 Web 开发 ASP.NET MVC 的唯一选择吗?寻求一些建议,甚至一些同情... :P

顺便说一句,我做了一个具体的说明引用 Rails 而不是 Ruby,因为我不介意 Ruby 的动态特性,例如脚本编写或其他类似的东西,但由于 Rails 依赖于如此多的 gem,并且通常会添加许多其他 gem,因此动态类型成为一个问题。

谢谢!

编辑:

我遵循了 pst 的建议并研究了 Scala 在阅读该语言的创建者 Martin Odersky 撰写的《Scala 编程》一书中,我在很多方面都遇到了这段文字。表达了我的担忧以及更多有趣的内容,

摘自 Martin Odersky 的《Scala 编程》第 52 页:

Scala 是静态类型的

静态类型系统分类 变量和表达式根据 他们持有的价值观类型以及 计算。 Scala 脱颖而出 具有非常先进的静态语言 类型系统。从一个系统开始 嵌套类类型很像 Java 的, 它允许您参数化类型 与泛型,使用组合类型 交叉点,并隐藏细节 使用抽象类型的类型。这些给 为建设和建设奠定了坚实的基础 编写您自己的类型,以便您 可以设计接口 同时使用起来安全灵活。

如果您喜欢动态语言,例如 Perl、Python、Ruby 或 Groovy,您都可以 可能会觉得有点奇怪 Scala 的静态类型系统列出 作为其优点之一。后 所有,缺少静态类型 系统被一些人引用为 动态语言的主要优点。 最常见的反对论点 静态类型是他们制作的 程序太冗长,防止 程序员不表达自己 如他们所愿,并使不可能 某些动态模式 软件系统的修改。

然而,这些论点通常并不 违背静态类型的想法 一般,但针对特定类型 系统,这些系统被认为太 冗长或太不灵活。为了 例如,艾伦·凯(Alan Kay), Smalltalk 语言曾经说过: “我并不反对类型,但我不 知道任何不是的类型系统 彻底的痛苦,所以我还是喜欢动态 打字。”

我们希望通过这本书说服您 Scala 的类型系统远非如此 是一种“彻底的痛苦”。事实上,它 很好地解决了两个常见问题 关于静态类型的担忧: 通过类型避免冗长 获得推理和灵活性 通过模式匹配和一些 编写和组合类型的新方法。 排除了这些障碍之后, 静态类型的经典优点 系统可以得到更好的欣赏。 其中最重要的是 好处是可验证的属性 程序抽象,安全 重构,更好 文档。

可验证的属性

静态类型系统可以证明 不存在某些运行时错误。 例如,他们可以证明 诸如以下属性:布尔值永远不会 添加到整数;私有变量 不能从其外部访问 班级;函数被应用到 正确数量的参数;仅有的 字符串曾经被添加到一组 字符串。

未检测到其他类型的错误 通过当今的静态类型系统。为了 例如,他们通常不会检测到 非终止函数、数组 边界违规或划分 零。他们也不会检测到 你的程序不符合它的 规范(假设有一个 规格,就是这样!)。静态类型系统 因此被一些人驳回 因为不是很有用。论点 因为这样的类型系统可以 只检测简单的错误,而 单元测试提供了更广泛的 覆盖率,为什么要费心静态类型 根本吗?

我们认为这些论点没有成立 重点。 虽然是静态类型 系统当然不能替代单位 测试,可以减少 需要照顾的单元测试 一些属性,否则会 需要进行测试。同样,单位 测试不能取代静态类型。 毕竟,正如 Edsger Dijkstra 所说, 测试只能证明存在 错误,永远不会缺席。所以 保证静态类型给出 可能很简单,但它们是真实的 某种形式的担保,金额不限 测试可以交付。

安全重构

静态类型系统提供了 让您做出改变的安全网 到具有高度的代码库 信心。例如考虑一个 重构增加了一个额外的 方法的参数。在静态 您可以更改输入的语言, 重新编译你的系统并简单修复 导致类型错误的所有行。 一旦你完成了这个,你 肯定已经找到了所有的地方 需要改变。这同样适用于 许多其他简单的重构,例如 更改方法名称,或移动 方法从一个类转移到另一个类。在 所有情况下都会进行静态类型检查 提供足够的保证,使新的 系统就像旧的一样工作。

文档

静态类型是程序文档 由编译器检查 正确性。与普通的评论不同的是, 类型注释永远不能超出 日期(至少如果源文件 包含它的最近通过了 编译器)。此外,编译器和 集成开发环境 可以利用类型注释 提供更好的上下文帮助。为了 以综合开发为例 环境可以显示所有 可供选择的成员 确定静态类型 选择的表达式 制作并查找所有成员 那种类型。

I used to do a lot of web programming in Rails (PHP before that) before I started studying computer engineering.

Since then, I've done a lot of school work in C, and some personal stuff in Objective-C (Mac stuff). I learnt to love static typing.

But now I'm having to do some professional web development (freelancing) and have picked up Rails once again. I'm finding it really annoying to write non-semantic type-checking tests. I was getting those for free from C and Objective-C compilers. I loved hitting Build and having the system check all my code to see that A can call B, B can call some obscure library C, etc. All I had to do was test the semantics. But with Rails, I'm the compiler. :(

Has anyone treaded this same path? Are my only options for web development ASP.NET MVC with C# and Java + x framework? Looking for some suggestions, or even some sympathy... :P

By the way, I make a specific reference to Rails rather than Ruby because I don't mind Ruby's dynamic nature for simple stuff like scripting or what not. But since Rails depends on so many gems and since one usually adds a number of other gems, the dynamic typing becomes an issue.

Thanks!

edit:

I followed up on pst's suggestion and looked into Scala. In reading the book Programming in Scala, written by the language's creator, Martin Odersky, I came accross this bit of text that in many ways expresses my concerns and a bit more. Very interesting reading.

Taken from page 52 of Martin Odersky's Programming in Scala:

Scala is statically typed

A static type system classifies
variables and expressions according to
the kinds of values they hold and
compute. Scala stands out as a
language with a very advanced static
type system. Starting from a system of
nested class types much like Java’s,
it allows you to parameterize types
with generics, to combine types using
intersections, and to hide details of
types using abstract types. These give
a strong foundation for building and
composing your own types, so that you
can design interfaces that are at the
same time safe and flexible to use.

If you like dynamic languages such as
Perl, Python, Ruby, or Groovy, you
might find it a bit strange that
Scala’s static type system is listed
as one of its strong points. After
all, the absence of a static type
system has been cited by some as a
major advantage of dynamic languages.
The most common arguments against
static types are that they make
programs too verbose, prevent
programmers from expressing themselves
as they wish, and make impossible
certain patterns of dynamic
modifications of software systems.

However, often these arguments do not
go against the idea of static types in
general, but against specific type
systems, which are perceived to be too
verbose or too inflexible. For
instance, Alan Kay, the inventor of
the Smalltalk language, once remarked:
“I’m not against types, but I don’t
know of any type systemsthat aren’t a
complete pain, so I still like dynamic
typing.”

We hope to convince you in this book
that Scala’s type system is far from
being a “complete pain.” In fact, it
addresses nicely two of the usual
concerns about static typing:
verbosity is avoided through type
inference and flexibility is gained
through pattern matching and several
new ways to write and compose types.
With these impediments out of the way,
the classical benefits of static type
systems can be better appreciated.
Among the most important of these
benefits are verifiable properties of
program abstractions, safe
refactorings, and better
documentation.

Verifiable properties

Static type systems can prove the
absence of certain run-time errors.
For instance, they can prove
properties like: booleans are never
added to integers; private variables
are not accessed from outside their
class; functions are applied to the
right number of arguments; only
strings are ever added to a set of
strings.

Other kinds of errors are not detected
by today’s static type systems. For
instance, they will usually not detect
non-terminating functions, array
bounds violations, or divisions by
zero. They will also not detect that
your program does not conform to its
specification (assuming there is a
spec, that is!). Static type systems
have therefore been dismissed by some
as not being very useful. The argument
goes that since such type systems can
only detect simple errors, whereas
unit tests provide more extensive
coverage, why bother with static types
at all?

We believe that these arguments miss
the point. Although a static type
system certainly cannot replace unit
testing, it can reduce the number of
unit tests needed by taking care of
some properties that would otherwise
need to be tested.
Likewise, unit
testing cannot replace static typing.
After all, as Edsger Dijkstra said,
testing can only prove the presence of
errors, never their absence. So the
guarantees that static typing gives
may be simple, but they are real
guarantees of a form no amount of
testing can deliver.

Safe refactorings

A static type system provides a
safety net that lets you make changes
to a codebase with a high degree of
confidence. Consider for instance a
refactoring that adds an additional
parameter to a method. In a statically
typed language you can do the change,
re-compile your system and simply fix
all lines that cause a type error.
Once you have finished with this, you
are sure to have found all places that
need to be changed. The same holds for
many other simple refactorings like
changing a method name, or moving
methods from one class to another. In
all cases a static type check will
provide enough assurance that the new
system works just like the old.

Documentation

Static types are program documentation
that is checked by the compiler for
correctness. Unlike a normal comment,
a type annotation can never be out of
date (at least not if the source file
that contains it has recently passed a
compiler). Furthermore, compilers and
integrated development environments
can make use of type annotations to
provide better context help. For
instance, an integrated development
environment can display all the
members available for a selection by
determining the static type of the
expression on which the selection is
made and looking up all members of
that type.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雅心素梦 2024-10-13 04:21:59

这是我对动态语言的“抱怨”之一。我想测试语义,而不是类型错误;-) 话虽如此,在所有重要情况下,良好的测试框架/设置确实是必须的,并且良好的代码覆盖率和测试的需求非常重要。

如果您确实想在 JVM 上走静态类型路径(我已经这样做了),我强烈建议您查看 Scala。与使用 Java 相比,使用 Ruby 远没有那么痛苦(而且实际上在不同方面有很多乐趣)。你可以“保留”你认为理所当然的东西——基于表达式的语法、闭包、在许多地方省略类型的能力(不像 Ruby 那样开放,但你确实可以进行编译时类型检查;-), everything(*)-is-an-object OO、统一的访问器方法、轻松构造 DSL 的能力和糖——并获得静态类型语言的好处,包括本地类型推断、模式匹配、相对丰富的集合框架,以及与 Java 的良好集成(包括众多 Web 框架,还有一些利用 Scala 语言的特定于 Scala 的框架)。

C#3.0/4.0(和 .NET3.5+)也不是太破烂(但要避免 C#2.0,它现在希望是一个遗迹),随着 LINQ/闭包的引入,基本类型推断和其他
良好的语言特性 我发现它对于大多数任务来说“可以接受”(猜猜我如何评价 Java 作为一种语言;-)。然而,C# 是一种 CLR 目标语言(有/曾经有一个 .NET Scala 端口,但我不确定状态——尽管它不是主要目标平台)。

既然我提到了 Scala,我还应该提到 F#(现在是“官方”.NET 语言),它采用与 OCaml 类似的“面向对象的函数式”方法——Scala 则恰恰相反,我将其描述为“OO”与功能”。我听说过在类型系统方面支持/反对 F# 与 C# 的争论,但没有 F# 的实际经验。您可能喜欢也可能不喜欢这种范式转变。

快乐编码。

This is one of my "gripes" about dynamic languages. I want to test for semantics, not type errors ;-) That being said, a good testing framework/setup is really a must in all non-trivial situations and good code-coverage and tested requirements is/are important.

If you do want to go down the static-typing path on the JVM (I have), I would highly recommend looking at Scala. Coming from Ruby, it's far less painful (and actually lots of fun in different ways) than going to Java. You get to "keep" the things you take for granted -- an expression-based syntax, closures, the ability to omit types in many places (not as open as Ruby, but you do get compile-time type checking ;-), everything(*)-is-an-object OO, unified accessor methods, ability to construct DSLs easily, and sugar -- and get the benefits of a statically typed language with local type inference, pattern matching, a relatively rich collection framework, and decent integration with Java (including the numerous web-frameworks, there are some Scala-specific frameworks as well which leverage the Scala language).

C#3.0/4.0 (and .NET3.5+) isn't too shabby either (but avoid C#2.0, which is now hopefully a relic), with the introduction of LINQ/closures, basic type inference and other
nice language features I find it "acceptable" for most tasks (take a guess how I would rate Java as a language ;-). However, C# is a CLR-target language (there is/was a .NET Scala port, but I am not sure of the status -- it is not the main target platform though).

Since I have mentioned Scala, I should also mention F# (now an "official" .NET language) which takes the "Functional with OO" approach being similar to OCaml -- Scala is more of the reverse and I would describe it as "OO with Functional". I have heard arguments for/against F# compared to C# w.r.t the type system, but have no practical experience with F#. You may or may not like the paradigm shift.

Happy coding.

指尖微凉心微凉 2024-10-13 04:21:59

这种类型的测试通常不在 Rails 中完成。不要因为必须这样做而烦恼,而是考虑不要担心它。或者也许可以更好地解释为什么你认为这是一个问题,因为大多数 Rails 程序员并不这么认为。

更新

编写 test_include_with_order_works 的人正在确保 Rails 在这种特殊情况下将符号解释为与字符串相同。这看起来不像是您必须测试的东西,因为 Rails 已经为您提供并测试了此功能。坦率地说,我有点惊讶竟然有人会担心符号是否能像字符串一样发挥作用。我们都知道它可以而且经常如此。

总的来说,我认为 Rails 框架必须确保您不做的事情,以便其实现符合其设计。我相信动态类型语言的工作原理是客户端代码不会传递会破坏它们正在调用的方法的参数。如果这样做,他们调用这些方法就没有任何用处。当您的方法可以轻松(并且应该)忽略额外的参数时,您不必浪费时间确保您的方法在提供太多参数时会抛出异常。

因此,我不确定您提供的示例是否真正证明了 Rails 中非语义测试的必要性。

This type of testing is not typically done in Rails. Instead of being annoyed by having to do it, consider not worrying about it. Or perhaps do a better job of explaining why you think it's an issue, since most Rails programmers don't.

Update

The person who wrote test_include_with_order_works is making sure that Rails will interpret a symbol the same as a string in this particular case. That doesn't seem like something you'd have to test, since Rails has already provided and tested this functionality for you. Frankly, I'm a little surprised that anyone would even worry about whether or not a symbol will function like a string. We all know that it can and often does.

In general, I think that the Rails framework has to ensure things that you do not so that its implementation will conform to its design. I believe that the working philosophy in dynamically typed languages is that client code will not pass in parameters that will break the methods they're calling. If they do, they get no use out of calling the methods. You don't have to waste your time making sure that your methods will throw exceptions when provided too many parameters, when your method can just as easily (and should) ignore the extra parameters.

So, I'm not sure if the examples you've provided really demonstrate the need for non-semantic testing in Rails.

回眸一笑 2024-10-13 04:21:59

当您提到 Rails 时,并且考虑到您对 Scala 感兴趣,您一定应该检查 Lift。这是2008 年对其创建者的采访,以及 2009 年演示文稿(视频),我链接该演示文稿是因为,虽然很旧,但他们将 Lift 与其他语言的替代品。

不过,如果 Lift 不是您的菜,请放心,还有其他 Scala Web 框架。

As you mention Rails, and given that you have become interested in Scala, you should definitely check Lift. Here's a 2008 interview with its creator, and a 2009 presentation (video), which I link because, though old, they compare Lift with alternatives in other languages.

If Lift is not your thing, though, rest assured that there are other Scala web frameworks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文