【问题标题】:How does Python's lack of static typing affect maintainability and extensibility in larger projects? [closed]Python 缺乏静态类型如何影响大型项目的可维护性和可扩展性? [关闭]
【发布时间】:2010-09-08 20:54:58
【问题描述】:

在阅读this very informative (albeit somewhat argumentative) question 之后,我想知道您使用 Python 编写大型项目的经验。随着项目变大,事情是否变得难以管理?这种担忧是让我对 Java 依恋的一件事。因此,我对大型项目的 Java 和 Python 的可维护性和可扩展性的知情比较特别感兴趣。

【问题讨论】:

  • 这种问题总是让我感到困惑。打字系统如何影响可维护性?有两种可能性 - 要么您可以信任检查您的源库的人,要么您不能。在前一种情况下,无论您使用什么语言、系统、框架等,您都不会遇到任何问题。如果您不能信任他们,那么无论您使用什么语言、系统、框架等,您都没有希望。我当然不明白打字系统这么小的一块蛋糕对项目的整体可维护性有多大影响。
  • 这看起来很适合 CW。
  • 我不是 Python 和 Java 方面的专家,对我来说可维护性主要取决于设计。
  • @THEn:祝你好运尝试维护一些 Visual Basic 或 Perl 或 shell 脚本......我想这就是你说大部分的原因。
  • @Longpoke:你抓住了我。 :) 这实际上就是我所做的。更糟糕的是我必须添加 VBA... :)

标签: java python project-management static-typing


【解决方案1】:

我从事一个用 Python 完成的大型商业产品。我粗略估计了 5000 个文件 x 500 行。这大约是 250 万行 Python。请注意,这个项目的复杂性可能相当于其他语言的 1000 万多行代码。我没有听到任何一位工程师/架构师/经理抱怨 Python 代码不可维护。从我从我们的错误跟踪器中看到的情况来看,我没有看到任何可以通过静态类型检查避免的系统性问题。事实上,很少有错误使用对象类型产生的错误。

我认为这是一门非常好的学术主题,可以实证研究为什么基于静态类的语言似乎不像人们想象的那么重要。

关于可扩展性。我们刚刚在我们的产品中的数据库 1 之上添加了一个数据库 2,它们都是非 SQL。没有与类型检查相关的问题。首先,我们设计了一个足够灵活的 API,可以预测不同的底层实现。我认为动态语言在这方面是一种帮助而不是障碍。当我们继续测试和修复错误时,我们正在研究使用任何语言的人都必须面对的那种错误。例如,内存使用问题、一致性和参照完整性问题、错误处理问题。我认为静态类型检查对这些挑战没有多大帮助。另一方面,我们从动态语言中受益匪浅,因为我们能够在运行过程中或在简单的补丁之后注入代码。而且我们能够测试我们的假设并快速展示我们的修复方法。

可以肯定地说,我们 100 多名工程师中的大多数人都乐于使用 Python 并富有成效。我们可能无法想象使用静态类型语言在相同的时间内以相同的质量构建相同的产品。

