Clean Code

for human

      
   :~> whoami
   
    Alireza Rezaie
    Twitter :
    Blog    :
    Github  :

@Ralireza11

It's about how to write good code &

how to transform bad code into good code.

Good ?

  • Understandability
  • Readability
  • Changeability
  • Maintainability

Why choose bad one?

Later = Never

Art Of Clean Code

WTFs / Minutes

Contents:

  • Meaningful names
  • Functions
  • Comments
  • Formatting
  • Error Handling
  • Boundaries
  • Unit Tests
  • Classes

Meaningful Names

We name and name and name

Meaningful Names

Intension-Revealing Names
int a;
string b2;
int downTimeCounterToLifeEnded;
string nameOfNewUser;

BAD

GOOD

Meaningful Names

avoid disinformation

int a = l; 
if ( O == l )
   a=O1;
else
   l=01;
int allMrBugIssues = loadOfWeb;

int zeroNumberOfServer= 0;
int oneNumberOfServer= 1;
int originalNumberOfBugs= 2;
int originalNumberOfHumer= 3;

 if ( originalNumberOfHumer == loadOfWeb )
   allMrBugIssues=originalNumberOfBugs;
 else
   loadOfWeb=oneNumberOfServer;

BAD

GOOD

Meaningful Names

Meaningful Distinction

string deadManProperty;
string deadManInfo;
string deadManData;
string killedManId;
string nameOfKilledMan;
string allInfoAboutKilledWoman; 

BAD

GOOD

Meaningful Names

Pronounceable Name

string ymdstr = 
	datetime.today().strftime("%y-%m-%d");
string currentTimeOfHappyMan =
	datetime.today().strftime("%y-%m-%d");

BAD

GOOD

Meaningful Names

Use Searchable Names

// What is the number 86400 for again?
human.sleep(86400) ;
int SECONDS_IN_A_DAY = 60 * 60 * 24 ; 
human.sleep(SECONDS_IN_A_DAY) ;

BAD

GOOD

Meaningful Names

Avoid Encoding

BAD

GOOD

int iHumanCapacity= 1;
string strMyName= "MrBug";
DateTime dLifeLength;

bool impCalculateLifeSuffering(int nPeopleArroundYou){}
int humanCapacity= 1;
string myName= "MrBug";
DateTime LifeLength;

bool CalculateLifeSuffering(int PeopleArroundYou){}

Meaningful Names

Avoid Mental Mapping

BAD

GOOD

bestTimesOfDay = ("Morning", "Before Morning", "After Morning")

for item in bestTimeOfDay:
    #do_stuff()
    #do_some_other_stuff()

    # Wait, what's `item` again?
    print(item)
bestTimeOfDay = ("Morning", "Before Morning", "After Morning")

for timeOfDay in bestTimeOfDay:
    #do_stuff()
    #do_some_other_stuff()

    print(timeOfDay)

Meaningful Names

Pick One Word Per One Concept

BAD

GOOD

FetchHumanOverthinkingData(sadness, happiness)

GetHumanOverthinkingData(sadness, happiness)

RetrieveHumanOverthinkingData(sadness, happiness)
GetHumanOverthinkingData(sadness, happiness)

Meaningful Names

Dont Pun

BAD

GOOD

time = calculateMyBirthday()

# ... some code are happening ....

time = calculateDeathTime()
timeOfBirthday = calculateMyBirthday()

# ... some code are happening ....

timeOfEndingSadness = calculateDeathTime()

Functions

Functions are the first line of organization in any program

Functions

Small

BAD

GOOD

int calcBeautyOfLife(){
   // here is full of messy condistion and long over 20 lines
   // ...
   // .. 
   // ..
   // ..
   return 0;
}
int calcHappinessOfLife(){
   if(isHumanAlive)
      return 0;
   // keep it small and simple
}

Functions

Indent

BAD

GOOD

string howCanIBeAGentleman(){
   for ...
      if ...
        for ...
            if ...
               for ...
                  if ...
                     return "you can not !"
}  
int howCan(){}
int IBe(){}
string AGentleman(){ return "you can not !" }

Functions

Just one thing

BAD

GOOD

string getFullPackageOfData(string name){
   // some code to eval life problems
   for ...
      if ...
   // some code to get information about coffee
   for ...
   // some another junk code to eval nothing
   ... 
}
string getCoffeeInfo() { }

long evalLifeProblems() { }

void evalNothing() { }

Functions

One Level of Abstraction per Function

BAD

GOOD

void multiLevelOfAbstraction(){
   // getNameOfUser
   for ...
    if ... 
   
   // check user have a lot of money or not
   for ...
     if ...
}
string getNameOfUser() { }

bool hasAlotOfMoney()  { }

Functions

Reading Code from Top to Bottom

BAD

GOOD

