当前位置: 首页 > news >正文

优秀的程序员思考数据结构

原文地址:https://read.engineerscodex.com/p/good-programmers-worry-about-data


我最近在这篇很棒的 Stack Overflow 文章中看到了 Linus Torvalds(Linux 和 Git 的创建者)的一句话。(这篇文章回顾了那篇文章中的许多引述。

它简洁地描述了我最近一直在研究的一个问题:

“糟糕的程序员担心代码。优秀的程序员思考数据结构及其关系。

就在上述引述之前,Linus 说:

Git 基于稳定且文档齐全的数据结构,其本身的设计实际上非常简单。
事实上,我非常支持围绕数据设计代码,而不是相反,我认为这是 git 相当成功的原因之一

事实上,我会声称,一个坏程序员和一个好程序员之间的区别在于他认为代码更重要,还是数据结构更重要。

良好的数据结构使代码更易于设计和维护。
它使软件更可靠,系统更易于理解,代码更具可读性。
在设计任何软件时,应用程序逻辑通常遵循数据模型的设计。
将数据模型视为事后的想法会导致更多的工作。
反之亦然 —— 拥有经过深思熟虑的数据模型可以更轻松地在复杂系统上进行迁移和构建。

当我读到这句话时,我实际上能回忆起过去无数的例子。
我曾经参与过一个项目,我们花了相当长的时间优化复杂的算法,结果才意识到,通过重组我们的数据,我们可以消除所有的问题。
我们将 500 行代码的函数替换为 50 行代码和精心设计的数据结构。
新代码不仅速度更快,而且更容易理解和维护。(当然,问题也转移到了“堆栈下游”,即大部分工作都变成了重组已有的数据)

另一个相关的引述是在 “The Art of Unix Programming” 中:

表示法则(Rule of Representation):将知识融入数据中,这样程序逻辑就可以既 “愚蠢” 又健壮。

即使是最简单的过程逻辑,人类也很难验证其正确性,但及其复杂的数据结构相当容易建模和追根溯源。
要了解这一点,请将 50 个节点的树的图表与 50 行程序的流程图的表达力和解释力进行比较。
或者,将表示转换表的数组初始值设定项与等效的 switch 语句进行比较。其理解表达力和清晰度的差异是巨大的。

/* 将数字转换为英文单词 */// 使用数据结构建模复杂度
const char* number_to_word(int num) {const char* words[] = {"one", "two", "three", "four", "five"};if(num >= 1 && num <= 5) {return words[num - 1]; // 减1是因为数组索引从0开始} else {return "invalid number"; // 超出范围的数字}
}// 使用代码逻辑建模复杂度,当值相当多时(例如 100 个),这种写法将变得相当复杂
// 这种写法经常还会诱导我们在特定的 case 条件中加入特定的处理逻辑,整个代码变得难以和维护
const char* number_to_word_switch(int num) {switch(num) {case 1: return "one";case 2: return "two";case 3: return "three";case 4: return "four";case 5: return "five";default: return "invalid number"; // 超出范围的数字}
}

数据比程序逻辑更容易处理。
因此,当您看到数据结构复杂性和代码复杂性之间的选择时,请选择前者。

更进一步:在改进设计时,您应该积极寻求将复杂性从代码转移到数据

这个观点并不是Unix社区首创的,但许多Unix代码都受到了它的影响。特别是C语言在处理指针上的强大能力,促使开发者从内核层面起,到更高编码层级,都采用了可以动态修改的引用结构。在这些结构中,简单的指针追踪常常承担起了在其他语言中需要通过更复杂的程序代码来实现的工作。

这里的实用建议是从数据入手。尽量通过对你的接口或数据库使用更严格的类型定义来减少代码的复杂性。额外花一些时间提前深入思考数据结构的设计。

这并不是说代码不重要。显然,一切都很重要 —— 但在深入研究与代码相关的细节之前,有一个强大的高级方法来了解数据的流动方式以及不同组件如何交互是非常有帮助的。

一些 “接口或数据库使用更严格的类型定义” 的例子

使用枚举代替魔法字符串:

通过枚举确保只有预定义的值被接受,这样可以避免无效值的出现,并在编译时就捕捉到错误。

   public enum Status {OPEN, IN_PROGRESS, CLOSED;}public void updateStatus(Status newStatus) {// 只接受Status枚举的值}

采用明确的数据结构而非泛型容器

使用明确的类或结构体来代替如 MapDictionary 等通用容器,可以提供更强的类型检查。

   public class User {private String name;private int age;// 使用构造函数和明确的字段类型public User(String name, int age) {this.name = name;this.age = age;}// 相应的getter和setter方法...}// 应该使用具体的类型public User getUserInfo(...)...// 而不是使用容器public Map<String, Object> getUserInfo(...)...

在数据库中使用严格的模式:

定义数据库模式时,使用严格的字段类型和约束条件,如非空、唯一性约束或外键约束。

   CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(100) NOT NULL,age INT NOT NULL CHECK (age > 0));

利用类型系统进行验证:

在编程中利用类型系统来强制数据的结构和预期的使用方式。

例如在弱类型语言 python 中使用 type hint 机制

使用类型转换和校验库:

使用类型转换和校验库如Joi或Yup等,来确保数据在运行时满足预定义的模式。

   const schema = Joi.object({name: Joi.string().required(),age: Joi.number().integer().min(0).required(),});// 使用schema来验证数据const { error, value } = schema.validate({ name: 'Alice', age: 25 });if (error) {throw new Error(error.details[0].message);}

相关文章:

优秀的程序员思考数据结构

原文地址&#xff1a;https://read.engineerscodex.com/p/good-programmers-worry-about-data 我最近在这篇很棒的 Stack Overflow 文章中看到了 Linus Torvalds&#xff08;Linux 和 Git 的创建者&#xff09;的一句话。&#xff08;这篇文章回顾了那篇文章中的许多引述。 它…...

「C/C++」C/C++标准库之#include<cstdlib>通用工具库

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…...

Oracle视频基础1.1.3练习

1.1.3 需求&#xff1a; 完整格式查看所有用户进程里的oracle后台进程 查看物理网卡&#xff0c;虚拟网卡的ip地址 ps -ef | grep oracle /sbin/ifconfig要以完整格式查看所有用户进程中的 Oracle 后台进程&#xff0c;并查看物理和虚拟网卡的 IP 地址&#xff0c;可以使用以下…...

python项目实战——多协程下载美女图片

协程 文章目录 协程协程的优劣势什么是IO密集型任务特点示例与 CPU 密集型任务的对比处理 I/O 密集型任务的方式总结 创建并使用协程asyncio模块 创建协程函数运行协程函数asyncio.run(main())aiohttp模块调用aiohttp模块步骤 aiofiles————协程异步函数遇到的问题一 await …...

基于.NET 8.0,C#中Microsoft.Office.Interop.Excel来操作office365的excel

开发环境&#xff1a; Visual Studio 2022 office365 项目模板&#xff1a;WPF应用程序 框架&#xff1a;.NET 8.0 依赖&#xff1a;Microsoft.Office.Interop.Excel 注意&#xff1a; 1.使用Microsoft.Office.Interop.Excel库时&#xff0c;服务器或电脑里面必须安装得…...

使用无线方式连接Android设备进行调试的两种方法

1.使用配对码配对设备方式 手机&#xff08;或者平板等安卓设备&#xff09;和电脑需连接在同一WiFi 下&#xff1b;保证 SDK 为最新版本&#xff08;adb --version ≥ 30.0.0&#xff09;&#xff1b; step1.手机启用开发者选项和无线调试模式&#xff08;会提示确认&#xff…...

Valgrind的使用

Valgrind 是一个强大的开源工具,用于检测程序中的内存错误、内存泄漏以及线程问题。它广泛应用于 C/C++ 等需要手动管理内存的编程语言中。以下内容将详细介绍 Valgrind 的安装、基本使用方法、常用命令及其输出结果的解析。 1. 什么是 Valgrind? Valgrind 是一个用于内存调…...

微信小程序瀑布流实现,瀑布流长度不均等解决方法

这是一开始实现的瀑布流&#xff0c;将数据分为奇数列和偶数列 <view class"content-left"><block wx:for"{{list}}" wx:key"list"><template isitem-data data{{...item}} wx:if"{{index % 2 0}}"></template&…...

Notepad++通过自定义语言实现日志按照不同级别高亮

借助Notepad的自定义语言可以实现日志的按照不同级别的高亮&#xff1b; 参考&#xff1a; https://blog.csdn.net/commshare/article/details/131208656 在此基础上做了一点修改效果如下&#xff1a; xml文件&#xff1a; <NotepadPlus><UserLang name"Ansibl…...

2024年四川省大学生程序设计竞赛 补题记录

文章目录 Problem A. 逆序对染色&#xff08;思维树状数组&#xff09;Problem B. 连接召唤&#xff08;贪心&#xff09;Problem E. L 型覆盖检查器&#xff08;模拟&#xff09;Problem F. 小球进洞&#xff1a;平面版&#xff08;几何&#xff09;Problem G. 函数查询Proble…...

17_事件的处理

目录 绑定事件与解绑事件优化事件的绑定和解绑方式处理不同事件类型的绑定处理同一事件类型多个事件处理函数事件冒泡与更新时机问题 绑定事件与解绑事件 既然要处理事件&#xff0c;那么首先面临的问题是如何在 vnode 中描述这个事件&#xff0c;在 vnode.props 中&#xff0…...

1FreeRTOS学习(队列、二值信号量、计数型信号量之间的相同点和不同点)

相同点&#xff1a; &#xff08;1&#xff09;传递区间 队列、二值信号量、计数型信号量均可用在任务与任务&#xff0c;任务与中断之间进行消息传递 &#xff08;2&#xff09; 传递方式 创建队列--发送队列--接受队列 创建二值信号量--发送二值信号量--接受二值信号量 创建计…...

数据库设计与范式及其应用

数据库设计是数据库管理系统&#xff08;DBMS&#xff09;中的核心环节&#xff0c;良好的数据库设计不仅可以提高数据存取的效率&#xff0c;还能增强数据的可维护性和一致性。范式&#xff08;Normalization&#xff09;是一种设计原则&#xff0c;用于减少数据冗余和提高数据…...

笔记-配置PyTorch(CUDA 12.2)

文章目录 前言一、安装 PyTorch&#xff08;CUDA 12.2&#xff09;1. 创建并激活 Conda 环境2. 安装 PyTorch&#xff08;CUDA 12.2&#xff09;3. 安装 torch_geometric 及依赖项4. 验证安装 总结 前言 一、安装 PyTorch&#xff08;CUDA 12.2&#xff09; 1. 创建并激活 Con…...

[C++]——红黑树(附源码)

目录 一、前言 二、正文 2.1 红黑树的概念 2.2 红黑树的性质 2.3红黑树节点的定义 2.4 红黑树的插入 2.4.1 情况一 2.4.2 情况二 ​编辑 2.4.3 情况三 2.5 红黑树的验证 三、全部代码 四、结语 一、前言 在上一篇博客中&#xff0c;为小伙伴们进行了AVL树的讲解&#…...

网络文件系统搭建

在CentOS7上搭建网络文件系统&#xff08;NFS&#xff09;&#xff0c;并让客户端进行挂载&#xff0c;具体步骤如下&#xff1a; 1. 服务器端操作 安装NFS服务器软件包&#xff1a; 执行以下命令安装NFS服务&#xff1a; sudo yum install nfs-utils -y 启动并启用NFS服务&…...

基于vue、VantUI、django的程序设计

首先构建vue项目&#xff0c;构建项目点这里 安装 npm install axios axios简介 Axios 是一个基于 promise 的 HTTP 库&#xff0c;用于发起请求和接收响应&#xff0c;实现异步操作 基本使用 axios对象 请求响应拦截 在utils文件夹里新建ajax.js 创建一个axios对象并…...

京准电钟解读:NTP网络对时服务器助力厂区改造方案

京准电钟解读&#xff1a;NTP网络对时服务器助力厂区改造方案 京准电钟解读&#xff1a;NTP网络对时服务器助力厂区改造方案 1&#xff09;系统概述 时钟系统可通过网络进行管理及时间校对&#xff0c;为厂区提供高精度、全天时、全天候 的授时服务&#xff0c;统一全厂各种系统…...

本地docker-compose仓库搭建以及推送docker镜像到仓库

前言 以下部分知识只适用于linux&#xff0c;不适合小白&#xff0c;请自行甄别执行 1.搭建 #参考 https://blog.csdn.net/u011535199/article/details/107457275 version: 3 services:registry:restart: alwaysimage: registry:2ports:- 5000:5000environment:#REGISTRY_HT…...

WPF+MVVM案例实战(八)- 自定义开关控件封装实现

文章目录 1、案例运行效果2、项目准备2、功能实现1、控件模板实现2、控件封装1、目录与文件创建2、各文件功能实现 3、开关界面与主窗体菜单实现1、开关界面实现2、主窗体菜单实现 4、源代码获取 1、案例运行效果 2、项目准备 打开项目 Wpf_Examples&#xff0c;新建ToggleBut…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...