代码阅读:发现Bug的超级能力

2025-09-08

作者分享了其职业生涯中一个重要的转变:从迭代式编程转向主动发现Bug。不再仅仅依赖测试迭代,而是通过仔细阅读代码来提前发现问题。文章指出,仔细阅读代码,构建程序的完整心智模型,并找出模型与代码的差异,是发现Bug的关键。作者建议关注控制流和数据结构,并识别代码中的潜在错误模式。通过这种方式,可以有效减少Bug,提高代码质量。

阅读更多
开发

优雅的重试循环:避免代码冗余和意外休眠

2025-08-27

作者探索如何编写一个优雅的重试循环,该循环能清晰地限制重试次数、避免最后一次尝试后的无用休眠、在重试失败时报告原始错误,且避免代码冗余。文章比较了几种方法,最终采用了一个 `try while` 循环,并通过添加循环上限来保证循环的终止,解决了之前的方案中存在的边界问题和潜在的无限循环风险。最终方案虽然仍有不完美之处,但相比之前的尝试,在简洁性和可靠性上有了显著提升。

阅读更多
开发

Zig 语言中巧妙处理枚举的偏匹配

2025-08-09

Zig 语言提供了一种优雅的方式来处理枚举的偏匹配,避免了冗余代码和运行时恐慌。文章介绍了一种技巧,利用 `inline` 和 `comptime unreachable`,让编译器在编译时就能检查到不必要的 `else` 分支,从而提高代码的健壮性和可读性。这种方法尤其在处理大量枚举变体时,能够极大简化代码逻辑。

阅读更多

CSS 属性 font-size-adjust 的误解与正确用法

2025-07-26

本文挑战了 CSS 属性 `font-size-adjust` 的普遍误解。作者指出,`font-size` 指定的是字形周围方框的大小,而非字形本身大小,不同字体字形大小差异很大。`font-size-adjust`并非仅仅用于字体回退,而是能使页面上不同字体大小更一致,作者建议将其设置为 `ex-height 0.53`,以使不同字体大小更统一,提升页面排版一致性。

阅读更多
开发

极简RSS阅读器:用Deno构建个性化博客订阅

2025-06-26

厌倦了臃肿的RSS阅读器?作者另辟蹊径,利用Deno和一个简单的文本文件构建了自己的RSS阅读器。它只显示最新三篇文章的标题和链接,无需本地存储全文或阅读标记,通过GitHub Actions每日自动更新。代码简洁,易于理解和扩展,是一个极简主义者的福音。

阅读更多
开发

加速Rust编译:从8分钟到10分钟的秘密

2025-06-20

Rust编译速度慢是众所周知的,但本文作者认为大多数Rust项目编译速度都远低于预期。以rust-analyzer为例,其20万行代码及百万行依赖项的CI流程在GitHub Actions上仅需8分钟。作者详细阐述了如何优化rust-analyzer的构建时间,包括利用CI缓存、拆分CI任务、禁用增量编译和调试信息、减少依赖项、使用`cargo build -Z timings`进行性能分析,以及精心设计代码以避免泛型代码在crate边界上的过度实例化等策略。文章强调了构建时间对开发效率的影响,并建议定期优化构建时间,将大型Rust项目的CI时间控制在合理范围内,例如10分钟左右。

阅读更多
开发

开源的协调难题:Linux桌面与LSP的启示

2025-06-20

作者以自身使用NixOS和KDE软件的经历为引子,探讨了Linux桌面环境下开源软件协调的困境。他指出,Linux桌面缺乏统一的API标准,导致软件生态碎片化,如同一个“埃舍尔式的永动机”。这与十年前微软发布的语言服务器协议(LSP)形成对比,LSP尽管实现一般,但其存在本身解决了IDE功能的协调问题,推动了行业发展。作者认为,开源社区缺乏协调能力,错失了在LSP出现前制定统一IDE协议的机会。而Linux的成功,则得益于POSIX提供的预先定义的API标准,减少了协调难度。这篇文章引发了对开源社区协调机制及软件生态发展模式的思考,归类为科技。

阅读更多
科技

提升代码效率的两个实用技巧

2025-05-17

本文介绍了提升代码效率的两个实用技巧:将if条件上移和for循环下移。将if条件上移到调用函数处,可以减少代码分支,简化控制流程,并提升代码可读性。将for循环下移到处理批量数据的地方,可以利用批量处理的优势,提升性能,并可能开启向量化操作。这两个技巧互相补充,可以有效提高代码效率,尤其在处理大量数据时效果显著。

阅读更多
开发

告别单事件处理:批量处理事件流的优雅之道

