Part 1: Clean Code – Rules for good, clean code


To write clean code and easy to understand the ultimate goal is a good IT Projet. Much depends on:

  • Maintainability
  • Training time for other programmers, means fast, what do individual functions
  • Robustness to changes
  • Testability, everything falls together, with small changes, can quickly stable updates are
  • Popularity with other programmers e.g.: bei Open Source Projekten, as a negative example is called XT-Commerce

The highly recommended standard work on the subject is “Clean Code – Refactoring, Patterns, Testing and techniques for clean code” of Robert C. Martin. In this article, chapter 1 to 3 treated.

Meaningful names

The name of a variable, Function or class should declare immediately, why you exist, what it does and how it is used. If a variable requires a Comment, It expresses not its purpose.

Bsp:

int d //Anzahl vergangener Tage
besser ist:
int daysSinceCreation;

Pronounceable name use

No constructs with unclear abbreviations as: int daSiCre instead of daysSinceCreation.

Searchable name use

Modern IDEs make searching easy, but it's no, when you have to look for the letters e and a control variable is swamped by results.

Variable names with a letter must only be used as local variables in short methods.

Nonmember prefixes for class variables

Präfice as m_ for class variables are unnecessary, because the classes and functions should be as small as possible and modern IDEs variables highlight color.

Also nicht $m_variable oder $_variable, but $ variable write.

Interfaces and Implementations

An interface identifier in the class should not contain any mention of the name, as e.g.. IShape, but simply Shape mean. The implementation of the interface should be marked on, the end of the called, e.g.. ShapeImp.

Loop counter variables

Loop counter variables such as i,j or k are allowed, but never l (“small L”), difficult because of the 1 distinguishable. The scope of these variables must be very small.

Class name

Should consist of a noun or a phrase substantivischem.

Method names

Method names should start with a verb or a verb. The JavaBean standard are e.g.. following prefixes before: get, set, is.

If Konstruktroren should be overloaded using static factory methods, describing the arguments:

//schlecht:
GeoPoint geoPoint = new GeoPoint(2,3.5);
//gut:
GeoPoint geoPoint = new GeoPoint.fromLatLong(2,3.5);

One word per concept

For example, it is. bewildering fetch, retrieve and get to be used as names for equivalent methods of different classes.

The same applies to controller, manager, driver: There should always be a consistent lexicon used to create clarity.

Names of the solution domain use

The reader of your code will be computer, therefore should always terminology from computer science or mathematics are used and the customer terms (e.g.: BWL- Terminology).

Only if no suitable expression exists, a term can be used in the problem domain, because then the customer could consider. can help.

No unnecessary information

Some programmers make the classes specific prefixes in front of the class name, as e.g.. the Zend_Framework (Zend_). In a programming language such as PHP, where the name spaces only with PHP 5.3 been introduced are, is it ok, otherwise the information is redundant.

Shorter names are generally better, as long as you are clear. Do not add more context than necessary.

Functions

  • Functions should be very small, hardly longer than 20 Lines. All functions that are longer, can refactor into smaller functions.
  • Shiftwidth no more than 2 Levels, increases the readability immensely
  • they should perform a task
  • an abstraction layer for each function, generate the HTML and configure the tools lies For example,. far apart
  • Code should be able to be read from top to bottom, it should be made according to each function a next level of abstraction.

SWITCH statements

Switch statements usually meet several tasks, what is bad. If they can not be avoided, then you should at least be buried deep in classes and will never be repeated. The solution is Polymorphism and the Abstract Factory Pattern.

Bsp.

public Money calculatePay(Employee e) throws InvalidEmployeeType {
switch(e.type)
{
case FREELANCER:
return calculatePayFreelancer(e);
case SALARIED:
return calculatePaySalary(e);
case COMISSIONED:
return calculatePayComissioned(e);
default:
throw new InvalidEmployeeType(e.type);
}
}

In this Example, there are several problems:

  1. The function is too long and gets longer with each new employee type.
  2. She performs several functions: Error handling and salary calculation
  3. You must be changed, when a new type is added
  4. There are probably several other functions with the same switch conditions, as e.g.: getPayPerHour(Emplayee e)

