You will create bugs no matter what you do. No amount of testing, type-safety, tooling, or anything else can prevent bugs. There are just too many edge cases in software for your brain to handle.
So accept that there will be bugs. Focus on having systems and processes in place that notify you immediately when things go wrong and that make it easy to fix things. For example:
- Have good error reporting tools (e.g., Sentry) that tell you exactly when and where an exception occurred and the stack trace leading to it.
- Knowing your debugger inside out so you can step through the stack trace to quickly diagnose the root of the issue. Every time you’re tempted to use
console.logor an equivalent, use a debugger instead. Use hotkeys to quickly step over, pause, and resume execution through various execution paths. A debugger should be your best friend.
- Make it easy to replicate the issue (e.g., replicate the production environment, have access to the production database, etc).
- Use assertions liberally to throw exceptions when unexpected things happen. Throw errors early so that when things go wrong, you find the problem closer to the source.
Focus on minimizing bugs in the most critical parts of the software. Bugs are part of life, but let’s minimise their severity.