Debugging needs a little extra
Beyond the compiler or toolchain support for “debug mode”, consider adding optional debug features to your systems.
Here’s a trivial example: the observer pattern. You can implement a history of “previous observers” for observables. You wouldn’t ship with this enabled, but it could save a lot of time debugging instead of trying to reconstruct the history manually.
A real-world example from game engines is the string values of string hashes. Often strings are used as identifiers, but if all we need is uniqueness and the ability to compare, we can compute a numerical hash and use that. This is better for memory usage and performance but is difficult to debug. You’d have to maintain some sort of look-up to check on each value you are interested in. The debug version of this system could store the full values inline for easier debugging.
One thing to keep in mind is to make sure you cannot easily build functionality that depends on the debug functionality to be present. In the best case it won’t compile in any configuration; in the worst it crashes in release/production mode.