【讨论】:

    【解决方案2】:

    根据我的经验,静态类型语言可能难以维护。例如,假设您有一个实用函数,它接受自定义类作为参数。如果以后你采用新的命名约定,那么这个类的名称将不得不改变,那么你所有的实用函数也必须改变。在像 python 这样的语言中,只要类实现相同的方法就没有关系。

    就我个人而言,我鄙视一种妨碍我的语言。表达想法的速度就是价值,这是 Python 相对于 Java 的优势。

    【讨论】:

    • 我正在研究目前人类历史上所创造的最糟糕的 Java 代码库。它充斥着不必要的全局状态、什么都不做的语句(包括什么都不做的匿名类实例化)、不必要的自定义类加载器、随机垃圾乱扔文件系统、竞争条件、谁知道还有什么,但它仍然相对容易使用... 为什么?因为它是一门简单的语言,虽然 Python 也... 静态类型的全部目的是让一切静态;即:易于分析
    • 您的命名约定示例没有任何意义:1. 在 Python 和 Java 中,您从不将类的名称传递给函数,除非您要求麻烦,或者有一个非常特定的用例。 2. 与无反射的 Java 代码相反,由于动态类型,Python 代码不能被确定性地重构为使用新的方法名称。 3. Pythonic 代码遵循 PEP8 命名约定,大多数 Java 遵循约定,就像这样,当你已经不得不混合使用 De facto 约定的 De facto 库时,为什么还要使用自己的约定?
    • 另外,在你说静态类型“妨碍你”之前,你可能想试试 Haskell……也许你的印象来自于 Java 实现它的愚蠢(但简单而合理)的方式。
    • @Longpoke:他关于命名的观点是你需要函数参数中的类型名。如果您有一个函数doStuff(CustomClass c) 并且您决定需要重命名CustomClass,那么您只需冲洗所有将其作为参数的方法。尽管这是一个非常小的问题,因为大多数 IDE 都允许您重构它。而 python 并没有摆脱这一点,因为你仍然需要实例化对象,而且这些调用也必须改变
    • @Falmarri:哎呀,我看错了,我以为他的意思是一个接受类名称的函数,而不仅仅是一个。同意。
    【解决方案3】:

    没有良好测试覆盖率的 python 中的大型代码库可能是一个问题。但这只是图像的一部分。一切都取决于人和合适的方法来完成这项工作。

    没有

    • 源代码管理
    • 错误跟踪
    • 单元测试
    • 坚定的团队

    任何一种语言你都可能失败。

    【讨论】:

    • 我的经验是,Python 代码库对新开发人员的宽容度较低,他们在原始开发人员已经离开后负责维护代码。我遇到的特定代码库没有任何单元测试,这意味着所有错误都只能在集成测试中发现,或者(经常发生)在现场。静态类型语言可以捕捉到你可能犯的一些更愚蠢的错误,但它肯定不是灵丹妙药。
    • 静态类型语言为您提供更详细的方法签名。如果您正在处理一个文档记录不佳且不是非常自我记录的代码库,那么它可能会有很大的帮助。不幸的是,良好的动态类型语言(我在这里想到的是 Python)使原型设计几乎太容易了——您可以让程序启动并运行,并且非常接近于完成,如此之快以至于正确命名和记录似乎是一件难以克服的苦差事。在静态类型失去其在可维护性方面的大部分优势之前,开发人员必须了解选择好名称的重要性。
    • 对于未记录的 Python 代码,您可以使用 sys.settrace 或为 sys.modules 上的每个函数添加日志装饰器来记录参数和返回值,然后添加编辑器“插件”以便查看函数定义上方的示例调用日志。另一个想法是在应用程序仍在运行时对其进行编辑,即:在函数调用中放置一个断点。不过,两者都需要某种代码覆盖率。
    【解决方案4】:

    尝试在具有大量 IoC 或其他设计模式的大型动态类型框架中追溯明显格式错误的对象的来源,在这些框架中无法直接在堆栈中向上跟踪对象。

    现在尝试使用静态类型语言来执行此操作。

    除非对象的类型记录在使用站点附近(例如,通过类型注释,a-la Python 的类型安全库)或堆栈上的某个位置,否则几乎不可能推断出它的来源。我根据经验发言,曾尝试调试 BuildBot 框架的某些部分。它涉及通过框架搜索大量原始文本,甚至使用 PyDev、Komodo 和 Wingware 等花哨的 IDE。

    我不怀疑对动态语言施加一些类型限制是可能的,但缺乏任何标准化似乎是任何尝试调试大型现有框架的一部分的人的障碍。

    编辑:自 2014 年以来,Guido 添加了 PEP484、MyPy 和打字模块。这让我在维护大型项目方面的经验变得非常好。

    【讨论】:

    • 您可以做的另一件事是为对象添加有关其历史记录(它们来自何处)的注释。
    【解决方案5】:

    我记得 IntelliJ IDEA 创新前后的日子。存在巨大差异。以前,静态类型只用于编译,开发基本上将源代码视为文本文件。之后,源代码是结构化信息,由于静态类型,许多开发任务必须更容易。

    但是,过去的日子并不像生活在地狱中。我们照原样做,做任何必要的事情,使用迄今为止可用的工具,构建系统,满意。没有太多不愉快的回忆。这可能就是动态类型程序员现在的感受。没那么糟糕。

    当然,我永远不会回到过去。如果我被禁止使用这样的 IDE,我想我会让我们一起编程。

    【讨论】:

      【解决方案6】:

      根据我的经验,可维护性取决于低耦合、良好的文档、良好的开发过程和出色的测试。静态类型与这些几乎没有任何关系。

      Java 将在编译时捕获的错误只是可能发生的错误的一小部分。它们也几乎总是最容易通过测试检测到的;如果您正在测试您的代码是否产生正确的答案,那么您绝对不会错过对错误类的对象调用方法!在这方面,您可能会争辩说 Python 在确保质量方面实际上更好;通过强制您至少测试一下以确保您的代码没有简单的拼写错误,它可以确保您实际上进行至少测试一下。

      事实上,Java 甚至不是一个很好的语言示例,它具有强大的静态检查以捕获大量错误。尝试在 Haskell 或 Mercury 中编程以了解我的意思,或者更好地尝试在 Scala 中编程并与 Java 库交互;当您将使用 Scala 库的普通惯用 Scala 代码与必须处理 Java 库的代码进行比较时,编译器能够为您保证多少“正确性”的差异是惊人的(我实际上已经这样做了,因为我编写了一个位在 Android 上的 Scala 中)。

      尽管 Java 的静态错误检测与 Scala 等语言相比存在缺陷,但您在大型代码库中编写良好的可维护代码的能力由许多开发人员长期研究,这取决于 完全相同的技术 尽管 Python 的静态错误检测与 Java 相比存在缺陷,但 Python 程序员通常在他们的大型代码库中做同样的事情。

      【讨论】:

        【解决方案7】:

        我在很多项目中都使用过 Python,从几百行到几千行不等。动态类型非常节省时间,它使像多态这样的 OO 概念更易于使用。类型系统不会使项目无法维护。如果您无法想象,请尝试用 Python 编写一些东西,看看效果如何。

        【讨论】:

        • 正在讨论的问题不是编写一个新程序 ex nihilo - 是的,这在 Python 这样的动态类型语言中要容易得多;问题在于可维护性,尤其是让你的头脑围绕着别人的代码。因为动态类型语言的方法签名本身并不携带任何类型信息,所以您失去了内置的自文档机制。
        • @outisnihil 我的观点不仅是用 Python 编写新代码很容易,而且根据我的经验,Python 代码非常易于维护。我想我没有明确说出来,但并不是所有我使用 Python 的项目都是单独的。这更像是一个证明而不是一个深刻的答案,但我认为它可能会增加对话的价值。
        • 至少对我来说,Python 使理解每个方法中的算法更容易,但是(像所有动态类型语言一样)理解如何使用现有方法稍微困难一些(没有文档)。
        【解决方案8】:

        我在一家使用 python 作为主要语言的大数据初创公司工作。我的项目大约是 30k 行 python。根据我的经验,如果您的团队采用良好的编程实践,例如 fox 示例、添加类型提示和广泛的单元测试,它可能不会对可维护性产生太大影响。因为如果有类型提示,Pycharm 可以自动检测类型某些类型错误。

        真正的问题是: 1.性能,这个可能和可维护性无关,但是是个问题。 2. 并非您处理的每个 python 代码库都写得很好。因为python很容易学习和编码。一些没有受过基本 CS 培训的人会开发一个无法维护的 python 项目。我工作了一个 python 项目,它有很多文件,每个文件都有几千行,没有类型提示。那家伙不知道OOP。他基本上以编写 C 的方式编写 python。他只是利用了一些 python 语言特性,但完全是命令式编程。编写好的 Python 项目确实依赖于训练有素的工程师。如果你不能聘请足够好的工程师,最好依靠工具本身。 3.在python大数据公司,产品经理和一些非技术人员不关心数据类型的一致性。那些人会设计一个不是类型安全的数据产品。例如,在 Json 中,如果一个字段通常是 ​​str,但是当它为空时,有些人会将其设为 null。这将在运行时失败。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-08-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多