Some months ago, I answered to a job interview question which was more or less like: "Suppose you have 20 minutes to talk to an audience of junior developers about the lessons you have learned from your software development experience. Summarise, in three points, what a good developer should do. What would be your advice?"
The following was my answer.
First, when you write your code don't start from the implementation, but start from the client code. Today it is popular to speak about Test Driven Development, and how writing test code first (which is client code), drives you to a better design. In the same way you can write your back-end services starting from the front-end, from how the user interacts with the UI, and letting the implementation details be driven from there. The internal design should emerge from the use cases, not viceversa. So, testing software early not only drives more reliable applications but, importantly, also leads to much better code: easier to understand, to extend and maintain. It is not a detail: in the software industry the code is your product!
I appreciate a developer who writes code which is easy to follow, more than developers who can easily understand messy code. Messy code comes from the bottom-up approach. The ability to deal with messy code, comes from the habit to write and deal with it. Real good developers are the ones who have developed a fine sense of the code smell. A good developer does not write code unless it is strictly necessary, and this is much easier if you start from the abstract idea.
Imagining the "model" at first means that you have to predict what you are gonna need. It brings in constraints, and requires you to take decisions, which will likely reveal to be wrong later.
I learnt this when I started to work in Eclipse. In Eclipse you use a variable (which doesn't exist yet!) in your method, Eclipse underscores it in red to say that there is a compilation error, then you do a "quick fix" and let the IDE declare the variable for you. You call a method which does not yet exist, and let the IDE implement the stub. This reverses the way you think. You will never write a useless method or variable again (at least this risk will be drastically reduced, and with some discipline you can keep things clean more easily).
Instead of thinking before on the details, you can focus on your business and write code that explains what your method is doing. And only after do you write the code specifying how to perform the functionality.
Starting to focus on a more abstract level helps make better applications for the users, and the code quality will also benefit.
Wikipedia says that the "bottom-up programming approach which is common in object-oriented languages such as C++ or Java". I agree with the guy who is defining this a «complete utter bull dung».
Writing readable code
Try to keep your code speaking, let the code be self explanatory, it's not that difficult... if you find yourself writing too many comments to explain what an algorithm is doing, that probably means that your code is not readable. Comment in source code is documentation for developers; but the code itself, if it is understandable by another developer, is the best documentation. Avoid putting logs everywhere: it makes the code confusing, and difficult to maintain (how many times have code changed and logs do not reflect what's happening anymore?). Put log statements in the strategic points: logging is a part of your application and also that should be carefully designed and thought as a feature. Don't put "debugging" everywhere, logging != debugging. Debug with your IDE, and write tests; it's hardly the case when you can understand what went wrong just from trace logs.
Once the code is written, it is going to be read dozen of times, and this is why it is so important that code is easy to read. Personally I prefer code which is understandable and performs well, over code which is messy and (maybe) performs super-fast. Most of the time messy "optimized" code is slower than simpler and more straightforward code.
Handling properly error/exceptional conditions
It looks like this is one of the hardest things to learn for software developers. And it's the source of many bugs. It's simple as that: catch the exception you can manage, and let the other pass through. Avoid "catching-and-rethrowing", avoid exception swallowing, and other amenity: there are plenty of articles about things you'd better never do. This one is quite comprehensive: Exception Handling Antipatterns. Make sure your software not only works well when everything goes fine, but also give the proper messages when something bad happens. This will also reduce the need to dig into the log files just to discover that "a server is down" (when your application could just nicely tell that to the user, or inform the administrators!), and reduce the habit of having so much code for debug log statements.
Writing code in TDD also helps with this. Finally try to think "what could go wrong? and how my software will react?" before saying you've completed your tasks. Remember how do you feel when you get a cryptic blue screen, and how Windows gained the name to be a very buggy OS.
Don't become a bluescreen author.
I don't know if this is a good answer to the question. But it reflects quite well some of the things I feel very important when I write my code, and that's why I decided to write about this topic here.
If you are curious, the interviewer didn't hire me :).
What would be your answer?
What are your top three pieces of advice to make better software? Tell us, leaving a comment.