最小化动态编程语言的缺点

e05a261a92fcf6c30ee4c851ed82f0f7.gif

本文介绍了动态语言的优缺点,倡导大家在享受动态语言的自由度时,也要尽可能地像静态语言那样思考,遵循一些规范和原则,避免一些隐患和错误。

原文链接:https://stackoverflow.blog/2023/01/19/adding-structure-to-dynamic-languages/

未经允许,禁止转载!

作者 | Daniel Orner      译者 | 明明如月

责编 | 夏萌

出品 | CSDN(ID:CSDNnews)

过去很长一段时间内,大多数软件开发依赖的都是静态类型和编译型语言,如 C、C++ 以及 Java。当动态语言开始崭露头角时,最初它们常常被贬低为“玩具”语言,而 JavaScript 就是其中之一。然而,随着时间的推移,解释型动态编程语言的优势开始得到认同。

现今,尤其在网络应用程序领域,使用动态语言的频率几乎与使用静态语言相当。JavaScript 和 Python 常年稳居常年最受欢迎语言前五之列,同时其他如 PHP 和 Ruby 等语言也始终占据一席之地。

动态编程语言带来了多项优势:

  • 它们是解释型的而非编译型的,无需在代码执行时额外的编译步骤和等待时间。

  • 代码一般更为简洁,因为不需要花费大量时间在定义和转换类型上。

  • 它们允许创建 领域特定语言 (DSLs),可以更自然地定义应用程序路由或配置。

  • 通常可以在运行时动态修改或“猴子补丁”(即“动态打补丁”),方便地为第三方库的对象添加新功能。

  • 可以容易地实现混合类型的集合,如数组和字典,这在静态类型语言中通常难以实现。

  • 类型转换通常更为简便——无需为不同的输入参数类型写多份函数,可以设计一个函数,接受任何类型的参数并进行必要的类型转换。

  • 元编程允许你轻松调整第三方代码,避免了漫长的分支、拉取请求和合并流程,这个过程可能会耗费数月甚至数年,取决于项目的规模。

你们中的细心人可能已经发现,这个列表中的每一项都既可以被视为优点,也可以作为缺点。让我们一一分析:

  • 解释器无法像编译器那样全面地捕获问题。

  • 不够精确的类型定义可能引发更多错误。

  • DSL(领域特定语言)可能引入混乱,增加你在理解应用和语言方面的心智负担。

  • 如果任何人都能修改一个类型,他们可能会滥用本应只在内部使用的代码。

  • 混合类型的集合的使用通常既不正确又混乱。

  • 一个函数应用于多个类型可能导致混乱。

  • 对第三方类进行动态打补丁可能导致代码过时和升级难。

随着动态语言越来越受欢迎,业界对如何解决这些问题进行了热议。我对动态语言的感知也在不断变化,最初对它们所带来的自由感到激动,但后来开始意识到其中潜在的问题。

我现在主要使用 Ruby,可能是最“动态”的流行动态语言之一。然而,即使在使用 Ruby 的过程中,我也发现了一套实践,我认为它们可以帮助缓解动态编程的一些缺点。

78a5ff28869202912a2406e17e3dcc97.png

充分发挥类型提示的作用

过去十年间,主流的动态编程语言都陆续引入了类型提示功能。其中最著名、使用最广泛的无疑是 TypeScript,它是 JavaScript 的超集,需要一个编译器将其代码转化为标准的 JavaScript。Python 和 PHP 在语言层面都引入了类型提示,即使是 Ruby 也试图进行了 RBS 和 Sorbet 项目(虽然这两个项目似乎并未得到广泛的支持)。

类型提示是使动态语言走向静态化的最直接路径。实际上,这让你能够享受最好的两个世界:编写动态代码的同时,需要更加谨慎地确定你期待获取和使用的数据类型。

有趣的是,优秀的类型提示系统往往比静态语言的类型系统更为复杂。以 Java 为例,你无法声明一个对象属性可以是整数 或者 字符串——但在 TypeScript 中,通过联合类型,这个操作就变得非常简单:

printLabel = (label: string|number) => string {console.log(`Please fill out ${label}`);
}

这是因为类型提示系统意图并不是要把动态语言变成静态语言,而是要让你用一种机器可以理解和执行的方式来记录你对类型的期望。这样,你可以在编译时或运行时发现并修复类型错误,提高代码的健壮性和可读性。

