The summary.
READ TRACEBACKS FROM THE BOTTOM
The last line states the error. Then find the last line referring to your own code — that is usually where the problem is.
Read the message literally. It is usually precise.
WHEN DEBUGGING
Reproduce it reliably first. Then narrow which input, which line, and what the values are.
Print the value and its type — a surprising number of bugs are a value being a different type than assumed.
USE LOGGING, NOT PRINTING, FOR ANYTHING BEYOND A QUICK CHECK
It can be left in place and silenced by configuration, rather than removed and re-added forever.
THE STRUCTURAL DECISION THAT MAKES TESTING POSSIBLE
Separate logic from external access, so logic can be tested without a database or a network.
FOR SMALL SCRIPTS WHERE FORMAL TESTS ARE DISPROPORTIONATE
Keep a sample dataset with known correct results, and check counts and totals.
That catches most failures at a fraction of the effort.
FOR PERFORMANCE
Measure before optimising. The assumption about where time goes is usually wrong.
A better data structure beats any amount of tuning, and the commonest cause is work repeated inside a loop.