You get to implement vectors, with basic operations on them, this gives you a chance to practice some abstractions. It's also good to create some unit tests to ensure your vector operations are correct. There's also good reason to parallelize your code and perform benchmarks. Abstractions, unit tests, parallelism, benchmarks, you have an excuse to try them all.
[1] https://github.com/RayTracing/raytracing.github.io/blob/7e2a...
https://tayfunkayhan.wordpress.com/2018/11/24/rasterization-...
Ray direction and ray length might be combined into one vector that just stretches from the origin for ray tracing, but using the direction with a surface normal for dot products, reflection vectors etc. is going to give artifacts.
See http://www.pbr-book.org/3ed-2018/Shapes/Spheres.html#Surface..., the paragraph beginning "A natural question to ask..."
(Also in practice floating point inaccuracy doesn't become a huge problem since you have to design around floats not being exact in the first place. Spheres can also wind up being more finnicky with precision but are rarely used as primitives to trace against in production renderers. There isn't a single right way to do the tracing, but the shading does need normalized vectors for a lot of common operations.)
I've never heard this before! Interesting. Why is this?
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-4...
Triangle meshes are better choices for the same reasons: they can be used to model arbitrarily complex shapes, and it's faster to compute ray-triangle intersections.