最后,需要指出的是,大部分类型提示系统都允许进行 渐进式类型化。在这种模式下,你可以逐个文件开启类型提示,而无需一次性转换整个代码库。你可以借助这个特性,逐步将你的代码迁移到你的类型系统中,而无需在一个项目中一次性完成所有转换。

651db68e211e8d733834bff7cccb5217.png

处理非结构化数据:字典的运用

在动态编程语言中,字典或哈希表的使用是一种常见的实践,它们被用于处理非结构化数据。当需要从函数返回数据或向函数传递选项时,字典通常是首选的数据结构:

def configure(options={})self.logger = options[:logger]self.host_name = options[:host_name]
end

或:

return { count: 5, average: 10}

由于字典可以用来存储任意的键值对,所以它们无法提供类型提示。使用字典来表达已知的数据会使得类型推导和错误查找变得困难。在第一个例子中,如果你不慎将 :loger 作为 :logger 的输入,错误将无法被抛出,而仅仅是把 logger 设为 null,这并不是你所期望的,因为这是一个调用代码中的错误,而不是数据中的错误。

对于支持接口或鸭子类型(动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。)的类型提示系统,如 TypeScript,你可以继续使用字典:

interface CountResult {count: number;average: number;
}
getCount : CountResult = () => { return { count: 5, average: 10} };

对于不支持该特性的编程语言,你可以选择使用结构体或数据类,这些类型简单且通常是不可变的,包含了一组字段:

ConfigurationOptions = Struct.new(:logger, :host_name)def configure(options=ConfigurationOptions.new)self.logger = options.loggerself.host_name = options.host_name
end

从索引表示法转为点表示法这一简单步骤引入了一种类型安全性级别。这样的转变可以增强代码的健壮性,即使在完全没有类型提示系统的情况下也可以实现。如果某个方法不存在,代码将会抛出一个错误,让你可以立即发现问题。

即使你没有使用类型提示系统,你也可以注释你的字段。许多 IDE 都能从这些注释中获取信息,进而实现自动补全。虽然这可能使定义变得更冗长,但是却更易于推理:

class ConfigurationOptions# @return [Logger]attr_accessor :logger# @return [String]attr_accessor :host_name

b066ca9c8a9f91ef75589af33466e117.png

明确地表达你的代码的意图和逻辑

静态语言强调明确性,有时候甚至给人过于严格的印象。你想知道一段代码在做什么?那就简单地用 ctrl+点击进入,然后沿着调用栈向下追溯。这里没有任何难以理解的“神秘”操作。

对于动态语言以及像 C 这样允许定义宏的语言,这种追踪过程就变得更加困难。动态语言经常无法通过“grep 测试” —— 我在阅读代码时,如果看到一个方法或特定的语法,我能否通过搜索整个代码库或者依赖来找到它的定义?如果找不到,那可能就意味着存在过多的元编程。

实际上,应该进行元编程或反射的只有框架本身。设计自己的内部框架是完全没有问题的,特别是它针对解决你的团队或公司特有的常见问题,那就是框架的最佳应用。但是,你不能假设他人理解你提供给他们的每一个细节影响,除非这些影响是明确地声明的。

如何判断自己的代码是否足够明确呢?当面对一个问题,你或许会有这样的想法,“我可以简洁地解决这个问题,或者我可以花费时间将所有的细节一一呈现出来,尽管这会花费我更多的时间。” 在这种情况下,你应该选择花费更多的时间来呈现细节。

让我们看个例子。在我们的 Rails 应用中,有许多与传单相关的工作类型。定义这些关联的一种方式需要遍历这些工作类型:

JOB_TYPES = [:process_image, :upload_image, :process_tagging]
JOB_TYPES.each do |type|has_many "#{type}_jobs"
end

这段代码能够正常工作,但如果我在代码库的某个地方看到 flyer.process_image_jobs,我应该如何知道它来自何处呢?

更直接的方式虽然工作量稍大,但是却更清晰:

has_many :process_image_jobs
has_many :upload_image_jobs
has_many :process_tagging_jobs

