These guidelines are probably insufficiently pithy, and might not be wise at all. But they seem to work for me.
See also the priority of constituencies. Start with UX mocks and storyboards, user documentation, API documentation, or whatever is appropriate for the kind of programming you’re doing. Don’t start writing code first.
Of course, this requires you to know what you are assuming. Use every
or other assumption-checking construct you can. Do not turn them off in
production builds, unless profiling shows an assertion is actually making a hot
spot hotter. (Very little code is actually hot.)
Use whatever facilities your language provides for nailing things down, and prefer languages that have such facilities. This is what functional programming people are always yelling about, and they have a point.
Comments are sometimes necessary. But if your interfaces and even your implementations don’t explain themselves by their use of names, try using more and better names and types instead of more comments. This is hard, but the effort pays off.
Don’t even allow ill-defined or invalid objects to come into existence. Raise an exception or return a well-defined sentinel value.
The claims of academics — formal verification being possible, static analysis discovering most or many bugs, and so on — gradually become increasingly solid enough to ship in production compilers. Type systems are usable proof systems, and compiler warnings are usable static analysis — and they’ve been getting better every year. Turn on all such options at their highest level. They will slow you down for a week and speed you up for the rest of your life.
Think long and hard about each dependency you take on. Mere convenience for you is inconvenience and unsafety for your users. Be certain that each dependency is less buggy and debt-laden than what you could do yourself — if it really needs doing at all.
If you’re not sure what to do yet, start with The Simplest Thing That Could Possibly Work. It may end up being all you need.
However, software that is too simple can be unnecessarily hard to use.