Clean Code are guidelines for clean programming.
The order of attributes and methods matters. Public attributes should be avoided. Instead, getter and setter methods should be created.
Ideal order:
class Konto {
public String inhaber:
private int guthaben;
public Konto(){...}
public static ...
private static ...
public ueberweisung(...){...}
public getGuthaben(...){...}
public setGuthaben(...){...}
}“Don’t talk to Strangers” โ meaning don’t do something like:
int i = getObj().getObj2().getObjA().getSomeOtherObject().getArray()[0];
Instead, use this to access instance objects.
What is stated in the method name should also be executed. And not fulfill any other random tasks.
Negative example:
class A {
private File SomeUnimportantFile;
File getUnimportantFile(){
launchNuklearMissile();
return SomeUnimportantFile;
}
launchNuklearMissile(){
//Destroy Everything!
}
}In enumerations, the order should be respected. For weekdays: Monday, Tuesday, etc.
Parts that are not expected should also be omitted; in an enumeration of weekdays, there should be no "Frei" (Free).
Even if "Frei" is the day you don’t work.
Negative example:
enum Date {
FREITAG, DIENSTAG, MITTWOCH, FREI
}To pick up the example above again, we have removed the unpredictable execution (launchNuklearMissile();).
class A {
private File SomeUnimportantFile;
File getUnimportantFile(){
return SomeUnimportantFile;
}
public launchNuklearMissile(){
//Destroy Everything!
}
}But now we notice that A and getUnimportantFile are not very descriptive; more precise identifiers should be used.
Example:
class Waffenstillstand {
private File vertrag;
File getVertrag(){
return vertrag;
}
public launchNuklearMissile(){
//Destroy Everything!
}
}Another interesting naming is duplications of the class name and the attribute and method names.
Negative example:
class Konto {
int kontoname;
}Here Konto appears twice.
Better would be something like:
class Konto {
int name;
}Too little is too little and too much is too much.
Many errors arise from “Copy” and “Paste”. Replace with procedures/functions.
You won’t need it.
Negative example:
class Konto {
public bool ueberweisung(String empfaenger){...}
public bool indieSchweizueberweisung(String empfaenger){...}
}The indieSchweizueberweisung method could be unnecessary when a bank program first appears.
One responsibility per class.
class myConnector {
void connect(){...}
void terminateConnection(){...}
}A send() and a receive() method should be moved to a separate class.
class Communicator{
void send();
void receive();
}Roughly speaking, a class should not contain more than about 200 lines, or around 15 methods.
Open for extension, closed for modification. It can be extended without being modified.
Negative example:
class Form{...}
for Form f in FormListe{
switch(typeof(f)){
case Kreis: f.zeichneKreis();
case Quadrat: f.zeichneQuadrat();
}
}The switch case branch would need to be adapted every time this type of implementation appears more often in the codebase, meaning it would have to be changed at every location again. Therefore, the Form class should provide a draw() method.
class Form{
zeichne();
}
for Form f in FormList:
f.draw();The subclass, e.g., Kreis, is then forced to implement a draw().
Inheritance that doesn’t work:
class Rechteck{
float breit;
float hoch;
}
class Quadrat extends Rechteck{
// hoch === breit
}Every square is a rectangle, which works in mathematics, but not in a programming sense.
The Quadrat class cannot inherit from Rechteck because the height is always equal to the width.
The other way around works:
class Quadrat{
float breit;
flaeche(){
return breit * breit
}
}
class Rechteck extends Quadrat{
float hoch;
flaeche(){
return hoch * breit
}
}In this example, the flaeche() method still needs to be overridden.
If inheriting from an interface, it must actually be needed.
Negative example:
interface Worker{
eat();
work();
}
class Mensch implements Worker{
work(){...}
eat(){...}
}
class Robot implements Worker{
work(){...}
eat(){} //<- Too much
}The eat() method is given to the Robot class, which then has to override it and leave it empty (dead code).
In this case, two interfaces Eats and Work would be better.
interface Eats{
eat();
}
interface Worker {
work();
}
class Mensch implements Eats, Worker{
work(){...}
eat(){...}
}
class Robot implements Worker{
work(){...}
}In software, we have several layers:

A CopyPast interface needs two other classes named ReadUserInput and WriteFile.
The CopyPast is in a very high layer (almost in the GUI layer). The classes ReadUserInput and WriteFile are in a lower layer (WriteFile is in the persistence layer). CopyPast depends on the two classes in this case, but the opposite is desired. To achieve this, a class is created that is in a higher layer. In our example, a Reader class for ReadTextInput and a Writer class for WriteFile.
A method should stay at one level of abstraction. This abstraction level should decrease from method to method. The most abstract method calls only methods that are invisible to anyone outside. In these lower methods, the actual computational operations are hidden.
You want to leave the code cleaner than you found it.
Methods should not change externally. What to do when a parameter is needed that wasn’t there before? Simple solution: use default parameters.
Only work with test cases, otherwise there is a risk of destroying the code without noticing.
Whenever you no longer understand your own code, you should refactor it.
Tidy up before optimizing for performance.