This is going to sound cliche, however it doesn't hurt to remind ourselves of the obvious fact that everyone is different from everyone else. Understanding these differences and how you, specifically, deviate from your peers will help you become a better software designer.

The most overmentioned fact related to this is that you, as a programmer, have a completely different understanding of the software that you create than your users do. It goes without saying that as the creator of a given thing you have intimate knowledge of its details that no other mortal but you can possibly have; therefore you have a complete mental model of the software whereas your users can only work with an inferred mental model.

"What is this insanity?" you ask yourself (as I force my thoughts into your mind via Internet waves), "I already knew that." Well, that's what you should be thinking, anyway. However, it's pretty obvious from the state of software that these thoughts never enter designers' minds when they're doing what they tell themselves they do best. That's how we end up with terrible designs.

You need to know three things in order to not completely fail at designing something user-friendly: who your users are, how they see your software and yourself. The first of these is the easiest. Your software is designed with a particular target audience in mind. Depending on what that audience is your design needs to accomodate them. For example, if your userbase is astrophysicists then you can generally rely on using terse, astrophysicisty words in order to simplify the descriptions of things; you can use the words "Schwarzschild radius" without having to link to Wikipedia to explain it first in order to be understood. If your userbase is the Internet then you have to make sure that your design is usable by anyone from any walk of life.

Knowing how your users understand your software is the fundamental art of usability. The goal of your software should be to be as easy to use as possible by as many people as possible within your target audience. A big part of your software's usability is the visibility of its functionality. There's entire book on this subject so I'm just going to paraphrase the most relevant part: it's easier to use an object (be it a physical object or a virtual one on a screen) if its functionality is clearly visible, its interactive parts map obviously to natural actions and its actual behaviour corresponds with how it looks like it should behave. The first of these is just a matter of making functions obvious, like a big button labeled "stop". The second is making things interactive in the most appropriate way, like making a button look like a button instead of a textbox. The last one is more subtle and demands its own paragraph!

When people use things (whatever those things may be) they come up with explanations of how they work. (E.g. a car goes forward when you press the gas pedal, so pressing the gas pedal must turn on a light to tell a gnome to shovel more coal into the boiler to make the car move.) The more closely a user's mental model resembles the object's actual behaviour, the more usable that user will find the object. So the trick, then, is to make the way the object works as simple and as obvious as possible. If you have a big button labeled "stop", that button had better actually stop something, because it looks like it should.

Determining if your design's outward appearance allows users to come up with the right mental model for the way your software works is as hard as it sounds. You have to use regular usability testing to observe how the user seems to be figuring the software out. If you actually ask the user, the user might not be able to describe it properly so you can't rely solely on interrogating the user after the fact. Some users might be better at articulating how they understand your software than others, so it's a good idea to determine how good they are at describing how things work when going over their answers (but be sure to do this evaluation after the test itself in case you tip them off to what you're looking for).

This is also why using your own software yourself (a concept known as dogfooding) doesn't work from a usability perspective. Dogfooding is good at finding features your software is missing, but since you already have the correct mental model of how the software works you can't dogfood your way to an easy-to-learn user experience. You need to test with people who do not work on the software being tested.

Bringing this all together is the final of the three things you need to know to not suck: yourself. Once you start to test your user interfaces with real users (unless you managed to nail it perfectly every time) you'll find that there are some situations in which you tend to fail consistently. Maybe it's colour, or button positioning or use of common UI objects in novel but confusing ways. Whatever it is you need to know your own limitations with respect to designing user interfaces. Remember that you are designing for others rather than yourself, so when you get an idea that is similar to something you've failed at before, talk to other people about it before you dive in and make the same mistake over and over again.

The bottom line is to not use yourself as the bottom line of usability decisions. Get people to actually use your software, then talk to them about how they think it works to make sure their understanding of its behaviour is as correct as possible. Learn from your mistakes to know where your internal ideas of usable deviate the most from what the majority of users from your target audience consider usable. Bounce ideas off of other people when you're working in an area that you've messed up in before. Don't be afraid to try new things; just make sure that when you mess up you don't give up.