Yes, I think - from my own experience, - not sure I count as a "top programmer" but I write music software that has many keen and enthusiastic users, so must be getting something right.
WHO THIS IS FOR
I wrote this for anyone who is involved, as I am, in writing software apps for the general public to use. By that, I mean, people who may have special skills - in my case most of the users of my most popular program are musicians for instance - but they have never seen your software and know nothing about it until they download it or buy it on recommendation of a friend or review etc.
WHO THIS IS NOT FOR
It's a very different situation if you write in-house software only to be used within your company - or software with no or minimal user interface e.g. for control of machinery on a chip - or server software, or software you write just for your own use for research purposes - or others who can be expected to be thoroughly familiar or willing to dedicate a lot of time to learning how to use the software.
Also, not for beginner programmers. If you have just started programming you probably will find little here that's relevant.
MAIN FOCUS OF THIS ANSWER
You'll notice, unlike other answers here, most of my answer focuses on the end user. The details of how you do the coding, and the beauty and elegance of your code - though important to developers understandably, I think are of less importance. Especially so if you are a sole developer or a small team.
It's almost symptomatic - that when coders talk about who is the best developer - they mean, mainly, someone who works well and quickly, makes code that is easy to maintain and understand and to debug . But in these discussions, developers often hardly mention the end user at all.
LISTENING TO THE END USER
So - I'd say - main thing is listening to the end users of your software. Testing not with people who know how the software works, but with people who have never seen it before.
Including also listening to those who use public betas, and the final release for later development of the software, encourage the public to contact you, and as developers, read what they say.
IF SOMEONE CAN'T UNDERSTAND YOUR PROGRAM, THINK ABOUT WHETHER YOU CAN IMPROVE THE UI
Then, if someone says that, e.g., they can't find something in your program and you need to give them a detailed explanation of how to do it - think to yourself - Can I re-arrange things, can I make this more intuitive somehow?
This doesn't need to be a chore. For me is often the most enjoyable part of the programming, talking to end users, finding out what they need to do, especially as they are often so enthusiastic about the program and it is so great for them also to be able to speak directly to the developer of the software.
If you aren't sure what they want don't be afraid to ask them to elaborate with more details, and to clarify.
Oh and important thing talking to end users, remember they are not programmers. They may say things like "I want .. in the program" and proceed to describe some complex widget or innovative UI. Often this is quite vague but sometimes, even, it is a detailed description of something they may have spent hours working on, which they are convinced will solve all the problems they have found with the UI, some radical change in how it should work..
You might spend days, even weeks sometimes, I have, occasionally, programming some new feature or UI element, exactly as they asked for it - only to find out it doesn't solve their problem. They thought, "this is what I want" but when put into a user interface in the program, turns out, it doesn't solve their issue at all.
That's your job, not theirs, to figure out how to make the program easy to use. So unless they are programmers themselves - and programmers with a track record for successful easy to use programs what's more - then treat what they say with a big pinch of common sense.
If someone suggests an element in the UI, then - instead of immediately thinking "how can I program that", then - unless it is immediately obvious of course - ask them to say more about how they want to use the program for, why they want that element and how they will use it.
Ask what they want to achieve, maybe something your program can't do yet - or something it can do - but is awkward, and ask them to say more out why it is hard to use as is if that's what it is. Just encourage them to talk and say more about it all.
Then think for yourself - is this idea they suggested the best way to achieve that? Often you find you come up with a better solution. Sometimes you find that you completely misunderstood what it was they wanted when you read their first email.
DETAILS OF THE UI FOR USER EXPERIENCE
Then look carefully at details of the user interface. For instance my programs, for a long time, didn't have active highlighting when you move the mouse over a button or control. Now they do.
Users might take a long time to discover that some fancy graphic control, which looks obvious to you, they might take ages to realize it actually does anything and is not just some meaningless decorative graphic - if there is no change of the visuals as you move the mouse over it.
That wasn't the case back in the days of Windows 95/98. But nowadays users expect just about all the graphics which is interactive to behave like that, change in some subtle way when you move the mouse over it. So you must do that - or else - in one way or another make it totally clear that it is a control and how to interact with it.
CONTEXT SENSITIVE HELP FOR CONTROLS FOR END USER TO UNDERSTAND
If help is needed to understand how to use parts of the program - then make it really easy to find and access.
In my program, then if you hover a mouse over a control, you get a tool tip - but not only that. There's also a help window which simultaneously shows more detailed help about that control, which can run to paragraphs or to several pages for some of the controls.
It doesn't matter how you do it, like that, or as more common, help button - but must be some way the user can easily jump from a control to the detailed help explaining how it works and what you do - unless your controls are totally simple and easy to use or the program is so small, so few controls, that you cn explain everything in a few pages in a manual.
And - best to have the help easily updated by the programmer yourself. So if you change the functioning of the program, can jump straight to the help for that control and immediately update it.
ADVANTAGE OF SMALL TEAMS OF DEVELOPERS WITH DIRECT COMMUNICATION TO END USERS
So - well with big companies like Microsoft they have whole teams of testers for the software.
But I think actually the sole developer or small team have an advantage there, that because everything is small, you can have direct communication of the developer to the end user. And I think that's vital - well in my own experience anyway - that you as developers keep talking to actual end users, not just work on ideas you think will work well. I think a lot of the unintuitive things you find in modern GUIs may be a result of some break in this line of communication.
ACCESSIBILITY
Also - I think it's important to think about accessibility from get go when you plan the project.
What are your plans for accomodating blind, deaf, and people who need high contrast visuals?
It is easy to make decisions early on that completely cut out blind people from your program for instance. Much of modern music software is unusuable by blind musicians, they don't satisfy even the most basic guidelines of accessibility for the blind -that you should be able to get to any control by using the tab key - and that once you get there, the control should have a text label that is readable by a screen reader so that a blind musician knows what it does (the text label can be invisible to ordinary users if you want to have a fancy graphic for them, just requires that there is text associated with the control, as its "window title" which the screen reader can see). (The same thing that in C code you can change with SetWindowText(..) ).
PROGRAMMING
This is last in my list of priorities, but of course not least important.
I'm a sole developer so haven't had to deal with many of the issues the rest of you face. With me, it's mainly, to make sure I can understand it later on.
FLEXIBLE CODING
I think it is important to keep it flexible. And probably key to a good programmer to know how to do that - what you can do that will mean less problems later on, and what you can do that is just useless bloat that will make it hard to maintain later on.
So experience of course helps. But main thing is to have some idea where you might need to go with this program way down the way.
There are some things though to watch out for
OPERATING SYSTEM AND LANGUAGE
You probably do this anyway but mentioning it because I wish I'd spent more time on it myself. Does it need to be multi-platform, e.g. Windows / iOS / xOS? If so - how can you do this, separate programs for each operating system, or write code once, deploy to them all - or use Wine and similar tools for compatibility?
Are you likely to need to support translations of the user interface and help into other natural languages apart from English other languages some time down the road? If so, it may be easier to build support for this into the program at the start rather than a later stage, or give some thought to coding methods that may make this easier to support.
Might some of your end users need to use characters in Unicode? If so are there any issues with that in the programming tools you use? (Not so much an issue nowadays).
NAMING VARIABLES AND ROUTINES
I use really long names for my variables. Especially if the variable is rarely used in the code, then I can have variable names of several words.
Don't use acronyms you may forget, or short forms of words that are ambiguous. Screen estate is free, and makes no difference to the final program.
Same for routines. Nice long names explain exactly what they do.
And if you change the functioning of a variable or routine - then do a search and replace and change its name also throughout the program.
DON'T HARD CODE MAGIC CONSTANTS
In my case when I first did coding, I'd just put numbers like say 16 into the code - 16 is a number often used by midi programmers as the number of channels.
But now I always do
#define MAX_MIDI_CHANNELS 16
int nChannels = MAX_MIDI_CHANNELS;
or for (iChannel=0; iChannel<MAX_MIDI_CHANNELS ; iChannel++)
or such like
I almost never use hard coded numbers in the code itself, except, 0 and 1. Actually that's a good rule of thumb, look through the code, do you see a number there apart from 0 and 1.
If so, there is a fair chance you can help make the code more readable and maintainable by replacing it by a #defined constant, or whatever is the equivalent in our language.
This makes it far more readable, also to check for consistency. And e.g. in my program I also have another notion of a Part, and another notion of a Layer - and the number of parts is 16 also, but doesn't need to be tied down to the number of channels.
DON'T BE AFRAID TO TRY A CHANGE THE WHOLE ARCHITECTURE OF YOUR PROGRAM
I've done this several times and was really nervous first time I did it. But - is surprising how few problems you can have if it is a good well thought out change.
The thing to do is - to first make sure everything is backed up and you can roll back easily. Then just say "Okay I'll have a go at this, spend a couple of days on it and see how it goes"
Then dive in, be brave, change it, and see what it looks like.
You might then find that it is not nearly as good as you expected it to be, or it causes numerous problems. I didn't say you have to accept your change, just not to be afraid to try it out.
If so, just roll back again.
But you might find it makes a huge difference and is so good it is an obvious change to make. If so then keep with the change.
So - from time to time, can give this a go, just see what it looks like if you change the architecture, does this help? And roll back if it doesn't help or seems likely to lead to problems.
KNOW HOW AND WHEN TO COMMENT
So many beginner programmers have no idea how to comment their code, and add comments that just repeat things you can see at a glance from the code already.
Especially if you have long variable names and function names also, then there may not be that much comment needed to explain what this and that is actually doing.
But if you have like a hundred lines of code, doing some carefully optimized algorithm, or you needed to puzzle over how to do it for several days and finally got it - or if you had a really tricky bug to fix, e.g., by way of example - which required a not very obvious but clever one line change in the code to sort it out - well when you are finished with the coding when it finally works without bugs - tendency to heave a sigh of relief and go on to your next challenge or bug fix.
But - that is the best moment to do the commenting. Get into the habit of doing that. Think, what is there about this code I just wrote that might be not so easy for me to understand two or five or more years from now? What did I have to search and puzzle over to get it working. What references did I need to look up, what online example code?
If it is a bug fix - what did I learn while solving this bug, which might help future coders? What is there about my change that is ingenious perhaps - but not going to be immediately clear and easy to understand by a future coder? Did the original version of the code cause some unexpected surprising issue with the program? Whatever that is - write that down in the code as a comment.
That's exactly the sort of thing that needs comments in the code to make sure a future coder, which could be yourself, doesn't undo your good work, e.g. making it simpler as they think, and reverting to the buggy code in the process.
Put all of that into the comments about that section of code. It seems a bind to do it because you know all that and why bother to write down what you already know. But five or ten years from now, you or your coworkers or whoever maintains your code later on will be grateful for it.
Your code should be easy to understand, not like a kind of tricky crossword puzzle for future coders reading it to solve.
When you want to do something but can't code it right away, put it into a wish list. When users ask for some feature, do the same.
This is great for communication with the end users too. They can see that their wish is in the list and you haven't forgotten it.
Then - some time down the road you might be able to code some of the wishes. Then - you might find, you can code several of them at once in the same code. Having that list of diverse wishes to code for gives you a good idea of what exactly you need to build into the code, what flexibility you need, what needs to be easy to change and what doesn't matter to the end user.
I also add notes to each wish right away about how easy or hard it is, ideas about how I might code it and so on - and update those if new ideas arise.
It's easy to do, and can make a huge difference later on.
Will give an idea of the sort of thing you can do.
You can have a private more techy wish list as well of course, this is a version designed to be readable by both coder and the end user.
The way I do that is I have a short term continuously rolling bugs list, and minor feature wishes and ideas for the UI that I just jot down as the ideas occur, or as bugs happen and then work through it coding and fixing, moving things into a "done list", usually with a cycle of a few days between adding things to the list and fixing or coding them.
Some of those then need more work and end up in longer term lists and may end up eventually in wish lists for the future, public or private.
DON'T JUST DIVE IN AND CODE USING THE FIRST IDEA THAT COMES TO MIND
Again - well depends - some things are totally routine, or you've done them hundreds of times, or is obvious how to do it.
But otherwise, as others have said here - there might be many ways to do it.
Spend a few hours just thinking about it not putting down a single line of code. Go for a walk, listen to music, disengage your mind a bit and then come back to it, Write ideas on paper, write out ideas in pseudo code, draw diagrams, or whatever it is.
Often my ideas start with the UI, so I sketch out dialogs or UI elements, or just think about them in my mind, how best to arrange them. Starting with the user experience like that often leads to new ideas about how to code it which better matches what the user expects - and so - makes it easier to code the program also.
I'm not the best exponent of these principles, I'd do well to listen to some of these recommendations more myself :). But I think, hopefully useful guidelines to help programmers not fall into some of the mistakes I made myself.