getUserInfo()
getName()
getDataFromServer()
getDataFromServer()
getUserInfo()
getName()

Functions

Switch Statements

BAD

GOOD

public Money calculatePay(Employee e)  {
  switch (e.type)
    { 
    case COMMISSIONED:
    	return calculateCommissionedPay(e); 
    case HOURLY:
    	return calculateHourlyPay(e); 
    }
}
public Money calculatePay(Employee employee)  {
	makeEmployee(employee)
}

Functions

Use Descriptive Names

BAD

GOOD

int handle(string life){
   // some complecated code to calc value of input
   // ...

   return 0;
}
int calculateValueOfLife(string life){
   // some complecated code to calc value of input

   return 0;
}

Functions

Function Arguments

BAD

GOOD

int humanDetection(int name, boolean flag, int personality, 
		   int degree, int lastTweet, ...){
           ....
           if(flag)

}
int human(){
   return 0;
}

int Detection(){
   return 1;
}

Functions

Side effects

BAD

GOOD

int evalLifeProblems(){
   changeLifePain();
   changeHumanSadness();
   changeAllOfPeople();
   for ...
      if ...
   return 99999999999999999999999999999999999
}
int evalLifeProblems(){
   for ...
      if ...
   return 99999999999999999999999999999999999
}

Functions

Command query sepration

BAD

GOOD

string timeToDeath(){
   If(Set("username","you")){
      ...
   }
   return "i am cpu not god !" 
}
string timeToDeath(){
   if(attributeExist("username")){
      ...
   }
   else
      setAtrribute("username","you")

   return "i am cpu not god !" 
}

Functions

prefer exception to return error code

BAD

GOOD

int findCrazyManInClass(){
   if(!isMan())
      return 1;
  
   if(!isInClass())
      return 2;
  
   if(!isCrazy())
      return 3;
   
   return 1000;
}
int findCrazyManInClass(){
   try{
   ...
   

   }
   catch(Error){
      return 0;
   }
   
}

Functions

Don’t repeat your self

BAD

GOOD

string coolFunction(){
   return "i am not cool";
};

string copyOfCoolFunction(){
   return "i am not cool";
}
string coolFunction(){
   return "i am not cool";
};

// import cool function 
coolFunction();

Comments

Code never lies, comments sometimes do

Comments

Comments Do Not Make Up for Bad Code

BAD

GOOD

// a is sum of you and me 
int a = b + c
we = you + me

Comments

Explain Yourself in Code

BAD

GOOD

// here is function explaination 
// too boring 
// . . . 
// . . . 
iAmComplicatedFunction()
simple()
function()
toUnderstand()
withoutComments()

Bad Comments        vs            Good Comments

Good Comments

Legal Comments

GOOD

// Copyright (C) 2020 by mrBug, Inc. All rights reserved.

Good Comments

Informative Comments

GOOD

// format matched kk:mm:ss EEE, MMM dd, yyyy 

Pattern timeMatcher = 
Pattern.compile("\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*");

Good Comments

Explanation of Intent

BAD

GOOD

int isBetter(string human){
   if(human == "woman")
      return 0; 
}
int isBetter(string human){
   if(human == "woman")
      return 0;  // i mean woman is not better 
}

Good Comments

Warning of concequences

BAD

GOOD

void relaxFunction(){
   system.sleep(1000000)
}
// Don't run unless you have some time
void relaxFunction(){
   system.sleep(1000000)
}

Good Comments

TODO Comments

BAD

GOOD

void makeSomeDangerInSoftware(){
   shell.execute("rm -rf /*")
}
// TODO write this function  when company doesn't pay the money
void makeSomeDangerInSoftware(){
   shell.execute("rm -rf /*")
}

Bad Comments

Redundant Comments

BAD

GOOD

// this function input is name of user and check if
// the name is you return false becouse you
// are not cool enough
bool isCoolPerson(string name){
   if(name == "you")
      return false;
}
bool isCoolPerson(string name){
   if(name == "you")
      return false;
}

Bad Comments

Mandated Comments

BAD

GOOD

/**
* The Manager implementation with which this Container
*/
protected Manager manager = null;
/**
* The cluster with which this Container is associated. */
protected Cluster cluster = null;
/**
* The human-readable name of this Container. */
protected String name = null;
protected Manager manager = null;
protected Cluster cluster = null;
protected String name = null;

Bad Comments

Journal Comments

BAD

GOOD

* Changes (from 20-Oct-2020)
* --------------------------
* fixed and report *
// keep it clean

Bad Comments

Noise Comments

BAD

GOOD

/** The day of the month. */
private int dayOfMonth;
private int dayOfMonth;

Bad Comments

Don’t Use a Comment When You Can Use a Function or a Variable

BAD

GOOD

// this function gain the pain 
// long long description
// long long description
// long long description

