Clean code: general principles

We start series of articles about Clean Code conceptions, that are based on a famous book of R.Martin Clean Code: A Handbook of Agile Software Craftsmanship, classification of Urs Enzler from BBV and our experience. Code with examples given on C# language, but it could be suitable and transfered for most of all OOP languages. We explain each principle, rule and negative rule; provide our own comments where it makes sense to use it.

Why Clean Code

Clean code is set of positive and negative principles/rules, that allows to produce ideal code. Joke, for sure. Ideal code seems yesterday, but today some part requires refactoring. But refactoring is proccess of spending time, that reserved for another tasks.
Where is trueth? What's to do?
Ideal code doesn't exist. Every valueble part of code is possible to optimize, refactor. Each new day gives new code principles and improvements.
Code is clean if it can be understood easily – by everyone on the team. With understandability comes readability, changeability, extensibility and maintainability. All the things needed to keep a project going over a long time without accumulating up a large amount of technical debt.

Clean code: general principles

Writing clean code from the start in a project is an investment in keeping the cost of change as constant as possible throughout the lifecycle of a software product. Therefore, the initial cost of change is a bit higher when writing clean code (grey line) than quick and dirty programming (black line), but is paid back quite soon. Especially if you keep in mind that most of the cost has to be paid during maintenance of the software. Unclean code results in technical debt that increases over time if not refactored into clean code. There are other reasons leading to Technical Debt such as bad processes and lack of documentation, but unclean code is a major driver. As a result, your ability to respond to changes is reduced (red line).

Comment: it's obviously from the graph, that for short time projects no make sense spend a lot of time for following Clean Code principles. Typical example is prototyping.

In Clean Code, Bugs Cannot Hide

Most software defects are introduced when changing existing code. The reason behind this is that the developer changing the code cannot fully grasp the effects of the changes made. Clean code minimises the risk of introducing defects by making the code as easy to understand as possible.

Comment: One of metric that we use in evaluation developer works is "speed of fixing bugs". High speed shows correctly implemented/setup task and vice versa.

✓ Follow Standard Conventions

Coding-, architecture-, design guidelines (check them with tools).
Do you have code conventions? Do you follow achitecture principles? Do you have object oriented design guidelines? Do you use such tools as Resharper? As it was mentioned before code should be understood easily. It happens when each developer follows code conventions.

Example 1: names of classes, properties, methods - Pascal casing; name of parameters, internal method variables - camel casing. If some developer decides to use own style or doesn't follow any style - speed of implementation/maintainability will decrease.

Example 2: name of columns, based on Foreign key is typical "name of linked table>ID (ContactID, CustomerID, etc). If developer decides to name it with last small char as ContactId for DB it will be OK. But if code uses mechanism of autogeneration entities with rule "for all Entities, that have column ContactID -> generate something" we will receive logical error.

Example 3: It's very important to name classes, methods, properties correctly. Wrong naming could disorients other developers, decrease speed of implementation and arise bugs. If exists class File, properties Size or Path are not correct. File.Size and File.Path have multiplicity of interpretations. File size could be in bites, bytes, KB... File path could be absolute, relative. Much more better names are File.SizeInBytes and File.AbsolutePath.

Example 4: Sometimes we receive projects/code where find out amount of lines with comments comparable with amount of code lines.

///<summary>
/// Gets the bound object.
///</summary>
public object BoundObject { get; set; }
Obviously, that we have property BoundObject and could recognise, that object represents some bound object in the system. We don't need any additional comment in this case. The code itself is the best comment, only write comments when it’s really needed, don’t leave commented code lines.
Example 5: Some examples, where make sense to leave comments:
  • TODO something
  • Strange business logic, that unclear for understanding
  • Public API with requirement to generate documentation from comments

Comment: Coding style convention is rather static compare with architecture principles, that from project to project are different typically. We could share some code convention examples

✓ Keep it Simple, Stupid (KISS)

KISS is an acronym for "Keep it simple, stupid" as a design principle noted by the U.S. Navy in 1960. The KISS principle states that most systems work best if they are kept simple rather than made complicated; therefore simplicity should be a key goal in design and unnecessary complexity should be avoided. The phrase has been associated with aircraft engineer Kelly Johnson. Variations on the phrase include "keep it short and simple", "keep it simple and straightforward" and "keep it small and simple".