2025-05-15

作者在构建状态服务时,发现单事件处理(Scalar Select)模式效率低下。文章以一个LSP服务器为例,阐述了该模式如何导致处理延迟和资源浪费。作者提出了一种改进方案:批量处理事件流。通过`batch_stream`函数,将多个事件合并成批次处理,从而显著提高效率。这种方法在低负载下表现为单事件处理,但在高负载下能够有效降低处理开销,提升系统性能。

阅读更多
开发

Zig 编译时元编程的限制与优雅

2025-04-20

Zig 语言的编译时 (comptime) 功能强大,支持泛型、条件编译等,但其设计上刻意限制了某些功能,例如不允许动态代码生成、自定义语法扩展、运行时类型信息 (RTTI) 和 I/O 操作。文章深入探讨了这些限制背后的原因,以及 Zig 如何通过部分求值和类型特化等机制,在限制中实现高效且易于理解的元编程。通过一个自定义打印函数的例子,展示了 Zig 如何在不依赖 RTTI 的情况下实现类型安全的运行时反射。最终,文章赞扬了 Zig 在元编程上的独特优雅之处,它虽然功能不如其他语言强大,但在实际应用中却异常高效易用。

阅读更多
开发

告别传统调试器:IntelliJ IDEA 的 Run to Cursor 和 Quick Evaluate Expression 功能

2025-03-28

作者厌倦了传统调试器的繁琐,尤其是gdb和lldb在原生代码调试中的无力感。他发现IntelliJ IDEA的“Run to Cursor”和“Quick Evaluate Expression”功能组合,可以将调试器转变为强大的REPL环境。通过“Run to Cursor”将程序运行到光标所在行,再用“Quick Evaluate Expression”在当前栈帧中评估表达式,甚至可以输入新的代码并执行,实现了高效的代码探索和实验。这种方式摒弃了传统的单行命令交互,而是利用编辑器的二维文本界面,提供代码补全等特性,极大提升了调试效率。

阅读更多
开发

在脚本中使用长选项

2025-03-22

许多命令行工具都支持短选项(-f)和长选项(--force)。短选项适用于交互式使用,而长选项更适合在脚本中使用。长选项更易于阅读和理解,提高了脚本的可维护性和可读性。例如,在Git命令中,使用`git switch --create release-{today} origin/main` 比 `git switch -c my-new-branch` 更清晰明了,尤其是在复杂的脚本中。

阅读更多
开发 长选项

硬核Rust:无动态内存分配的光线追踪器

2025-01-30

本文介绍了作者使用极简API(无动态内存分配)编写Rust应用程序的案例研究。作者批评了RAII(资源获取即初始化)机制导致资源管理混乱,并提出了一种“硬核模式”:将程序分割成`std`二进制文件和`#![no_std] no_alloc`库,仅允许二进制文件直接向操作系统请求资源。文章以一个玩具光线追踪器为例,详细讲解了在“硬核模式”下如何处理像素缓冲区、并行化、内存分配器和场景解析等问题,最终实现了一个无需动态内存分配的光线追踪器。

阅读更多
开发

不变式:编写正确代码的利器

2025-01-12

本文探讨了编程中“不变式”的概念及其应用。作者从一个小例子——编写一个计算插入点的二分查找变体——出发,阐述了如何通过明确定义并维护不变式来编写正确的代码。 文中指出,不变式是一种在系统动态演变过程中始终保持的属性,它能够简化推理过程,避免因考虑多种执行路径而带来的复杂性。 作者还以Cargo、rust-analyzer和TigerBeetle等项目为例,展示了在大型系统中应用不变式带来的好处,例如提高代码可维护性和性能。最终,作者总结了不变式在小规模和大型编程中的重要作用,强调了其在编写正确且高效代码中的价值。

阅读更多
开发

颠覆性设想:将Magit理念应用于jj版本控制系统

2024-12-13

作者提出了一种新颖的思路,将Emacs的Magit版本控制界面(以文本文件为UI)应用于新兴的jj版本控制生态系统。文章指出,Magit的文本化UI具有高效性和可移植性,通过LSP协议,可以在多种编辑器中实现类似Magit的体验,避免重复开发。作者设想通过生成特定文本文件(如.jj/status.jj),并利用LSP的语义标记、折叠范围和跳转定义等功能,实现与Magit类似的版本控制操作,最终目标是创建一个跨平台、高效的jj版本控制用户界面。

阅读更多
开发 jj Magit

缺失的IDE特性

2024-11-04

