If you were asked to answer the question: What is the difference between a bad coder, a mediocre, and a great coder, how would you reply? You might say that a bad coder is someone who writes code that doesn't work, a mediocre coder is someone who writes code that works, but no one can read it, and a great coder is someone who writes code that works and others can understand what it does. About 20 years ago I was on a project which had two code bases written in assembly language. Those of you who have programmed assembly code know how hard it can be to read. One code base was the equivalent of spaghetti C code. It had variable names that had no meaning. There were random gotos (jumps) throughout the code. There was no rhyme or reason to the design. The other code base, also in assembly, was written with variables that had meaning. They were words describing the state of a function. They had declarative tables defining state. The code was well commented and well documented. You could actually look at the assembly code and say, "Hey! I understand exactly what that is doing." The first code base worked, but I, the programmer who had to read the code became quickly frustrated. As a result my productivity on the first code base was slow and possibly buggy. The second code base not only worked, but was easy to change, add to and expand upon with confidence. These two assembly code projects, written by completely different programmers, clearly illustrated the difference between the work of a mediocre programmer and a great programmer.
Robert Martin's book Clean Code - A Handbook of Agile Software Craftsmanship, is a follow up to the book, Agile Software Development, Principles, Patterns, and Practices. Both books are excellent reads for those programmers wishing to take their code to the next level. The examples for Clean Code are in java, while the examples for Agile Software Development, Principles, Patterns, and Practices are in C#. Many of the principles described in Agile Software Developmen Principles are repeated heavily in Clean Code. I'll describe some of the principles in the pages that follow.
Robert Martin on Functions
To summarize, here are Martin's basic premise on how to name functions: Functions should be small, use meaningful names, and have no more than 2 parameters. Martin's decree on functions falls in line with his view of comments. He feels comments should almost be non-existent and the function names should describe themselves. Comments should only be used to describe intent or to clarify when clarification is needed.
Robert Martin on Classes
Martin most harps upon the fact that the classes should be small and must follow the Single Responsibility Principle (SRP), described in his first book. The Single Responsibility Principle states that a class should have only one reason to change. Martin equates "one reason to change" with "one responsibility". To illustrate his point, Martin shows a class that inherits from a GUI component and also tracks version information. This class has two reasons to change. The version info can change, regardless if the GUI has changed or not. He also goes on to mention that SRP is one of the principles that is most abused by mediocre coders. If you are a seasoned developer, you may have come across a class that has too many unrelated things. What's nice about the book is it describes why you need to follow this principle and how you can take existing code and make it follow this principle by refactoring.
Martin gives good examples of what a poor class or function looks like and how to refactor and rename variables to make the code more readable and more maintainable.
Test Driven Development
Martin, as are other agile proponents, are heavily into Test Driven Development (or TDD). Martin describes the three laws of TDD basically saying you need to write a unit tests in tandem with the production code. I think the laws can be improved by stating more specifically as to what exactly you are testing. Martin says the tests in TDD are testing production code, but what does that mean? Does it mean he is writing unit tests against a function? A class? A use case? I think the three laws need to be a little clearer.
In my experience, unit tests are centered around a test instance of a class. Unit tests are written around different functions inside the class and test different constraints of the function or the results of the function. So perhaps this is what Martin is getting at with the three laws.
Also tests can either test the state of the object or it can test the ability to interact as expected with mock objects. Martin doesn't really talk about these different models.
Martin, however, does stress the importance of TDD, and gives examples through JUnit of how to write good unit tests against your code.
Martin describes the importance of dependency injection and using an IoC Container (Inversion of control container). An IoC container allows you to utilize a framework, such as Spring (Unity in the .NET world), to hook up the dependencies of your objects upon construction. He tells how IoC moves the responsibility of constructing objects away from the objects themselves, therefore adhering well to SRP. The nice thing about frameworks like Spring is you can describe all your dependencies in an XML file and easily manipulate the type of construction and dependencies of construction of different classes. Inside this file you can also swap in and out different concrete types. This is a powerful feature, because inside your code, you may just be passing in an interface into a constructor, but the IoC container describes which of the concrete classes is in the underlying object. An example of the power of dependency injection is say you wanted to provide data to a particular class through a data provider. You could create a constructor in your class that took an interface for all data providers. You could then, for example, change to a different data provider in your IoC container. The code for the classes receiving the data provider in their constructor (as an interface), would not have to change as long as the data provider you swapped out had the same interface.
Martin does have a great section called Smells and Heuristics describing bad code to look for (although I found it ironic that he named one of the sections of the book General after describing in his book that it was bad to give meaningless names to classes, and here he is giving a pretty meaningless name to a section of his book). In any case, the code smells, as they are called, are gems because we all have come across them, and many of have certainly coded them. Here are some of them you might recognize
1) Dead Code - Advice: Remove it (use version control to track it)
2) Output Arguments - Advice: Put them in the class fields
3) Flag (Boolean) Arguments - Breaks SRP, Advice split the function in two.
4) Functions should do one thing - Advice: Break them up so that each function does one thing
5) Avoid negative conditionals.
6) Don't pass null arguements
Also Martin gives some good advice on heuristics to follow when coding
7) Choose names at the appropriate level of abstraction
8) Prefer polymorphism to if/else or switch case
9) Use constants instead of hard coded numbers
10) Encapsulate conditionals
11) Local variables should be declared directly above statements about to use them
12) Use descriptive names (this statement is made throughout the book in about 10 different ways, but can't be said enough. From code I've seen, following this rule alone can greatly improve how others view you as a coder.
Robert Martin's book Clean Code provides a great set of guidelines if you are a professional coder. If you already code within the boundaries of Martin's suggestions, then you are already a great coder. If you find that you do not adhere to a lot of these principles, but you "see the light" from the suggestions in the book, then you have taken the first steps to becoming a great coder that other coders will gain a new respect for. But most importantly, if you follow the suggestions inside the book, your job will become easier because your code will be easier to maintain, will be less buggy, and become more readable. You'll also be able to extend your code more easily, and even better, others will be able to build upon the strong structure you've provided.