Every sizable system will contain a large amount of logic and complexity. The primary goal in managing such complexity is to organize it so that a developer knows where to look to find things and need only understand the directly affected complexity at any given time. In contrast, a system with larger, multipurpose classes always hampers us by insisting we wade through lots of things we don’t need to know right now.

Visual Studio could calculate code metrics. Menu ANALYZE -> Calculate code metrics. To identify source is simple or not need to check Cyclomatic Complexity. Low value is better.
Cyclomatic Complexity – Measures the structural complexity of the code. It is created by calculating the number of different code paths in the flow of the program. A program that has complex control flow will require more tests to achieve good code coverage and will be less maintainable.

Clean code: general principles

Ways to decrease Cyclomatic Complexity:
- Follow code convention with rule to have not more 50 rows in method
- Divide large methods to sub-methods and shift code to it
- Decrease conditional instructions amount (if else if)
- Use attributes, use AOP(aspect oriented programming)

Comment: it's really trueth! If exists task: project should be implemented in 1 month with connection to MS SQL server, no make sense to spend additional x days for creation communication with other RDBMS. No make sense to implement flexibility if customer/product owner doesn't ask about it. Current trend is NOSQL DB really needs in 1% from all scope projects(facebook, google, etc). Other 99% could cover over standard RDBMS servers. Development possibilities and implementation speed is much more lower with NOSQL. At this point a lot of new projects start with NOSQL. Why? If project will be successfull from business point, appears budget and task for adoptation to new challenges in future. But if resolve great challenges from the start and spend twice more time on it - large possibility to receive business FAIL from the start.

✓ Boy Scout Rule

It’s not enough to write the code well. The code has to be kept clean over time. We’ve all seen code rot and degrade as time passes. So we must take an active role in preventing this degradation.

The Boy Scouts of America have a simple rule that we can apply to our profession.
Leave the campground cleaner than you found it.

If we all checked-in our code a little cleaner than when we checked it out, the code simply could not rot. The cleanup doesn’t have to be something big. Change one variable name for the better, break up one function that’s a little too large, eliminate one small bit of duplication, clean up one composite if statement. Can you imagine working on a project where the code simply got better as time passed? Do you believe that any other option is professional? Indeed, isn’t continuous improvement an intrinsic part of professionalism?

Comment: one of characteristic of developer seniority level is "code should become better after code modification(bug fixing, adding new future, etc)."

✓ Root Cause Analysis

Always look for the root cause of a problem. Otherwise, it will get you again. Root cause analysis is a method of problem solving used for identifying the root causes of faults or problems

A factor is considered a root cause if removal thereof from the problem fault-sequence prevents the final undesirable event from recurring; whereas a causal factor is one that affects an event's outcome, but is not a root cause. Though removing a causal factor can benefit an outcome, it does not prevent its recurrence within certainty.

General principles of root cause analysis:

  • The primary aim of root cause analysis is: to identify the factors that resulted in the nature, the magnitude, the location, and the timing of the harmful outcomes (consequences) of one or more past events; to determine what behaviors, actions, inactions, or conditions need to be changed; to prevent recurrence of similar harmful outcomes; and to identify lessons that may promote the achievement of better consequences. ("Success" is defined as the near-certain prevention of recurrence.)
  • To be effective, root cause analysis must be performed systematically, usually as part of an investigation, with conclusions and root causes that are identified backed up by documented evidence. A team effort is typically required.
  • There may be more than one root cause for an event or a problem, wherefore the difficult part is demonstrating the persistence and sustaining the effort required to determine them
  • The purpose of identifying all solutions to a problem is to prevent recurrence at lowest cost in the simplest way. If there are alternatives that are equally effective, then the simplest or lowest cost approach is preferred.
  • The root causes identified will depend on the way in which the problem or event is defined. Effective problem statements and event descriptions (as failures, for example) are helpful and usually required to ensure the execution of appropriate analyses.

Comment: The success of task execution depends fully from how task was setup.

Next article is about Smells: Rigidity, Fragility, Immobility, Viscosity of Design, Viscosity of Environment, Needless Complexity, Needless Repetition and Opacity.
Clean code: smells


Sources:
R.Martin Clean Code: A Handbook of Agile Software Craftsmanship
BBV.ch
MSDN
Wikipedia