I'm a novice programmer and often when I'm working on my own projects, I always get the feeling that the design of my code is not the best it could be, and I hate this feeling. I end up spending time looking things up, but then I become overwhelmed easily with many details, such as design patterns to choose from and when to use an abstract class or an interface. Am I supposed to try and learn a little bit of everything at once?
A few suggestions:
Use encapsulation to manage complexity by separating functionality into distinct building blocks. Prove each block works (via unit tests), and you can use it without being concerned about its inner details.
Learn and study software patterns. Software patterns are tried and proven methods for performing certain common, well-known tasks.
Study and understand data structures. Learn the appropriate uses and performance characteristics for each type of data structure.
Know your programming language well, its strengths and weaknesses, and how to best use its features.
You don't have to know all of this at once, but you should study all of it over time.
My advice is: stop worrying.
Experience is the best teacher, and you don't get experience if you don't write code. Also, badly designed code that is written is better than great design that is not.
So, write more code. Finish your projects. That feeling that the code is not ideal is probably right. And you'll probably have problems with this code. And when you have these problems, then you'd learn why exactly it was bad. You'd learn way more from firsthand experience than from "looking things up".
Also, don't hope that this feeling of "code smell" will ever go away. As you are getting better, you'll fix some problems, but start noticing new, more obscure/advanced ones.
This is a common problem with beginning programmers. Dont paralyze yourself by thinking everything has to be perfect. Thats the surest way to never finish a project. One of the most important skills to learn as a developer is the difference between perfect and good enough. Accept that every system you create can be improved upon. Focus on finishing your projects. After you finish, you can go back and improve on them. Thats why we have version 2.0's, after all.
My best advice is to focus on the fundamentals such as the list Robert Harvey suggested. Software development is a complex monster that takes years to even get remotely good at, especially in the topic of good interface design. It is really hard to appreciate many aspect of software development without first experiencing them. Even something as basic as commenting code can be under appreciated. From day one, you are taught to write well documented code. I'll admit that it wasn't until I was really bit in a$$ attempting understand code that I wrote months ago before I truly appreciated the value of good comments. The same can be said for many programing concepts. For example, data encapsulation, low coupled modules and crisp clean interfaces.
The most valuable resource that I have encounter is my co-workers. You are going to bad write code. Just accept that. It is what you do to make sure that you write better code over time that defines you as a programmer. For example, when I first started working, my company didn't have any sort of formal code or design review procedures. I took it upon myself to subject my work to the criticism of my more senior co-workers and to be honest, I felt like an idiot for better part of my first year working.
Software development is an on going learning experience. Ask tons of questions, have your code reviewed, understand the why's of the suggestions more senior people give, don't be afraid to questions the validity of the suggestions more senior developers give and most of all don't be afraid to be wrong. Eventually the intimation factor or sense of being overwhelmed fads. For the record...learning curves suck.
- First: Refactoring (it will still smell but will be a little more organized)
- Second: See if you can use some Design Patter to make the refactored pieces match your logic.
- Third: when things start looking better, remember the time you spent doing the first and second step. This way when you write some new feature, you'll think about then while your doing it and not as another process.
Take a look at the book Refactoring: Improving The Design Of Existing Code, by Martin Fowler. The first thing you should do is refactor your code, in order to improve code readability and reduce complexity to improve the maintability of it.
When you refactor your code, you're already using Design Patterns, Encapsulating code, etc.
This is one of the best books I've ever read about this topic. It provides lots of useful recipes.
A good resource is The Pragmatic Programmer. The chapter on "Broken Windows" describes where you see yourself. The short and pithy response is to fix the problems.
When you start fixing your design, it helps to understand what you don't like about it. It's easy to come up with the vague answers like "it just goes all over the place" or "why did I do that there?". But take the time to see if there are any common patterns that you used.
- Good design will reuse a small number of concepts throughout the codebase (the ideal is one concept, but in practice you may need a couple more)
- A good design will make it easy to figure out where to fix problems (DRY principle, SRP principle)
- A good design will have good error reporting (related to the point above, but called out as a separate item because it is an often overlooked aspect)
Once you figure out where you want to go, take small, easily reversable steps to get there (i.e. this is what Refactoring is about). Every time you improve your code, consider the impact on the rest of the code. Did you make things better or worse? This at least is my approach to bringing order to chaos.
If you already have some experience in programming, why don't you study some open source projects that have clean code? You could look into THIS question from SO which has some relevant links.
Also, design patterns is a must know -- think about it, the whole idea of having patterns is to solve known problems without re-inventing the wheel or writing buggy code.
Finally, looks like you need some dose of functional programming to clear your head. Look into Haskell or Ocaml for a start.
If you're not a dangerous monster, you should find a so-called friend, who can review your code, and vice versa. Also, if you making things, which will be revisited, or just overseen by others, it's a good pression to do it better way.
And don't forget, programming begins before coding, always revisit your ideas, plans. If your plan is bad, it's a joyful act to throw it out: you have just saved the frustration of throwing out a bunch of code (and the time of its creation) based on a bad plan.
My advice is take each of the smells seriously and try to fix it. There are many good books on the topic (Clean code and GOOS are the best IMHO). But more than books go to conferences to hear and discuss with other people and on online comunities (mailing list, groups). Still better try to join your local xxug (dotnetug, jug, xpug, etc.) or found one.
Discuss with other programmers is the only way I know to really improve (unless you're luckily enough to work together with other dedicated programmers).