总的来说,你应该遵循最少惊讶原则。具体来说就是:

  • 不要对你无权修改的对象,尤其是基础类型,进行动态打补丁或更改行为。

  • 不要通过编程的方式创建方法;确保你可以在你的代码库。

  • 尽量不要使用隐式状态(例如在类的作用域之外使用 JavaScript 的 this 关键字)。明确指出正在操作的是什么对象。

  • 避免隐式地自动关联代码(例如,通过读取特定的文件结构,StimulusJS 就是这样做的,这是我对其它一些优秀的包的不满之处)。

当然,有些情况下我们可能需要一些“花哨”的操作,但是你需要明智地选择使用的场景!

cd5b3cd90eec427284babea60a9009c9.png

要经得住诱惑

动态语言给你很多自由,但也有很多风险,就像有句话说的,给你无限的空间让你自取灭亡。你应该享受自由,但也要尽可能地像静态语言那样思考,遵循一些规范和原则,避免一些隐患和错误。

对于如何更好地使用动态语言,你有何经验?欢迎在评论区交流经验。

推荐阅读:

▶微信:有零钱的微信号不会被系统注销;拼多多旗下 Temu 在美起诉 Shein;Rust 1.71.0 发布|极客头条

▶“仅 1 行代码,我们改了 6 天!”

▶我是如何使用ChatGPT和CoPilot作为编码助手的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17387.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

盘点微服务架构下的诸多身份验证方式

身份认证是授予用户访问系统并授予使用系统的必要权限的过程。而提供了这一功能的服务,就是身份认证服务。 作者 | 罗泽轩, 赵士瑞 责编 |梦依丹 出品 | CSDN(ID:CSDNnews) 在传统的单体软件应用程序中&#xff0…

第5章信息系统工程

信息系统工程是用系统工程的原理、方法来指导信息系统建设与管理的一门工程技术学科,它是信息科学、管理科学、系统科学、计算机科学与通信技术相结合的综合性、交叉性、具有独特风格的应用学科。当前信息系统工程的主要任务是研究信息处理过程内在的规律&#xff0…

离职两年后,程序员遭前东家索赔:Bug是你写的

👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇 整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 问:身为一名程序员,你能确保至今写的代码中没有一个 Bug 吗&…

ChatGPT 过时了,Auto-GPT才是未来

Auto-GPT概述 AutoGPT 是一项卓越的 AI 技术,一个实验性开源应用程序,它通过 API 利用 GPT-4 和 GPT-3.5 通过迭代自己的提示并在每次迭代中构建它们来创建成熟的项目。Auto-GPT是 GPT-4 完全自主运行并突破 AI 可能性界限的首批示例之一。它可以读写文件…

【PPT】《挑战用chatgpt完成流水线操作的ppt,再也不用担心每周肝组会报告ppt了#人工智能 #chatgpt应用领域 快学起来!!!》- 知识点目录

《挑战用chatgpt完成流水线操作的ppt,再也不用担心每周肝组会报告ppt了#人工智能 #chatgpt应用领域 快学起来!!!》 1. PPT文字模板说明(Prompt) 我的名字叫做【haozi】,帮我制作一篇内容为《如何做好一名…

如何通过ChatGPT快速生成PPT?ChatGPT搭配闪击PPT生成PPT,你只需要输入一个标题

了解闪击PPT的【文字转PPT】功能 闪击PPT有一个文本转PPT功能,这也是今天的主角 我的名字叫做芝士不吃,帮我制作一篇内容为《秦朝为什么会灭亡》PPT,要求如下: 第一、一定要使用中文。 第二、页面形式有3种,封面、目…

【3分钟高效制作PPT】ChatGPT搭配闪击PPT生成PPT,你只需要输入一个标题

Hello,大家好,我是你的好伙伴AI博士 今天我来分享一下,怎么用ChatGPT配合闪击PPT,只输入一个标题,怎么生成一份高颜值的PPT。 第一步:了解闪击PPT的【文字转PPT】功能 闪击PPT有一个文本转PPT功能&#x…

如何使用ChatGPT的API(一)大语言模型如何工作

这篇文章介绍大语言模型的一些概念,包括它是如何工作的,什么是Token等等。 大语言模型如何工作 我们从一个示例开始说起。 当我们写一个提示“我喜欢吃”,然后要求一个大型语言模型根据这个提示填写后面可能的内容。它可能会说&#xff0c…

