Reflecting on "The Ray Tracer Challenge"
07 Aug 2025
In December of 2023, I got a copy of “The Ray Tracer Challenge: A Test-Drive Guide to Your First 3D Renderer”. Getting close to the two year anniversary of that purchase and semi-frequent work on the project, and having been knocked out by some sort of bronchitis the past week, I figured it might be a good time to put some sort of “bow” on my work (I’ve gotten through 11 of the 17 chapters). These are some collected thoughts, mostly having to do with Rust. I’ve worked with Rust a bit before, but this was the most ambitious project I’ve undertaken with it. As a degenerate JVM-enjoyer, I rarely have to think about memory. This is obviously a double-edged sword, and getting a better handle on how the JVM does it’s garbage collection is another on-going project of mine (“The Well-Grounded Java Developer” is an excellent book I recently more-or-less completed). I’d highly recommend working with Rust, if only to have it make you think about the real “cost” of the abstractions provided by other languages! So, here are some thoughts.
Working with Rust is a pleasure
Cargo is a beautiful package manager, and makes starting a new project trivial. The built-in testing framework is more than enough to make great tests (“unit” or otherwise)—although having the tests live in the same file took some getting used to. Having built-in formatting and linting should be the standard as it is here. The community is wonderful to engage with as a beginner. This point is kind of interesting to me because I think Rust gets a reputation as a language for anti-social programmers eager to show off that they use the most “difficult” language possible. The second half of that might apply to me (oops, something to work on!), but certainly the official Rust forums are very pro-social. Just stay off YouTube and Twitter.
Working with Rust is hard, and that’s good
Spending most of my days in the JVM world, having to think about memory at all is (maybe unfortunately) very foreign. Trying to do things that are very easy in Java like implementing an observer pattern, or really anything that would have me reaching for an interface
, come with a boatload of extra considerations in Rust. Going from using an interface
as I would any other Java type, to working with things like a Box<dyn trait>
, really made me think. Taking another step and figuring out polymorphism in an asynchronous context was really a mind bender for me (don’t ask me about that at least at the moment). This all had the effect on me to ask “how does this actually work in Java?”, or to really consider if there’s such a thing as a “free lunch” when it comes to the abstractions a language provides.
Just writing a test first is not TDD
I’m a big TDD person, part of me would like to be disabused of that, but I don’t think of myself as being super good at programming so I need the help. The book that I was working out of is a “Test-Driven Guide” to building a ray tracer, and this aspect really made me reflect on what I consider to be the most beneficial aspects of TDD. To me, the greatest benefit of practicing TDD is actually writing the tests, which you don’t really get if you’re just copy-pasting from examples. The book is great, and I don’t know exactly how the author could give more liberty to the reader without it getting totally off the rails. At a certain point, I found that the author’s design was being enforced through the tests that accompany each chapter, and that that design was not really working for me. With the support of very coarsely grained snapshot testing, I was able to depart from the implementation details put forward in the book, but then this of course required some translating between tests that he lays out and what I would have to implement.
I don’t know anything about hardware acceleration
My ray tracer is not fast, at least at the time of writing. I very naively thought that harnessing a GPU would be simple. I’m just writing instructions for a processor right? So shouldn’t I be able to direct them at another processor? Very much not so easy!