编写玩具软件是一种乐趣(2025)

Lobsters Hottest 新闻

摘要

一篇倡导编写玩具程序以深入理解软件并重新发现编程乐趣的博客文章,反对过度工程化和软件开发的工业化。

<p><a href="https://lobste.rs/s/ax6col/writing_toy_software_is_joy_2025">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/07/29 05:51

# 编写玩具软件是一种乐趣 来源:https://blog.jsbarretto.com/post/software-is-joy 为什么你应该写更多玩具程序 --- *2025年6月15日* 我是理查德·费曼那句名言的超级粉丝: > "我不能创造的东西,我就无法理解" 我认为这句话非常精辟,并且在许多领域都成立(如果你愿意对"创造"的定义稍加创意的话)。我相信,我真正擅长的一切都归功于这个原则。有人会告诉你要避免重复造轮子,但他们错了:你*应该*自己造轮子,因为这样学到的关于轮子工作原理的知识,比读一千本书都要多。 2025年,编写软件的美丽和工艺正在被侵蚀。人工智能威胁要取代我们(至少,取代我们工作中最快乐的部分),软件开发正变得越来越商品化、可衡量、可打包和工业化。软件开发需要更多简单的乐趣,我发现创建玩具程序是重新记起我为什么开始与计算机打交道的好方法。 ## 保持简单 玩具程序遵循80:20法则:20%的工作,80%的功能。重点*不是*构建生产级软件(尽管确实有些最好的生产级软件最初只是玩具)。极力避免过度工程化,只写实现目标所必需的代码。让每个代码路径都崩溃/报错,直到你被迫实现它才能推进。你可能会惊讶地发现,构建那些你之前认为极其困难的软件的玩具版本竟然如此简单。 ## 其他好处 我经常惊讶地发现,在玩具项目中学到的某些晦涩知识,在我日常工作中竟然非常有价值,要么让我在追踪某个工具或库的问题时领先一步,要么在错误发生前就识别出来。 理解塑造软件形态的约束条件对于处理软件至关重要,而获得对这些约束的洞察的最好方法就是直接撞上它们。你甚至可能想出一些新颖的解决方案! ## 项目列表 以下是我在过去15年中尝试过的玩具程序列表,按难度和所需时间评分。这些评分是估算值,并假设你已经熟悉至少一种通用编程语言,并且像我一样,每天只有一两个小时的空闲时间写代码。还包含一些我觉得有用的推荐资源。 ### 正则表达式引擎(难度 = 4/10,时间 = 5天) 一个能读取POSIX风格正则表达式程序并识别匹配字符串的正则表达式引擎。正则表达式简单却惊人的表达力,编写一个像样的正则表达式引擎也会教会你使用该语言所需的一切知识。 - Wikipedia: Regular expression (https://en.wikipedia.org/wiki/Regular_expression#Syntax) ### x86 OS内核(难度 = 7/10,时间 = 2个月) 一个兼容multiboot的操作系统内核,带有简单的CLI、键盘/鼠标驱动、ANSI转义序列支持、内存管理器、调度器等。额外的挑战包括编写内存文件系统、用户模式和进程隔离、加载ELF可执行文件,以及支持足够的视频硬件来渲染GUI。 - OS Dev Wiki (https://wiki.osdev.org/) Tupai (https://gitlab.com/zesterer/tupai) ### GameBoy/NES模拟器(难度 = 6/10,时间 = 3周) 一个最简单的GameBoy或NES游戏的粗糙模拟器。GB和NES是经典机型,都有相对简单的指令集和外设硬件。额外的挑战包括编写合格的PPU(视频)和PSG(音频)实现,以及处理一些更奇特卡带格式。 - GB Dev (https://gbdev.io/) - NES Dev Wiki (https://www.nesdev.org/wiki/Nesdev_Wiki) ### GameBoy Advance游戏(难度 = 3/10,时间 = 2周) 一个基于精灵的游戏(俯视或侧平台)。GBA是一个编写代码的漂亮小主机,并且有一个活跃且专注的开发社区。我真的相信GBA是最后一个可以被单个开发者完全理解(包括指令时序)的游戏主机之一。 - Tonc (https://www.coranac.com/tonc/text/toc.htm) - GBATEK (https://problemkaputt.de/gbatek.htm) ### 物理引擎(难度 = 5/10,时间 = 1周) 一个实现牛顿物理的2D刚体物理引擎,支持矩形、圆形等。最简单的实现,比如只是相互排斥的球体,相当容易。当引入更复杂的形状、角动量等时,事情开始变得复杂。额外的挑战包括让碰撞解析快速且可扩展,使复杂交互随时间趋于稳态,软体交互等。 ### 动态解释器(难度 = 4/10,时间 = 1-2周) 一个树遍历解释器,用于类似JavaScript的语言,带有基本流程控制。这个项目有无穷无尽的额外功能可以添加,但能够用我自己的语言编写程序仍然让我感到孩子般的兴奋。这感觉像是一种技术创世:一旦你有了自己的语言,你就可以在其中开始构建宇宙。 - Crafting Interpreters (https://craftinginterpreters.com/) Forge (https://github.com/zesterer/forge) ### C语言编译器(难度 = 8/10,时间 = 3个月) 一个用于简单类型化类C编程语言的编译器,支持至少一种目标架构。额外的挑战包括实现一些最常见的优化(内联、常量折叠、循环不变量代码移动等)以及设计一个足够通用的中间表示(IR)来支持多个后端。 ### 文本编辑器(难度 = 5/10,时间 = 2-4周) 这个项目变数很大。最粗略的实现,比如读写文件,几行Python就能搞定。但构建一个接近日常使用的编辑器就复杂多了。你可以选择使用QT或GTK等工具包实现UI,但我个人更喜欢在终端中工作的编辑器。正确处理Unicode、语法高亮、光标移动、多缓冲区支持、窗格/窗口、标签页、搜索/查找功能、LSP支持等,都可能给项目增加一周到一个月的时间。但如果你坚持下来,你可能会加入那些使用自己创建的编辑器的精英开发者行列。 ZTE (https://github.com/zesterer/zte) ### 异步运行时(难度 = 6/10,时间 = 1周) "异步"的含义因语言而异。至少在Rust中,这意味着一个库可以接收`impl Future`任务并并发轮询它们直到完成。增加对I/O唤起的支持是一个有趣的挑战。 ### 哈希映射(难度 = 4/10,时间 = 3-5天) 哈希映射(或集合/字典,高级语言可能这么叫)是程序员的基本工具。然而,令人惊讶的是,我们中很少有人真正理解它们底层的运作原理。有大量技术可以混入:封闭或开放寻址、墓碑、罗宾汉规则等。你会理解它们何时以及为何快速,以及何时应该只使用向量+线性搜索。 - Robin Hood Hashing should be your default Hash Table implementation (https://www.sebastiansylvan.com/post/robin-hood-hashing-should-be-your-default-hash-table-implementation/) ### 光栅化器/纹理映射器(难度 = 6/10,时间 = 2周) 我们大多数人都玩过简单的3D图形,但有多少人真正理解图形管线的工作原理,更重要的是,当它出问题时如何修复?编写自己的软件光栅化器将给你带来这些知识,同时让你重新欣赏向量数学和半空间的美丽,这些在许多其他领域都有应用。额外的复杂度包括正确实现裁剪、Z缓冲、N边形光栅化、透视校正纹理映射、Phong或Gouraud着色、阴影映射等。 - Scratch-A-Pixel (https://www.scratchapixel.com/) - How OpenGL works: software rendering in 500 lines of code (https://github.com/ssloy/tinyrenderer/wiki/Lesson-0:-getting-started) euc (https://github.com/zesterer/euc) ### SDF渲染(难度 = 5/10,时间 = 3天) 有符号距离场是一种通过数学定义渲染3D空间的优美简单方法,非常适合演示场景着色器。只需相对较少的工作,你就可以构建一个可爱的小可视化或一些像80年代图形演示那样的运动形状。你还会欣赏着色器语言和向量数学。 - Inigo Quilez's Site (https://iquilezles.org/articles/distfunctions/) - ShaderToy (https://www.shadertoy.com/) Signed Distance Fields (https://www.shadertoy.com/view/ftXBWs) ### 体素引擎(难度 = 5/10,时间 = 2周) 我相信读到这篇文章的人很少有人没玩过《我的世界》。构建一个类似风格的玩具体素引擎出奇地容易,尤其是如果你已经具备一些3D图形或游戏开发知识。体素引擎的简单性,加上它们所能表达的近乎无限的创造力,总能给我带来快乐。额外的复杂度可以通过处理纹理、更复杂的程序生成、洪水填充光照、碰撞、动态流体、通过网络发送体素数据等来增加。 - 0 FPS: Meshing in a Minecraft Game (https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/) ### 线程化虚拟机(难度 = 6/10,时间 = 1周) 编写解释器很有趣。什么更有趣?*更快的解释器*。如果你在不进行架构特定代码生成(如AOT或JIT)的情况下不断将解释器推向极限,你最终会发现(重新发现)*线程化代码*(不要与多线程混淆,后者是完全不同的东西)。这是一种将程序从高度优化的微小程序中编织出来的优美方式,一个好的实现甚至可以在性能上与AOT编译器一较高下。 - Wikipedia: Threaded code (https://en.wikipedia.org/wiki/Threaded_code) - muforth.dev: Threaded code (https://muforth.dev/threaded-code/) ### GUI工具包(难度 = 6/10,时间 = 2-3周) 我们大多数人可能都用过tkinter、GTK、QT或WinForms拼凑过GUI程序。但为什么不试试编写你自己的GUI工具包呢?额外的复杂度包括实现一个合格的布局引擎、良好的文本整形(包括Unicode支持)、辅助功能支持等。事先警告:除非你的工具经过*实战测试*,否则不要鼓励别人使用它——世界上已经有了太多缺乏辅助功能或本地化支持的GUI。 - YouTube: How Clay's UI Algorithm Works (https://www.youtube.com/watch?v=by9lQvpvMIc) GUI (https://github.com/zesterer/gui) ### 轨道力学模拟(难度 = 6/10,时间 = 1周) 一个简单的牛顿引力模拟可以在很短的时间内拼凑出来。众所周知,包含两个以上天体的引力系统无法解析求解,所以你必须熟悉迭代*积分*方法。额外的复杂度来自实现更精确和更快的积分方法,考虑相对论效应,并编写可视化器。如果你的数学正确,你甚至可以尝试输入NASA的真实数据来预测下一次涨潮或满月。 - Wikipedia: Leapfrog integration (https://en.wikipedia.org/wiki/Leapfrog_integration) ### 位运算挑战(难度 = 3/10,时间 = 2-3天) 这是我为自己想出来的一个挑战,但我认为它很适合游戏开发比赛:编写一个游戏,只在连续帧之间保存64位状态。也就是说,所有东西只有64位:整个帧对帧的游戏状态应该仅用64位数据就能重现。听起来简单,但它迫使你在游戏状态管理方面变得极其有创意。规则详情可以在下面的GitHub页面找到。 - The Bitwise Challenge (https://github.com/zesterer/the-bitwise-challenge) Snake (https://github.com/zesterer/bitwise-examples) ### 一个ECS框架(难度 = 4/10,时间 = 1-2周) 给所有的游戏开发者:尝试构建你自己的ECS (https://en.wikipedia.org/wiki/Entity_component_system) 框架。这并没有你想象的那么难(你可能已经无意中做过了!)。如果你能构建安全性和正确性特性,以及与所选编程语言的类型系统特性良好集成,那就算加分。 我为我的GBA版超级马里奥64 (https://www.youtube.com/watch?v=nS5rj80L-pk) 项目构建了一个自定义ECS,因为平台有独特的性能和内存限制,而且我非常享受这个过程。 ### CHIP-8模拟器(难度 = 3/10,时间 = 3-6天) CHIP-8 (https://en.wikipedia.org/wiki/CHIP-8) 是一个来自70年代的优美简单的虚拟机。你可以在一天或两天内编写一个完全兼容的模拟器,而且有大量粉丝制作的在上面运行的游戏。这是我为它制作的一个 (https://github.com/zesterer/emul8/raw/refs/heads/master/test/test.ch8) 游戏。 - Wikipedia: CHIP-8 (https://en.wikipedia.org/wiki/CHIP-8) Emul8 (https://github.com/zesterer/emul8) ### 国际象棋引擎(难度 = 5/10,时间 = 2-5天) 编写国际象棋引擎非常有趣。开始时它走的每一步都是不合法的,但随着时间的推移,它会变得越来越聪明。输给自己的国际象棋引擎真的是一种成人礼,感觉非常神奇。 - Wikipedia: Minimax (https://en.wikipedia.org/wiki/Minimax) - Wikipedia: Alpha-beta pruning (https://en.wikipedia.org/wiki/Alpha-beta_pruning) Chess ### POSIX shell(难度 = 4/10,时间 = 3-5天) 我们每天都与shell交互,构建一个shell会让你学到大量关于POSIX的知识——它是如何工作的,以及它是如何不工作的。一个简单的shell可以在一天内构建,但要兼容现有的shell语言则需要时间,并且会让你学到比你想知道的更多的关于其古怪特性的知识。 - Write a shell in C (https://brennan.io/2015/01/16/write-a-shell-in-c/) Tosh (https://github.com/zesterer/tosh) ## 关于学习和LLM的说明 也许你是LLM的用户。我理解,它们是方便的工具。对于某些类型的学习它们很有用。但我建议抵制在这样的项目中使用它们的诱惑。知识不应该被端上盘子喂给你。如果你想要那种学习,读书就好了——构建这类玩具项目的乐趣来自于对未知的探索,而不让现有解决方案污染你的头脑。如果你已经使用LLM一段时间了,这种突然戒断的方式一开始可能会很痛苦,但要坚持下去。没有痛苦就没有快乐。 运动员的高潮不会降临到那些坐公交车的人身上。

相似文章

软件关乎人,而非代码(2020)

Hacker News Top

一篇论述软件成功更多取决于理解人及其需求,而非编写完美代码的文章,并以被遗弃的、未解决实际问题的代码库为例。

我决定回归手写代码

Hacker News Top

作者在重构一个 Kubernetes 仪表盘工具时反思道,虽然借助 AI 进行“氛围编程”(vibe-coding)能加速功能开发,但在缺乏人工监督的情况下,往往会导致架构臃肿和技术债务。

2026年为何还要写代码

Hacker News Top

认为尽管有AI编码代理,人类仍能从编写代码中获得更好的理解、所有权并维持软件质量。

@saranormous: https://x.com/saranormous/status/2064510215056400652

X AI KOLs Following

尽管以Devin为代表的AI编程助手取得了快速进展,显著提升了代码编写和交付的速度,但本文认为,软件工程中最有价值的部分仍难以通过基准测试衡量,并且需要人类的判断和组织协调,这些是无法轻易自动化的。