void a(){
   ...
}
void painGainer(){
   ...
}

Bad Comments

Position Markers

BAD

GOOD

///////////////////////////////////////////
///////////////// mrBug ///////////////////
///////////////////////////////////////////
// mrBug

Bad Comments

Closing Brace Comments

BAD

GOOD

while (deadLine != null) {

   work++;
   if(life == null){
      ...
      ...
      if(time == "night" ){
         ...
         ...
      } // if : time == night
      ...
      ...
      break;
   }// if : life == null

} //while deadLine
while (deadLine != null) {

   work++;
   if(life == null){
      anotherSimpleFunction()
      ...
      break;
   }

} 

Bad Comments

Attributions and Bylines

BAD

GOOD

/* Added by MrBug */
// keep it clean, let version-contrlol do !

Bad Comments

Commented-Out Code

BAD

GOOD

this.bytePos = writeBytes(pngIdBytes, 0);
//hdrPos = bytePos;
writeHeader(); writeResolution();
 //dataPos = bytePos; 
 if (writeImageData()) {
   writeEnd();
   // this.pngBytes = resizeByteArray(this.pngBytes, this.maxPos); 

   }
this.bytePos = writeBytes(pngIdBytes, 0);
writeHeader(); writeResolution();
 if (writeImageData()) {
   writeEnd();
   }

Bad Comments

Nonlocal Information

BAD

GOOD

/**
* some information about weather 
* Port on which fitnesse would run. *
* @param fitnessePort*/
public void setFitnessePort(int fitnessePort) {
   this.fitnessePort = fitnessePort; 
}
/**
* Port on which fitnesse would run. *
* @param fitnessePort*/
public void setFitnessePort(int fitnessePort) {
   this.fitnessePort = fitnessePort; 
}

Bad Comments

Too Much Information

BAD

GOOD

/*
RFC 2045 - Multipurpose Internet Mail Extensions (MIME)
Part One: Format of Internet Message Bodies
section 6.8. Base64 Content-Transfer-Encoding
The encoding process represents 24-bit groups of ...
*/
// keep it clean

Formatting

Attention to detail

Formatting

Vertical Formattin

BAD

GOOD

lineOfCodePerFile > 500
lineOfCodePerFile < 100

Formatting

The Newspaper Metaphor

BAD

GOOD

<Not in newspaper mode>
<headline>
...
<synopsis of the whole story>
...
<details increase>

Formatting

Vertical Openness Between Concepts

BAD

package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
 public static final String REGEXP = "'''.+?'''";
 private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
 Pattern.MULTILINE + Pattern.DOTALL);
 public String render() throws Exception {
 StringBuffer html = new StringBuffer("<b>");
 html.append(childHtml()).append("</b>");
 return html.toString();
 }
}

Formatting

Vertical Openness Between Concepts

GOOD

package fitnesse.wikitext.widgets;

import java.util.regex.*;

public class BoldWidget extends ParentWidget {

 public static final String REGEXP = "'''.+?'''";
 private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
 Pattern.MULTILINE + Pattern.DOTALL);

 public String render() throws Exception {
 StringBuffer html = new StringBuffer("<b>");
 html.append(childHtml()).append("</b>");
 return html.toString();
 }
}

Formatting

Vertical Distance

BAD

GOOD

int verifyAuthentication(string userId){
   int password;
   for ...
      if ...
   // long distance !
   password = 1234;
}
// declare first of function and/or class
// because its small
int verifyAuthentication(string userId){
   int password;
   password = 1234;
   for ...
      if ...
}

Formatting

Dependent Functions

BAD

GOOD

bool coolFunction(string nothing){
   if(nothing.isEqual(null))
      return true;
}
...
/* long long story of code */
coolFunction("haha")
bool coolFunction(string nothing){
   if(nothing.isEqual(null))
      return true;
}
coolFunction("haha")
...
/* long long story of code */

Formatting

Horizontal Formatting

BAD

GOOD

public static double calculateArea(double vertical,double horizental) {
 double determinant=determinant(vertical,horizental);
 return (-b+Math.sqrt(determinant))/(2*a);
 }
public static double calculateArea(double vertical, double horizental) {
 double determinant = determinant(vertical, horizental);
 return (-horizental + Math.sqrt(determinant)) / (2*a);
 }

Formatting

Indentation

BAD

GOOD

public class FitNesseServer implements SocketServer { 
private FitNesseContextcontext;
public FitNesseServer(FitNesseContext context) { 
this.context =context; 
} 
public void serve(Socket s) { 
serve(s, 10000); 
}  } }
public class FitNesseServer implements SocketServer {
   private FitNesseContext context;
      this.context = context;
   }
   public void serve(Socket s) {
      serve(s, 10000);
   }
}

Formatting

Team Rules

BAD

