Like beauty, quality is often in the eye of the beholder, and because perspective and values matter in how code is judged, it can be hard to nail down a proper definition for code quality with which everyone would agree.
For example, often a client will list code being “optimized” as a requirement. Sounds good, but what does that really mean? What should it mean?
For many, “optimized” means “speed.” The code must be fast and performant. But that is not the only interpretation. In other situations, optimized code means that the code must be easily maintained or portable to other platforms. In fact there are as many ways to interpret this word as there are dimensions to measure the quality of code. It all comes down to what is valued by those who will ultimately own the result.
This means that in many instances, the communications that describe the goal of any project are often more important than the technology ultimately chosen to implement it. This is especially true in the .NET development world because assumptions can affect where a project begins and what compromises are needed to get it done well enough to be accepted, or fast enough to hit a deliverable.
Code developed with any language on any framework against any platform requires this clear communication to have a chance to meet expectations, and there are other factors at work as well. So you have to ask yourself, what matters to you? What does optimized mean for your project? Think about that while we will cover the things that most agree lead to or define low-quality code.
The foundation matters
When setting out to construct anything, the foundation matters. Marketing, building construction and even literature succeed most when the opening or foundation is of high quality. Quality code has an even greater dependence in this regard since, in most cases, you are not writing machine language. We all depend on many abstraction layers, for better or worse, to do everything.
As far as foundations go, the .NET Framework is a good pick these days. It is mature and roundly tested for all manner of purposes. It is hard to imagine a use (suitable to a framework) that it has not addressed over the last decade.
This argument for well-worn code being higher in quality is something the component vendors emphasize as well, and it makes sense. There is a reason that adoption follows a curve where early adopters are followed at a distance by the masses.#!At the BUILD conference in early April, Microsoft committed to open-source many libraries, including much of .NET itself. Never before have .NET developers had this much access to the guts of the platform, and there is hope that this act will increase the quality, security and stability of the .NET platform in the long run. But for now, .NET developers have to rely on the current quality of the platform. In most cases, this is a good dependency: .NET is well proven and has improved over several major iterations when we focus on the Base Class Libraries.
Other parts of .NET are less well worn and are even controversial for some. For example, Microsoft has never produced a data layer it did not ultimately replace. Even Entity Framework, the latest iteration of tools designed to make the data layer easy, has its detractors due to problems at scale and in certain high-volume situations. If the Entity Framework produces SQL under the covers that does not perform well in critical situations, that is definitely a knock on quality for the project. While not a concern for most, this serves as proof that the details matter.
The choice of Web service carrier is another area for .NET developers where there are choices, and the wrong choice can affect perceived quality of the project and the code. Would the goals of a project be better served by using Web API or SOAP via WCF? The answer depends on the details of the implementation and the requirements.
The bright spot in all of this is that, more often than not, the frameworks of .NET contribute positively to code quality because they handle so much of the grunt work that developers can concentrate on keeping their parts of the code up to snuff. Getting the architecture right raises code quality, and these things raise architectural more questions to developers than ever before.
The software craftsmanship movement
The first person who taught me about software craftsmanship is Steve Smith. He is an experienced trainer and development mentor who has published courses with Pluralsight and is very passionate about quality.
Software development as a profession has grown in ways unlike almost anything else in history. Only in the field of software development can someone with absolutely zero formal training command respect of those with advanced degrees in the subject and even rise to the top of the field.
One big reason for this is that for most of the last decade, there just have not been enough capable developers. However, the profession does lend itself to allowing people to prove themselves very quickly.
Getting the degree does not insulate developers from making bad judgments or being lazy, and with so many self-taught developers at work, the software craftsmanship movement provides guidance and resources to aspire toward continual improvements.
Bruce Backa, CEO of NTP Software, has managed a great many developers over the years. When asked why the software craftsmanship movement was needed, he explained it like this: “Most people are so happy when they figure out a solution to a problem that they immediately stop looking for alternative solutions and rush to implement.” He went on to explain that, “in most cases there are a number of possible solutions to any given problem, but even assuming a small number such as four, this means that there is only a 25% chance that the first one that comes to mind is the best solution.”
If you talk to any of the people like Smith who aspire to be a software craftsman, you realize that there is serious passion, but also an understanding that it cannot work if the devotees just browbeat everyone to not write junk code. After all, it is a movement driven by community rather than for profit. So it should come as no surprise that it has a manifesto to define the goals of software craftsmanship. The manifesto and its chief demands are reminders to not only do the job, but to also do it well.
People who study classical martial arts will know that a kata is a practice that you do that teaches you the movements for style of combat that makes up that martial art. The idea is that doing the kata will help you master the techniques and prepare you to apply them when needed in a confrontation. The word “kata” in Japanese means “form” and is an alien concept to most developers, though after understanding the intent, the average developer does warm to the idea.
SoftwareCraftsmanship.org hosts videos of code katas with straightforward tasks such as converting numbers to Roman numerals. The point of these exercises is to show correct approaches rather than to create code that will be used in an actual program. These would be great homework assignments for any aspiring developer who wants to produce quality code. (To hear more on Smith’s views on software craftsmanship check out the .NET Rocks interview on the subject he did back in mid-November.)#!Code smell
“It seemed like a good idea at the time…” is the post facto justification for many blunders, with common threads of not thinking about possible ramifications or just taking short cuts. Code smell represents the coding version of this often-heard lament.
Code smell is the term used by software craftsmen for things that seem like a good idea when a problem is not well understood or when essential use cases are not considered. Many of the cardinal sins of programming, including many deadly security mistakes, spring from this lack of foresight, but they can also come from rushing to get something to work in spite of understanding that the approach has issues.
This means that even experienced developers often produce code of low quality. In one such case, technical debt is incurred when expediency overrides doing things correctly. All software in the real world accumulates some technical debt as it matures. In some cases the gamble pays off if the product never matures to a place where these shortcuts need to be remediated, but in these cases you can be actually betting against your own success. The best approach to code smell is to avoid it and keep the books clear of technical debt, but if the debt needs to be incurred, then make a plan for going back later to do it right.
Code smells are also on the list of pet peeves for many developers. For example, a personal favorite has to do with not maintaining comments in code. It sounds like a trivial matter, and many of the code smells appear that way at first glance. But not maintaining comments often confuses the next developer who has to look at the code. Since developers naturally take comments at face value, it can take hours to fix code that behaves differently from what the comments seem to suggest. Not having comments is bad, but it’s better than comments that lead to confusion.
Here I’ve shown a sample procedure written in C# that presents a few code smells, including useless comments for code that no longer applies, old commented-out code, log parameter lists, and uncommunicative names. Each of these items can get your project in trouble by causing bugs, making the code harder to understand and generally slowing things down.
The uncommunicative names smell has to do with naming things such that someone who looks at the code won’t know what should happen. In our example, the method name of “ContactStuff” only hints at what this procedure is trying to accomplish. Any developer looking at it would have to look at the procedure itself to figure it out, which would slow things down.
Removing code smells is the best way to improve your code, all other things being equal. To learn more about how to do this, Smith has done a highly rated eight-hour course for Pluralsight named “Refactoring Fundamentals” that thoroughly covers how to address code smells and reduce technical debt by refactoring code properly. It is available with a subscription (or free trial) with Pluralsight. This is a great place to start for anyone looking to embrace the software craftsmanship movement and improve their code in the process.#!Patterns and anti-patterns
A design pattern shows you how you should be doing things and how components should be put together. And, by the same token, an anti-pattern talks about what you should not be doing and how things should not be put together.
Design patterns have been extremely helpful over the years, with Microsoft documenting them regularly via their Patterns and Practices group. The evolution of ASP.NET has been greatly influenced by the popularity of design patterns like ASP.NET MVC being based on the Model-View-Controller design pattern. These guides are meant to show developers how things are supposed to work, and they can illustrate things such as the best way to implement logging on a high-volume system without hurting performance, or how to deal with claims-based identity and access control.
Anti-patterns tend to be shorter than patterns and come across as rules, and can often be technology- or even language-dependent. For example, in the C# language, the Boolean data type exists so Boolean comparisons can be done directly rather than comparing it to true or false.
Another anti-pattern is to avoid looking through a list of items in a loop when you can just ask for the item directly. The reason you might think you need the loop is to avoid trying to access something that does not actually exist (such as a file), but in those cases the logic goes that you can catch the exception if the file does not exist.
Often it will be hard to tell the difference between an anti-pattern and a code smell, and in fact the difference is somewhat semantic. Peter Ritchie addressed the issue in a blog post, saying that anti-patterns are “recognizable solutions (patterns) that don’t work in at least one way and should never be used,” and he goes on to point out that “code smells, on the other hand, are defined as ‘…a hint that something might be wrong, not a certainty.’ ”
A popular video that made the rounds at the BUILD Conference called “The Expert” depicts a hapless engineer facing a room full of clueless stakeholders demanding impossible results. While exaggerated, these are precisely the kinds of things that must be stamped out early in a project to give the resulting code any chance of being acceptable.
Ultimately the best way to keep up code quality on a .NET project is to keep the requirements reasonable. Every other industry has realized this imperative, which is why we have laws that keep truckers from driving through the night on no sleep, and why there are studies required before medicines and surgical techniques are allowed. Winging it does not produce good, solid results, and code is no different.
Some of the rules that software craftsmanship seems to demand are less vital for an individual programmer who is not working with a team, but things change and assumptions are deadly, including assuming that no other developers will ever see the code being developed.
It is important to not confuse issues of code quality with controversies that are more akin to disagreements over religion. There are some issues that are hot-button items for many passionate people, with language choice and naming conventions being prominent examples. There are still some people who will disparage anything written in a language other than their chosen language.
More often than not it is Visual Basic that is getting heat from a small cadre of C# developers, though in recent years that has cooled down quite a bit. For naming conventions, there are some well-worn examples of what works and what does not, but the key is to focus on the code itself, since after it goes through the compiler, the names do not matter at all.
Perhaps the hardest metric to satisfy for quality code lies in the area of performance. Users expect systems to be faster and faster to the point that instant is just good enough, and anything less is too slow. We now live in a world where the speed of light is actually getting in the way of stock market transactions, which is leading to trading companies competing to get their servers closer to the trading servers.
The laws of physics are literally the latest barrier in these instances. When developers set out to tackle a task that has performance as a component for measuring quality, the first critical step is determining the acceptable ranges. For example, if one is setting out to maintain a cache from remote servers, there are definite mechanisms to ensure maximum speed. But the responsiveness of the underlying network is usually an unalterable factor that must be taken into consideration.
Often developers and their project managers are brought to task to fix or justify their “slow code” when in fact the blame lies in the infrastructure. Companies like PreEmptive provide tools that help with this situation. Its Analytics product tracks everything your code is doing, and it can help locate where the delays are coming from so that slow code can be addressed and slow infrastructure can be called out when it is causing delays.
Too many projects are deemed failures because the results are too slow or not performant enough, when in fact the unspoken expectations for performance were never raised in a rational form at the start. It is important to understand that code quality often depends on prior agreement on what success looks like, and it can be completely separate from the code itself in certain areas.