编写玩具软件是一件乐事
Writing Toy Software Is a Joy

原始链接: https://www.jsbarretto.com/blog/software-is-joy/

受费曼名言“我无法创造的东西,我就不理解”的启发,本文提倡通过实践构建来学习,即使这意味着“重新发明轮子”。在软件开发商品化和人工智能威胁的时代,作者建议通过编写玩具程序来重燃编码的乐趣。文章列举了各种项目,并估算了其难度和时间投入,包括正则表达式引擎、操作系统内核、游戏模拟器(GameBoy/NES/GBA)、物理引擎、动态解释器、类C编译器、文本编辑器、异步运行时、哈希表、光栅化器、SDF渲染器、体素引擎、多线程虚拟机、GUI工具包、轨道力学模拟器、位运算游戏、ECS框架、CHIP-8模拟器和国际象棋引擎。这些项目的复杂程度各不相同,为各个水平的程序员提供了学习机会,并有机会深入理解基本概念。作者相信,无论结果如何,创建这些项目都能带来宝贵的学习经验,并重新点燃对软件开发的热情。

Hacker News 上的一个帖子讨论了编写“玩具软件”的乐趣,以及创建小型个人项目以学习和娱乐的好处。用户分享了他们各种项目的经验,例如模拟器、编译器,甚至多人宾果游戏。原文建议列出了一些此类项目,并估算了难度和时间投入,但评论者对这些估计的准确性提出了质疑,强调这取决于项目的复杂性和所需的完成度。许多人认为,关键的好处并不在于最终产品是否完美,而在于学习和创造性探索的过程。几位用户分享了他们自己的项目创意以及相关的资源链接,例如“自己动手制作X”。一个共同的主题是摆脱了职业约束,可以进行创新和冒险,而不用担心失败。业余项目是保持思维敏捷和精力充沛的好方法!
相关文章

原文

I am a huge fan of Richard Feyman’s famous quote:

“What I cannot create, I do not understand”

I think it’s brilliant, and it remains true across many fields (if you’re willing to be a little creative with the definition of ‘create’). It is to this principle that I believe I owe everything I’m truly good at. Some will tell you should avoid reinventing the wheel, but they’re wrong: you should build your own wheel, because it’ll teach you more about how they work than reading a thousand books on them ever will.

In 2025, the beauty and craft of writing software is being eroded. AI is threatening to replace us (or, at least, the most joyful aspects of our craft) and software development is being increasingly commodified, measured, packaged, and industrialised. Software development needs more simple joy, and I’ve found that creating toy programs is a great way to remember why I started working with computers again.

Here are a list of toy programs I’ve attempted over the past 15 years rated by difficulty and time required. These ratings are estimates and assume that you’re already comfortable with at least one-general purpose programming language and that, like me, you tend to only have an hour or two per day free to write code. Also included are some suggested resources.

Perhaps you’d like to try some yourself!

Regex engine (difficulty = 4/10, time = 3 days)

A regex engine that can read a POSIX-style regex program and recognise strings that match it. Regex is simple yet shockingly expressive, and writing a competent regex engine will teach you everything you need to know about using the language too.

x86 OS kernel (difficulty = 7/10, time = 1 month)

A multiboot-compliant OS kernel with a simple CLI, keyboard/mouse driver, ANSI escape sequence support, memory manager, scheduler, etc. Additional challenges include writing an in-memory filesystem, user mode and process isolation, loading ELF executables, and supporting enough video hardware to render a GUI.

GameBoy/NES emulator (difficulty = 6/10, time = 2 weeks)

A crude emulator for the simplest GameBoy or NES games. The GB and the NES are classics, and both have relatively simple instruction sets. Additional challenges include writing competent PPU (video) and PSG (audio) implementations, along with dealing with some of the more exotic cartridge formats.

GameBoy Advance game (difficulty = 3/10, time = 1 week)

A sprite-based game (top-down or side-on platform). The GBA is a beautiful little console to write code for and there’s an active and dedicated development community for the console. I truly believe that the GBA is one of the last game consoles that can be fully and completely understood by a single developer, right down to instruction timings.

Physics engine (difficulty = 5/10, time = 1 week)

A 2D rigid body physics engine that implements Newtonian physics with support for rectangles, circles, etc. On the simplest end, just spheres that push away from one-another is quite simple to implement. Things start to get complex when you introduce more complex shapes, angular momentum, and the like. Additional challenges include making collision resolution fast and scaleable, having complex interactions move toward a steady state over time, soft-body interactions, etc.

Dynamic interpreter (difficulty = 4/10, time = 3 days)

A tree-walking interpreter for a JavaScript-like language with basic flow control. There’s an unbounded list of extra things to add to this one, but being able to write programs in my own language still gives me child-like elation. It feels like a sort of techno-genesis: once you’ve got your own language, you can start building the universe within it.

Compiler for a C-like (difficulty = 8/10, time = 3 months)

A compiler for a simply-typed C-like programming language with support for at least one target archtecture. Extra challenges include implementing some of the most common optimisations (inlining, const folding, loop-invariant code motion, etc.) and designing an intermediate representation (IR) that’s general enough to support multiple backends.

Text editor (difficulty = 5/10, time = 3 weeks)

