24

我正在探索开发新系统(Web 应用程序)的几种可能性。

我是一个“老式”的人,本质上是面向对象的(多年前从程序转换而来)。我玩过 Python 并学习了一点 Ruby,但坦率地说,我对使用 Microsoft 的工具(C#、ASP.NET MVC)很感兴趣。在构建大型复杂应用程序时,所有这些运行时输入、基本内容上没有编译器错误等等只会让我的生活更加艰难。

我经常听到人们谈论你可以用动态语言做的伟大事情,但是除了狗、猫的例子以及你可以多快地编写一种很酷的方法来计算事物之外,Visual Studio 的“工业实力”似乎只是消除了那些动态语言提供了整洁的小东西,特别是现在你有免费的 VS 快速版本和免费为初创企业提供的完整版本。

我觉得我在这里遗漏了一些东西,因为大型应用程序确实是使用动态语言开发的,那么在查看大型复杂应用程序时,这些语言使您能够做的那些伟大的事情是什么?是什么让你放弃了VS的实力?

4

9 回答 9

19

“你能多快编码”让我非常担心,以至于我很高兴地放弃了通过编译的漫长而缓慢的工作。

动态语言的优点。

  1. 没有编译,没有构建。只需编码和测试,然后部署到生产。

  2. 即刻满足。没有时间花时间在 API 调用可能是什么上绞尽脑汁。只需在 Python >>> 提示符下交互式地键入它,看看它实际上做了什么。

  3. 非常非常短的设计周期。与其用额外的接口定义和适当的抽象声明和覆盖来精心制作一个类层次结构,我可以只对类进行编码,对它们进行单元测试并完成。

  4. 更少的代码。动态语言自省减少了源代码的数量。我不会在我的应用程序中写这些东西;我依靠框架为我做这件事。但是基于框架的代码通常很短;Java 中没有如此常见的重复声明,您必须在 XML 配置中重复一些事情。

  5. 没有奥秘。正如我们在 Python 社区中所说:“使用源代码,Luke。” 框架的作用或 API 的真正含义没有歧义。

  6. 绝对的灵活性。随着我们的需求发生变化,我们不必为破坏整个架构的破坏性变化而苦苦挣扎。我们可以 - 简单地 - 对一些类进行更改,因为 Python 的 Duck Typing 消除了对我们认为不需要的缺失接口定义进行改造的需要。他们只是没有;我们没有编写的代码是我们不必修复或维护的代码。

  7. 弹力。当我们的精算师头脑发热时,我们不必花费数月时间来弄清楚如何将这种新的、更复杂的承保模式集成到应用程序中。几乎任何东西都可以被挤进去。同样,这严格来说是鸭式打字的结果。我们无需将其强制安装到无法预期新业务模型的架构中。

  8. 由于源应用程序,源可以是它自己的配置文件。我们没有某些外来语法的 XML 或 INI 配置文件。我们在 Python 中有配置文件。Django 框架就是这样做的,我们跟随他们的脚步。我们有非常复杂的模拟数据声明,用于销售演示和单元测试。超级复杂的数据实际上是来自数据库的 Python 对象的集合——除了——我们省略了加载数据库。只调整 Python 对象构造函数而不是加载 SQL 数据库更简单。

[顺便提一句。在使用 Cobol、Fortran、PL/I、Java、C、C++ 开发软件 30 多年后,我只是厌倦了大多数编译语言所需的相对低级的手动优化。多年前,我读过一篇关于大多数编译器效率低下的评论:它引导我们创建复杂的构建系统来解决编译器的限制。我们只需要make因为cc太慢了。]


编辑

动态编程不会让你成为天才。它只是节省了很多时间。你仍然需要管理学习过程。你不知道的事情在所有语言中都很困难。动态语言通过允许您逐步进行,一次发现一件新事物而无需进行大量设计工作,只是为了发现您的假设是错误的,从而为您提供了杠杆作用。

如果您想基于被误解的 API 编写大量代码,那么动态语言可以提供帮助。您可以自由地编写大量崩溃和烧毁的代码:C#、VB、C++、Java 或 Python。您总是可以编写不起作用的代码。

编译器会提前警告您代码将无法工作。通常,不编译是一个很大的提示。但是,您仍然可以编写大量代码来编译并通过所有单元测试。编译器只检查语法,不检查语义。

Python 可以提前警告您代码将无法工作。通常,您无法让它以交互方式运行。但是,您仍然可以编写许多未通过所有单元测试的代码。

于 2009-06-25T11:13:00.687 回答
6

静态类型是过早优化的一种形式。当您可能不具备做出决策的知识时,它会迫使您提前做出详细的决定。除非您创建足够多的类型以使其具有逻辑意义,否则它不会特别有助于程序的正确性。这使得动态更改数据结构变得困难。

你从中得到的是非常有限的正确性检查:非常有限,因为它没有分离使用整数的方式,例如。假设我们正在处理行和列;两者都可能是整数,但不应互换使用行和列变量。您还可以获得优化,这可能是一件非常有用的事情,但不值得放慢初始开发速度。您可以通过编写适当的测试来弥补正确性检查。

Common Lisp 类型系统对此很有用。所有数据对象都知道它们的类型,如果您愿意,可以显式指定该类型。

eval 循环类型的执行模型使得在编写例程时测试例程变得非常容易。您不必事先明确编写测试(尽管没有什么可以阻止您这样做);您可以编写它们并即时执行它们(然后您可以将其细化为测试套件 - 将其视为增量测试开发)。

没有长的构建步骤可以更容易地进行测试驱动的开发,因为运行测试要快得多。您不必在每次想要测试时都分解您正在做的事情。

当我听到人们抱怨动态语言时,我想起了人们抱怨没有排他锁的版本控制系统。有些人需要很长时间才能意识到他们通过迁移到现代 VCS 获得了什么,同样有些人需要很长时间才能欣赏动态语言。

于 2009-06-25T14:12:38.920 回答
5

一般来说,我更喜欢谈论“交互式”语言而不是“动态”语言。当您只有一个编辑/编译/运行周期时,任何周转都需要很长时间。好吧,至少按照“需要保存、编译、查看编译报告、试运行、查看测试结果”的顺序。

使用交互式语言,通常很容易修改一小部分,然后立即测试结果。如果您的测试运行仍然需要很长时间,那么您并没有赢得那么多,但您通常可以在较小的情况下进行测试。这有利于快速发展。一旦你有一个已知正确的实现,这也有助于优化,因为你可以快速开发和测试你的新的、改进的函数并尝试不同的表示或算法。

于 2009-06-25T11:38:12.727 回答
3

这是我对先前类似问题的部分回答(我知道 C#。我会使用 Python 提高工作效率吗?):

我自己来自 C#/.NET 背景。在 abt 中开始使用 .NET 进行编程。2001 年,大约在同一时间被引入 Python。2001 年,我花在 C# 和 Python 上的时间大约是 90% C# / 10% Python。现在,这个比例是 5% C# / 95% Python。在我的公司,我们仍然维护着一条基于 .NET 的产品线。但是所有的新东西都是基于 Python 的。

我们在 Python 中创建了重要的应用程序。

以我的经验,让我在 Python 与 C# 中更高效的原因是:

  • 它是一种动态语言。使用动态语言通常允许您从应用程序中删除整个架构层。Python 的动态特性允许您以比 C# 更自然和灵活(语法方面)的方式创建可重用的高级抽象。
  • 图书馆。社区提供的标准库和很多开源库都是高质量的。Python 用于应用程序的范围意味着库的范围很广。
  • 更快的开发周期。没有编译步骤意味着我可以更快地测试更改。例如,在开发 Web 应用程序时,开发服务器会检测更改并在保存文件时重新加载应用程序。从我的编辑器中运行单元测试只需一个按键,并且立即执行。
  • “轻松访问”常用功能:列表、列表推导、生成器、元组等。
  • 不太冗长的语法。您可以使用比典型 .NETweb.config文件更少的代码行来创建基于 WSGI 的 Python Web 框架 :-)
  • 好的文档。好书。
于 2009-06-25T11:43:42.263 回答
2

互动贝壳! 这是一个巨大的生产力提升。只需启动 irb/python 以坐在交互式 shell 前面(分别用于 ruby​​ 和 python)。然后,您可以交互式地测试您的类、函数、实验表达式(非常适合正则表达式)、不同的语法和算法。这是真正的程序员游乐场,也是调试的好工具。

关于错误只有我两分钱:

在构建大型复杂应用程序时,所有这些运行时输入、基本内容上没有编译器错误等等只会让我的生活更加艰难。

编译器可检测错误是您在执行各种自动测试(单元、功能等)时将检测到的错误类型,以及无论如何都应该编写的错误。可能 Linus Torvalds 可以说:回归测试”?那是什么?如果它可以编译,那很好,如果它启动它是完美的,但他有成千上万的测试人员可以为他完成这项工作。啊,使用交互式 shell,你得到了关于您的语法的自动反馈,例如当您编译应用程序但代码被执行到位时。

于 2009-06-25T11:25:49.583 回答
2

我的经验

我和两者都共事过,可能每个专业都有大约十年的时间。

有趣的是,我花更多的时间试图让静态类型语言理解我想要做什么(可能是几周 - 可能总共几个月),而不是我花在修复由动态类型错误引起的错误上(可能一年一两个小时? )。

学习

人们已经非常努力地获得证据表明其中一个或另一个在程序员生产力方面更好,但我读过的最新评论说没有有力的证据证明这两者。

极权主义

静态类型分析在某些情况下很有用。我认为它不应该天生就融入你的语言。它应该是您的交互式计算环境中的一个工具,以及您的测试、REPL、重构、文档、文字编码等。

静态类型系统可以让你思考有用的东西。在像 Haskell 这样带有类型类和 Monads 的语言中尤其如此(我承认我仍然没有真正理解)。这是一件好事,但我觉得相信它总是一件好事是极权主义的。你应该在适当的时候考虑一​​下。一种语言不应该让你从一开始就思考它或意识到它。

限制性太强和限制性不够

非图灵完备的静态类型系统的表达能力有限。为什么要使用一种新的特殊领域特定语言将其融入语言中,只是为了讨论类型?现在,您的语言设置了您可以访问的准确表达水平。想要更多?您需要重新编写代码或更新语言。想要更少?你不走运——使用不同的语言。

相反,为什么不使用基础动态语言来描述类型和类型系统呢?作为图书馆。它更具表现力;更强大(如果需要);更灵活;并且意味着更小的基础语言。

样板

静态类型语言似乎鼓励样板或代码生成。我不确定这是否是固有的。也许一个足够强大的宏观系统会克服它。我正在将 Swift 中用于测试的模拟状态与目标 c 中的状态进行比较。

单片

静态类型语言似乎鼓励单体应用程序——这是我无法支持的观点和观察,但它似乎成立……它们或它们附带的工具似乎鼓励单体应用程序和思考。

相反,在交互式计算环境中,您无需构建新应用程序,而是扩展系统以使其执行更多操作。我所知道的系统(Lisp 机器、Smalltalk 和 Unix——它们的工具在它们之间有一个动态类型接口)使用动态类型将部件组装在一起。

我们应该为整体构建微小的扩展,而不是着手构建新的整体应用程序,因此这种单一趋势,如果存在的话,是有害的。

速度

最快的动态跟踪 JIT 编译器生成快速代码,它们仍然是一项相当年轻的技术。不过——你也可以使用静态类型语言来做到这一点。

长期

我怀疑从长远来看,我们最终会得到支持强大静态分析的环境,您可以在其中声明类型和协议,系统将帮助您查看它们是否满意,或者帮助您显示隐含的类型。但你不需要这样做。

于 2016-09-07T20:50:48.337 回答
1

我也喜欢静态类型。但是当我编写 Python 时,我发现我并没有那么想念它,(只要我使用的类有很好的文档记录——而且我认为没有任何语言特性可以让我们免于糟糕的文档) . 在编写 C++ 时,我也不会错过 Python 的大部分动态特性(我想念的是 lambdas:即使语法很糟糕,也要使用 C++0x。还有列表推导式)。

对于错误检测,大多数“传递了错误的类型”和“调用了错误的方法”错误并不微妙,因此主要区别在于异常替换了编译器错误。您必须确保实际执行每个代码路径和所有重要的数据路径,但当然,对于严肃的项目,无论如何您都会这样做。我怀疑很难测试可以分配给给定变量的所有类。主要问题是习惯 C++ 的人已经学会依赖编译器,并且不努力避免编译器会捕获的大类错误。在 Python 中,您可以选择在编写代码时考虑它,或者等到测试运行后才知道它。同样,“的C++“自动重构”操作

因此,您必须确保您正在运行正确的测试子集,因为大型 Python 应用程序的完整单元测试运行将花费比当前 C++ 代码/编译/代码/的“编译”阶段可接受的时间更长的时间。编译/编码/编译/测试循环。但这与不想在 C++ 中重建所有内容完全相同。

当您的代码实际上难以运行时(例如使用嵌入式设备,或者特别是您无法在本地重现的怪异服务器环境),静态类型会获胜,因为您在弄乱串行电缆和同步。但这就是为什么无论你用什么语言编写都需要一个模拟器,以及为什么对于严肃的服务器代码,如果开发人员的机器无法模拟生产,你有一个适当的测试环境。

另外,值得记住的是,许多 C++ 编译器错误和警告实际上与您的设计无关,它们与编写看起来正确但行为完全错误的代码的方式有很多不同的事实有关。Python 程序员不需要警告他们不小心插入了一个三元组,或者对一个指针进行类型双关,因为他们没有精神病预处理器,也没有基于严格别名的优化。

于 2009-06-25T14:02:20.937 回答
0

考虑您有一个采用单个参数的子例程的情况:

sub calculate( Int $x ){ ... }

现在您的需求发生了变化,您必须处理多个参数:

multi sub calculate( Int $x ){ ... }
multi sub calculate( Int @x ){
  my @ret;
  for @x -> $x {
    push @ret, calculate( $x );
  }
  return @ret;
}

请注意,不同版本之间几乎没有变化。

现在,如果您发现您确实应该使用浮点数怎么办:

multi sub calculate( Num $x ){ ... }
multi sub calculate( Num @x ){
  my @ret;
  for @x -> $x {
    push @ret, calculate( $x );
  }
  return @ret;
}

这是一个比以前更小的更改,请注意,任何调用这些子例程的代码都将继续工作而无需进行任何更改。

这些例子写在Perl6

于 2009-06-25T15:43:07.303 回答
-1

我知道已经有一段时间了,但接受的答案列出了不限于动态类型语言的属性。例如,#4(更少的代码)也适用于 Scala(如果我没记错的话)。Groovy 绝对是这样(它建立在 Java 之上,所以从技术上讲,groovy 既是静态的又是动态的)。我唯一同意的是#7(韧性)

来自维基百科,

动态编程语言是一种......高级编程语言,它在运行时执行静态编程语言在编译期间执行的许多常见编程行为。这些行为可能包括扩展程序、添加新代码、扩展对象和定义或修改类型系统。动态程序员也可能包括动态类型。

根据我的经验,动态语言的优点是更少的代码/更高效的代码和更好的“最佳”实践(如强大的测试文化)......不是特定于动态语言的东西。

谈到测试文化,某些动态语言爱好者(尤其是 Ruby)声称他们编写的所有测试(测试感染)也允许他们轻松地重构应用程序。我倾向于不相信这种说法——写得不好的测试(非常、非常容易编写)往往会成为维护的噩梦。

总结:动态语言倾向于快速交付产品,应用程序可能容易维护也可能不容易维护,但对于高性能应用程序来说是可怕的(静态编译的应用程序更快)

于 2014-12-30T21:14:14.287 回答