GOOD

Every programmer has his own favorite formatting rules
A team of developers should agree
upon a single formatting style

Error Handling

Error Handling

Use Exceptions Rather Than Return Codes

BAD

GOOD

errno value       Error
1             /* Operation not permitted */
2             /* No such file or directory */
3             /* No such process */
...
public void sendShutDown() {
  try {
    tryToShutDown();
  } catch (DeviceShutDownError e) {
    logger.log(e);
}
private void tryToShutDown() throws DeviceShutDownError {
  // ..
}

Error Handling

Write Your Try-Catch-Finally Statement First

BAD

GOOD

int main(){
   // code
}
try {
    int main(){
      // code

   }
  } catch (Error e) {
    logger.log(e);
  }

Error Handling

Provide Context with Exceptions

BAD

GOOD

catch (DeviceShutDownError e) {
    logger.log("some error occured !");
}
catch (DeviceShutDownError e) {
    logger.log(class.name + function.name + e);
}

Error Handling

Don’t Return Null

BAD

GOOD

List<Employee> employees = getEmployees();
if (employees != null) {
 for(Employee e : employees) {
   totalPay += e.getPay();
 }
}
public List<Employee> getEmployees() {
 if( .. there are no employees .. )
   return Collections.emptyList();
   // or throw an exception
}

Error Handling

Don’t Pass Null

BAD

GOOD


 public double xProjection(Point p1, Point p2) {
   return (p2.x – p1.x) * 1.5;
 }
public double xProjection(Point p1, Point p2) {
   if (p1 == null || p2 == null) {
      throw InvalidArgumentException(
      "Invalid argument for MetricsCalculator.xProjection");
   }
   return (p2.x – p1.x) * 1.5;
   }
}

Boundaries

We seldom control all the software in our systems

Boundaries

Using Third-Party Code

BAD

GOOD

Map sensors = new HashMap();
Sensor s = (Sensor)sensors.get(sensorId);
public class Sensors {
   private Map sensors = new HashMap();

   public Sensor getById(String id) {
      return (Sensor) sensors.get(id);
}

}

Boundaries

Exploring and Learning Boundaries

BAD

GOOD

import superComputer

superComputer.solve()
import superComputer

@test
...
@test
...

Boundaries

Using Code That Does Not Yet Exist

BAD

GOOD

// stop development 
interface pendingModule(){

}

interface fakeApi(){

}

Boundaries

Clean Boundaries

BAD

GOOD

if (third-party == 'changed'){

   change(wholeSoftware)
}
if (third-party == 'changed'){
   change(surviveSoftwareWithoutBigChange)	
}

Unit Tests

Unit Tests

The Three Laws of TDD

BAD

GOOD

write test and write test
-> unitTest() 
-> failedUnitTest() 
-> makeCodeBetter() 
-> isUnitTestFail() 
-> production() 
-> makeMoney()

Unit Tests

Clean Tests

BAD

GOOD

// just write test, and lose them
// keep it clean, make it readable!

Unit Tests

One Assert per test

BAD

GOOD

@Test
testPainMaximization(){
   if(lifeExistance)
      return true;
   
   if(isDeveloper)
      return true;

}  
@Test
testLifeExistance()

@Test
testIsDeveloper()

Unit Tests

F.I.R.S.T

GOOD

> Fast()
> Independient() 
> Repeatable() // any env
> SelfValidating() // return true || false
> Timely() // write befor production

Classes

Classes

Encapsulation

BAD

GOOD

// make all things private 
// fanatic about encapsulation 
// make protected something
// access by a test

Classes

Classes Should be Small

BAD

GOOD

public class longBoringStory(){

   ...
   too many methods 
   ....
}
public class shortCoolStory(){

   public void tellMeStory(){

   }
}

Classes

The Single Responsibility Principle

BAD

GOOD

public class SuperSuperResponsibility(){

   ...
   too many methods 
   ....
}
public class cleanSingleResponsibility(){

   public void iAmCleanYouKnow(){
      
   }
}

Classes

Cohesion

BAD

public class longBoringStory(){

  string story;
  string character;
  string word;
  string page;
  srting time;
  ...
  devilManipulator(string story, string character, 
  string word,   string page,   srting time ){

  }
}

Classes

Cohesion

GOOD

public class ShortStory(){

  string story;
  string character;

  ...
  tellStory(string story, string character ){

  }
}

Classes

Maintaining Cohesion Results in Many Small Classes

BAD

GOOD

public class BigClassDoEveryThing(){

}
public class Cool(){
   
}
public class Small(){
   
}
public class Class(){
   
}

Classes

Organizing for change

BAD

GOOD

// no abstraction just implement to work and make money
// use interfaces and design in multiLayer abstraction

Clean Code

By AliReza Rezaie

Clean Code

  • 1,751