I feel that I am good at writing code in bits and pieces, but my designs really suck. The question is, how do I improve my designs - and in turn become a better designer?

I think schools and colleges do a good job of teaching people how to become good at mathematical problem solving, but let's admit the fact that most applications created at school are generally around 1000 - 2000 lines long, which means that it is mostly an academic exercise which doesn't reflect the complexity of real world software - on the order of a few hundred thousand to millions of lines of code. 

This is where I believe that even projects like topcoder / project euler also won't be of much help, they might sharpen your mathematical problem solving ability - but you might become an academic programmer; someone who is more interested in the nice, clean stuff, who is utterly un-interested in the day to day mundane and hairy stuff that most application programmers deal with.

So my question is how do I improve my design skills? That is, the ability to design small/medium scale applications that will go into a few thousand of lines of code? How can I learn design skills that will help me build a better html editor kit, or some graphics program like gimp?

The only way to become really good at something is to try, fail spectacularly, try again, fail again a little less than before, and over time develop the experience to recognize what causes your failures so that you can manage potential failure situations later on. This is as true of learning to play a musical instrument, drive a car, or earn some serious PWN-age in your favourite first person shooter, as it is of learning any aspect of software development.

There are no real shortcuts, but there are things you can do to avoid having problems get out of hand while you are gaining experience. 


Identify a good mentor. There is nothing better than being able to talk about your issues with someone who has already paid their dues. Guidance is a great way to help fast-track learning.
Read, read some more, practice what you've been reading, and repeat for the entire lifetime of your career. I've been doing this stuff for more than 20 years, and I still get a kick out learning something new every day. Learn not just about up front design, but also emergent design, testing, best practices, processes and methodologies. All have varying degrees of impact on how your designs will emerge, take shape, and more importantly, how they last over time.
Find time to tinker. Either get involved with a skunkwork project through your workplace, or practice on your own time. This goes hand-in-hand with your reading, by putting your new knowledge into practice, and seeing how such things will work. This is also the stuff that makes for a good discussion with your mentor.
Get involved with something technical outside of your workplace. This could be a project, or a forum. Something that will allow you to test out your theories and ideas outside of your immediate circle of peers in order to maintain a fresh perspective on things.
Be patient. Recognize that earning experience takes time, and learn to accept that you need to back off for a while in order to learn why and where you have failed.
Keep a diary or a blog of your tasks, your thoughts, your failures and your successes.  This isn't strictly necessary, however I have found that it can be of great benefit to you to see how you have developed over time, how your skills have grown and your thoughts have changed.  I come back to my own journals every few months and look at the stuff I wrote 4-5 years ago. It's a real eye-opener discovering just how much I'd learned in that time. It's also a reminder that I got things wrong from time to time. It's a healthy reminder that helps me improve.