This one has a lot of variability. At the blunt end, simply reading and writing a file can be done in a few lines of Python. But building something that’s closer to a daily driver gets more complex. You could choose to implement the UI using a toolkit like QT or GTK, but I personally favour an editor that works in the console. Properly handling unicode, syntax highlighting, cursor movement, multi-buffer support, panes/windows, tabs, search/find functionality, LSP support, etc. can all add between a week or a month to the project. But if you persist, you might join the elite company of those developers who use an editor of their own creation.

Async runtime (difficulty = 6/10, time = 1 week)

There’s a lot of language-specific variability as to what ‘async’ actually means. In Rust, at least, this means a library that can ingest impl Future tasks and poll them concurrently until completion. Adding support for I/O waking makes for a fun challenge.

Hash map (difficulty = 4/10, time = 1 week)

Hash maps (or sets/dictionaries, as a higher-level language might call them) are a programmer’s bread & butter. And yet, surprisingly few of us understand how they really work under the bonnet. There are a plethora of techniques to throw into the mix too: closed or open addressing, tombstones, the robin hood rule, etc. You’ll gain an appreciation for when and why they’re fast, and also when you should just use a vector + linear search.

Rasteriser / texture-mapper (difficulty = 6/10, time = 1 week)

Most of us have played with simple 3D graphics at some point, but how many of us truly understand how the graphics pipeline works and, more to the point, how to fix it when it doesn’t work? Writing your own software rasteriser will give you that knowledge, along with a new-found appreciation for the beauty of vector maths and half-spaces that have applications across many other fields. Additional complexity involves properly implementing clipping, a Z-buffer, N-gon rasterisation, perspective-correct texture-mapping, Phong or Gouraud shading, shadow-mapping, etc.

SDF Rendering (difficulty = 5/10, time = 2 days)

Signed Distance Fields are a beautifully simple way to render 3D spaces defined through mathematics, and are perfectly suited to demoscene shaders. With relatively little work you can build yourself a cute little visualisation or some moving shapes like the graphics demos of the 80s. You’ll also gain an appreciation for shader languages and vector maths.

Voxel engine (difficulty = 5/10, time = 1 week)

I doubt there are many reading this that haven’t played Minecraft. It’s surprisingly easy to build your own toy voxel engine cut from a similar cloth, especially if you’ve gone some knowledge of 3D graphics or game development already. The simplicity of a voxel engine, combined with the near-limitless creativity that can be expressed with them, never ceases to fill me with joy. Additional complexity can be added by tackling textures, more complex procedural generation, floodfill lighting, collisions, dynamic fluids, sending voxel data over the network, etc.

Threaded Virtual Machine (difficulty = 6/10, time = 3 days)

Writing interpreters is great fun. What’s more fun? Faster interpreters. If you keep pushing interpreters as far as they can go without doing architecture-specific codegen (like AOT or JIT), you’ll eventually wind up (re)discovering threaded code. It’s a beautiful way of weaving programs together out highly-optimised miniature programs, and a decent implementation can even give an AOT compiler a run for its money in the performance department.

Your Own GUI Toolkit (difficulty = 6/10, time = 2 weeks)

Most of us have probably cobbled together a GUI program using tkinter, GTK, QT, or WinForms. But why not try writing your GUI toolkit? Additional complexity involves implementing a competent layout engine, good text shaping (inc. unicode support), accessibility support, and more. Fair warning: do not encourage people to use your tool unless it’s battle-tested - the world has enough GUIs with little-to-no accessibility or localisation support.

Orbital Mechanics Sim (difficulty = 10/10, time = 4 days)

A simple simulation of Newtonian gravity can be cobbled together in a fairly short time. Infamously, gravitational systems with more than three bodies cannot be solved analytically, so you’ll have to get familiar with iterative integration methods. Additional complexity comes with implementing more precise and faster integration methods, accounting for relativistic effects, and plugging in real numbers from NASA to predict the next high tide or full moon.

Bitwise Challenge (difficulty = 3/10, time = 1 day)

Here’s the challenge: write a game that only persists 64 bits of state between subsequent frames. That’s 64 bits for everything: the entire frame-for-frame game state should be reproducible using only 64 bits of data. It sounds simple, but it forces you to get incredibly creative with your game state management. More details about the rules on the GitHub page below.

An ECS Framework (difficulty = 4/10, time = 1 week)

For all those game devs out there: try building your own ECS framework. It’s not as hard as you might think (you might have accidentally done it already!). Extra points if you can build in safety and correctness features, as well as good integration with your programming language of choice’s type system features.

CHIP-8 Emulator (difficulty = 3/10, time = 3 days)

The CHIP-8 is a beautifully simple virtual machine from the 70s. You can write a fully compliant emulator in a day or two, and there are an enormous plethora of fan-made games that run on it. Here’s a game I made for it.

Chess engine (difficulty = 5/10, time = 2 days)

Writing a chess engine is great fun. You’ll start off with every move it makes being illegal, but over time it’ll get smart and smarter. Experiencing a loss to your own chess engine really is a rite of passage, and it feels magical.

POSIX shell (difficulty = 4/10, time = 3 days)

We interact with shells every day, and building one will teach you can incredible amount about POSIX - how it works, and how it doesn’t. A simple one can be built in a day, but compliance with an existing shell language will take time and teach you more than you ever wanted to know about its quirks.

联系我们 contact @ memedata.com