IP-Guard能否限制PC端微信登录?

能否限制PC端微信登录? 不能限制微信登录,但可以通过应用程序控制策略,禁止微信程序启动。 在控制台-【策略】-【应用程序】,添加以下策略: 动作:禁止 应用程序:wechat.exe 可以实现禁止微信启…

七年老程序员的三四月总结:三十岁、准备婚礼、三次分享

你好,我是 shixin,一名工作七年的安卓开发。 每两个月我会做一次总结,记下这段时间里有意义的事和值得反复看的内容,为的是留一些回忆、评估自己的行为、沉淀有价值的信息。 一转眼 2023 年过去了三分之一,这两个月经历…

一张图就是一个故事,用 SceneXplain 讲个好故事

精准的图像描述不仅可以让人们更容易理解图像背后的故事和信息,还可以让图像更易于被检索和识别。然而,对于那些复杂的图像来说,写出既准确又详细的描述实在是件非常困难的事情。 图像描述算法的演变 所谓 Image Caption(图像描述)任务&#…

NLP 中语言表示 (向量化) 的基本原理和历史演变综述

目录 1 前言2 语言表示2.1 离散表示2.1.1 独热编码2.1.2 词袋模型2.1.3 TF-IDF 模型2.1.4 N-gram 模型2.1.5 基于聚类的表示 2.2 连续表示2.2.1 分布式表示2.2.2 Word Embedding2.2.2.1 Word2Vec2.2.2.2 GloVe2.2.2.3 FastText 2.2.3 基础神经网络模型2.2.3.1 神经词袋模型2.2.…

七年程序员的三四月总结:三十岁、准备婚礼、三次分享

你好,我是 shixin,一名工作七年的安卓开发。 每两个月我会做一次总结,记下这段时间里有意义的事和值得反复看的内容,为的是留一些回忆、评估自己的行为、沉淀有价值的信息。 一转眼 2023 年过去了三分之一,这两个月经…

SceneXplain:让 ChatGPT 开启视觉视角

来自:Jina AI 精准的图像描述不仅可以让人们更容易理解图像背后的故事和信息,还可以让图像更易于被检索和识别。然而,对于那些复杂的图像来说,写出既准确又详细的描述实在是件非常困难的事情。 图像描述算法的演变 所谓 Image Cap…

如何选择国际通知短信服务商?

企业在开拓海外市场的过程中,往往需要用到国际短信接口,帮助企业实现用户注册、订单通知、快递通知、营销推广等功能。 那么如何选择国际短信服务商?接下来互亿无线小编整理了相关信息,为大家做个详细介绍: 一、国际…

国际短信发送接口

接口地址 http://intlapi.1cloudsp.com/intl/api/v2/send 用户通过HTTP(或HTTPS)的POST或GET方式提交短信发送请求。编码采用 UTF-8 编码。

ChatGPT还有什么不会?招行信用卡用它写出金融业首篇AIGC

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 内容来自机器之心 比尔盖茨:它(ChatGPT)让我们窥见了未来。 2023 开年至今,AI 赛道最火的莫过于 OpenAI 的 ChatGPT。 推出不到两个月的时间,月活用户…

数字人是AI的UI,ChatGPT助推数字人升级为数智人

以ChatGPT为代表的AIGC智能工具与数字人结合后,将彻底改变人类与计算机的交互方式,使虚拟世界中的数字人对话更真实、更贴近人类,具有记忆和实现连续对话的能力;通过大量人工智能模型训练后数字人将提供更准确、更有价值的信息&am…

ChatGPT-4回答电子电路相关问题,感觉它有思想,有灵魂,一起看看聊天记录

前几天发了一篇文章,讲了我们平常摸电脑或者其它电器设备的时候,会有酥酥麻麻的感觉,这个并不是静电,而是Y电容通过金属壳泄放高频扰动,我们手摸金属壳的时候,就给Y电容提供了一个泄放回路,所以…

虚拟数字人遇上ChatGPT,好看的皮囊和有趣的灵魂?

都说好看的皮囊千篇一律,有趣的灵魂万里挑一,博雅仔不禁好奇,到底有没有皮囊又好看,灵魂又有趣的人呢?二者能否得兼?答案是当然可以啊。 虽然在现实生活中,遇到这样的人需要静待缘分的安排&…