本文作者认为IDE中缺失一项重要特性:默认折叠方法体。该特性易于实现,能极大提升阅读代码的效率,却在多数编辑器中缺失。文章详细解释了该特性的工作原理:仅折叠方法体而非其他代码块,折叠是默认状态,并在跳转到定义时自动展开。作者认为该特性能隐藏80%的非核心代码,突出重要的函数签名,提升代码可读性。文章呼吁编辑器开发者添加此功能,并指出通过Tree-sitter或LSP可以相对容易地实现。作者本人六年前已在rust-analyzer中实现了该功能的服务端部分,但受限于LSP协议,未能完全实现。

阅读更多
未分类 代码折叠

更深层次地修复问题

2024-10-16

本文讲述了作者在一天的工作中,如何通过更深层次地思考问题,发现并修复了一系列潜在的错误和设计缺陷。从数据库磁盘空间不足的错误信息,到代码格式化问题,再到编译时参数的混淆,作者不断地挑战自己,寻找更优雅、更彻底的解决方案。最终,作者将问题归结到代码逻辑的重构上,并试图通过改进代码设计来避免此类问题的再次发生。

阅读更多
未分类

什么是 io_uring?

2024-09-24

io_uring 是一种全新的 Linux 内核接口,用于进行系统调用。与传统的同步、逐个提交系统调用的方式不同,io_uring 采用批量异步方式。应用程序通过将系统调用代码和参数写入无锁共享内存环形缓冲区来提交多个系统调用。内核读取并按自身节奏执行,结果异步写入第二个环形缓冲区供应用程序读取。

阅读更多
未分类 io_uring

软件依赖的基本法则

2024-09-04

文章指出,软件的规范源码应该包含所有依赖项内容的校验和,并列举了几个例子:源码管理应该使用类似Git的内容寻址版本控制系统;第三方库的依赖关系应该使用包含校验和的锁文件管理;编译器的哈希值也应该包含在锁文件中,以便验证编译器的可靠性。作者认为,校验和本身并不重要,重要的是获取校验和的过程能够促使开发者明确依赖项、自动化下载依赖项、确保依赖项构建的可重复性以及隔离项目依赖项,最终使得软件开发变得更容易。

阅读更多
未分类 软件依赖

Rust 的丑陋语法

2024-08-30

这篇文章探讨了Rust语法,作者认为人们对Rust语法的抱怨实际上是对其语义的反对。文章以一个读取文件的Rust函数为例,展示了其语法复杂性,并尝试用其他语言风格改写,以期找到更简洁的表达方式。作者进一步探讨了简化Rust语义的可能性,例如移除泛型、借用和错误处理机制,最终得到了一个更简洁但牺牲了性能和安全性的版本。

阅读更多
未分类

面向程序员的原始递归函数

2024-08-03

本文讨论了图灵完备性的概念,并指出在实践中,非图灵完备性并不像人们通常认为的那样重要。作者通过介绍有限状态机、图灵机和原始递归函数,证明了任何在图灵机上运行并在原始递归函数时间内终止的算法都可以用原始递归函数实现。文章还探讨了良好配置语言的特性,包括确定性、定义明确、纯洁性、安全性、沙盒化和简单性,并指出非图灵完备性本身并不能保证这些特性。

阅读更多
未分类 原始递归函数

我是如何使用 Git 工作树的

2024-07-26

文章介绍了作者如何利用 Git 工作树来管理并发任务,而不是将其作为分支的替代品。作者创建了五个工作树,分别用于查看原始代码、编写代码、审查代码、运行模糊测试以及处理其他临时任务。这种方法提高了作者的编码效率,并能更好地管理并发任务。

阅读更多
未分类 工作树

如何正确地测试并发数据结构

2024-07-06

文章介绍了一种测试并发数据结构的方法,通过模拟并控制线程的执行顺序,实现了对并发操作的精细化测试。作者首先解释了传统并发测试的不足,然后逐步推导了一种基于“管理线程”的测试方法,并用一个简单的计数器示例演示了如何使用该方法发现并最小化并发错误。文章最后还探讨了如何将该方法扩展到更复杂的场景,例如模拟弱内存模型和穷举所有可能的交错执行路径。

阅读更多
未分类 并发测试

正则、递归、受限

2024-06-05

本文探讨了如何使用一种称为“递归受限正则表达式”的新形式来描述算术表达式。作者首先指出现有语法(如上下文无关文法和解析表达式文法)在描述表达式优先级和结合性方面的局限性。然后,作者提出了一种使用正则表达式来定义树形结构的方法,并通过添加约束规则来消除歧义。最后,作者提出了一个问题:是否存在一种算法可以判定任意递归受限正则表达式是否具有歧义性。

阅读更多