The solution is to the switch statement to hide behind an Abstract Factory and can implement Funktionenpolymorph of the Employee interface.

public abstract class Employee{
public abstract Money caluclatePay();
public abstract Money getPayPerHour();
}
-----
public interface EmployeeFactory{
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
----
public class EmployeeFacotryImpl implements EmployeeFactory{
public Employee makeEmployee(Employee e) throws InvalidEmployeeType {
switch(r.type)
{
case FREELANCER:
return new FreelancerEmployee(r);
case SALARIED:
return SalariedEmployee(r);
case COMISSIONED:
return ComissionedEmployee(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
}

Number of function arguments

It should be no argument at best and most 2 to 3 Arguments are used. The less, the easier course, the functions.

Advantage, that the functions are easy to test, because by increasing the number of arguments, the number of combinations increases potentially.

Output arguments are difficult to understand as the return values:

//schlecht: Verwendung von Output-Argumenten
generateHTML("<div>lalala</div>", $html);
//besser: Rückgabewerte verwenden
$html = generateHTML("<div>lalala</div>");

Functions with input parameters (monadic functions)

  1. Ask question about the argument: boolean is_int($was)
  2. The argument manipulate, e.g.. Convert: InputStream fileOpen(String filename)

Flag arguments

Are absolutely prohibited and suggests, the more than one task is processed, e.g.. render(true), here must only be looked, for which the parameter is. The function should 2 Functions will be divided, e.g.. renderHighQuality() and renderLowQuality().

Functions with two input parameters(dyadic functions)

Are difficult to understand and the parameter order can cause problems, e.g.. assertEquals(expected, actual). It makes sense for functions, among the parameters logically belong together as. new Point(1,1).

Many dyadic functions can be e.g.. convert on the introduction of class variables to monadic functions. The same applies to triadic functions.

Functions with more than 2 Input-Parametern(polyadic functions)

It is probably, that the case should be wrapped in separate classes:

drawCycle(double x, double y, double radius);
//besser:eigene Klasse, verständlichere Bennenung
drawCycle(Point center, double radius);

Avoid side effects

If verprechen functions to accomplish a task, also perform a hidden feature, often leads to the bugs. This can e.g.. changing class variables / global variables to be. This leads to difficult Paths to errors, which are dependent on the time the function is called and are difficult to reproduce.

function checkPassword($userName, $password)
{
if(isAuthorized($userName, $password))
{
// führt zu Nebeneffekten
session.start();
return true;
}
else
{
return false;
}
}

Statements and queries separate

Functions should either do something or something Reply, neither of which are permitted.

boolean setString($value)

is confusing, because

if(setString($value))

can mean, that it is checked, whether the value was set or whether the value has been set successfully.

Exception vs. Error Codes

By error codes as return of arguments, many if loops provoked and the code is the use of exceptions hässlich.Bei Fehlerbhandlung can be separated from the logic. They should the try-catch blocks are always separated from the logic and be separated into individual functions:

public void setString(String value)
{
try{
setStringValue();
}
catch (Exception e)
{
logError(e);
}
}

private void setStringValue(String value) throws Exception
{
this.string = value;
}

private void logError(Exception e)
{
logger.log(e.getMessage());
}

DRY – Don&#8217;t Repeat Yourself

Repetitions bloat the code and require extra effort when changes.

Structured programming

By Donald Knuth, any function having an output and an input: Is anathema multiple return statements, and break, and continue to use goto.

This applies only when longer functions, in short, a plurality of functions returns, break and continue perfectly legal and useful, because they make the code more expressive.

GOTO should really no used.

How to program to properly write such functions?

When writing code, it is perfectly natural, that the first draft ugly, too long and unstructured. This design was to be converted so long and improved, accompanied by unit tests, until you are at peace with the results and all the criteria are met.

continue to: Part 2: Clean Code – right and bottle Comments

Read more?

  1. Or we use a consistent style to name Varblen. You must be not necessarily pronounce, as long as the function declare it complete.

    “I” as well as “mpchgr” Variable names which fully describe the data type and function.

    This system is u. a. used by Microsoft

  2. Good and easy introduction to the clean code –> has helped me.

    Mfg
    CodeHasser: The code hates haters;)