Clean Code Developer Checklist

A developer checklist derived from the book Clean Code by Robert C Martin

Download as .zip Download as .tar.gz View on GitHub

Clean Code Developer Checklist

A developer checklist mostly derived from the book Clean Code by Robert C Martin

See to β€œGitlab: Code Review Guidelines”

Table of contents :bookmark_tabs:



Naming things :u5272:

🟒 Name should reveal intent

🟒 Avoid using abbreviations

🟒 Do not encode name with data structure

🟒 Do not use names which vary in small ways

🟒 Do not name variables just to satisfy the compiler

🟒 Avoid using noise words

🟒 Distinguish names in such a way that the reader knows which one to call.

🟒 Use pronounceable names

🟒 Use searchable names

🟒 Include units of a measurable entity to its variable name

🟒 The length of a name should correspond to the size of its scope

🟒 Classes and objects should have noun or noun phrase names.

🟒 Methods should have verb or verb phrase names

🟒 When constructors are overloaded, try to use static factory methods with names that describe the arguments

🟒 Pick one word for one abstract concept and stick with it

- For instance, it’s confusing to have `fetch`, `retrieve`, and `get` as equivalent methods of different classes.

🟒 Don’t add gratuitous context

🟒 It’s okay to use computer science terms, algorithm names, pattern names, math terms

🟒 Add no more context to a name than is necessary




Functions :microscope:

🟒 Function should be small

🟒 Blocks inside if, else, while should be one line long, and that should probably be a function call

🟒 The indent level of a function should not be greater than one or two

🟒 Functions should do one thing, they should do it well, they should do it only

🟒 Functions should not have sections inside them

🟒 Function should have one level of abstraction

🟒 The Stepdown Rule

🟒 Switch statement should be buried in a low-level class, should appear only once, to create polymorphic objects and is never repeated

🟒 Try to have functions with 3 arguments

🟒 If a function is going to transform its input argument, the transformation should appear as the return value

🟒 Flag arguments should be avoided

🟒 When a function need more than 2 or 3 arguments, if possible wrap some of those arguments into a class of their own

🟒 Functions should not have any side-effects

🟒 Function should do one thing, which the name suggests and not do anything else

🟒 Functions should either do something or answer something (command query separation)

🟒 Prefer exceptions to returning error codes

🟒 Extract Try/Catch Blocks

🟒 Avoid code duplication




Formatting :rainbow:

🟒 Vertical size of a file should be typically be within the 200 lines limit

🟒 We would like a source file to be like a newspaper article

🟒 Vertical Openness Between Concepts

🟒 Variables should be declared as close to their usage as possible

🟒 Instance variables should be declared at the top of the class

🟒 If one function calls another, they should be vertically close

🟒 Codes having strong conceptual affinity between them should have less vertical separation between them

For example

public static void assertTrue(boolean condition) {
assertThat(condition).isTrue();
}

public static void assertFalse(boolean condition) {
assertThat(condition).isFalse()
}

🟒 Lines should not be more than 120 characters

🟒 Use spaces between operators, parameters, and commas

🟒 Use a consistent formatting style across the team

🟒 Indentation




Objects and Data Structures :two_men_holding_hands:

🟒 Hide implementation of classes with Abstraction

🟒 Data/object anti-symmetry

🟒 Choosing between Functional code and OO code

🟒 The law of demeter

🟒 Train Wrecks

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

This kind of chaining operations are called train wrecks and should be avoided.

someList.map(..).map(..).filter(..)

🟒 Hybrids, classes which have functions that do significant things, and they also have either public variables or public accessors and mutators

🟒 DTOs should not have any behavior , i.e. they should be data-structure and not objects




Error handling :interrobang:

🟒 Error handling is important, but if it obscures logic, it’s wrong

🟒 Use unchecked exceptions

🟒 Provide context with exceptions

🟒 Define exception classes in terms of a caller’s needs

🟒 If a portion of code throws many types of exception, wrap that part and throw a common exception

🟒 Wrap your third party API calls

🟒 Instead of having a special flow for exception, use special case pattern

try {
  MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
  m_total += expenses.getTotal();
} catch (MealExpensesNotFound e) {
  m_total += getMealPerDiem();
}
MealExpenses expenses = expenseReportDAO.getMeals(employee.getID());
m_total += expenses.getTotal();
public class PerDiemMealExpenses implements MealExpenses {
  public int getTotal() {
    // return the per diem default
  }
}

🟒 Don’t return null

🟒 Don’t pass null as arguments

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;
}
public double xProjection(Point p1, Point p2) {
    assert p1 != null : "p1 should not be null";
    assert p2 != null : "p2 should not be null";
    return (p2.x – p1.x) * 1.5;
}

But this also doesn’t solve the problem, instead of NullPointerException we are going to get some different RuntimeException




Unit tests :umbrella:

🟒 Follow three laws of TDD

🟒 Keep test clean

🟒 Follow the The Build-Operate-Check pattern

🟒 A Dual Standard

🟒 One assert per test (flexible)

🟒 Single Concept per Test

🟒 F.I.R.S.T.




Class :school_satchel:

🟒 Class organization :arrow_down:

🟒 Classes should maintain Encapsulation

🟒 Classes should be small and do only one thing

🟒 Single Responsibility Principle

🟒 Classes should have cohesion

🟒 Classes should depend upon abstractions, not on concrete details (Dependency Inversion)




Emergence :green_book:

🟒 Design must produce a system that runs all tests as writing tests leads to better designs

🟒 No duplication

🟒 Expressive

🟒 Minimal classes and methods




Concurrency :arrows_clockwise:

🟒 Concurrency always doesn’t improve performance

🟒 To make a system concurrent we might need to change the overall design strategy

🟒 Understanding potential concurrency issue is important even though it might not be the problem at hand

🟒 Shared data between threads create synchronization problems, hence take data encapsulation to heart, limit the access of any data that may be shared

🟒 Instead of sharing data, create copies of data for different thread and collect them at the end of processing

🟒 Threads Should Be as Independent as Possible, and should not share data with any other thread

🟒 Use thread safe library functions

🟒 Use producer consumer model for concurrent operation

🟒 Use Readers-Writers model for concurrent operation

🟒 Use different locking strategies like

🟒 Keep your synchronized sections small and avoid side-effects

🟒 Have a shutdown strategy in place which works

🟒 Treat spurious failures as candidate threading issues

🟒 Get your non-threaded code working first

🟒 Make your threaded code pluggable

🟒 Make your threaded code tunable

🟒 Run with more threads than processors

🟒 Run on different platforms

🟒 Instrument your code to try and force failures




Code smells :speak_no_evil:

🟒 If you see commented out code. delete it

🟒 Unused code should be deleted

🟒 Implementation should be obvious

🟒 Look for every boundary condition and write a test for it

🟒 Base classes should know nothing about their derivatives

🟒 Code should be consistent

🟒 Prefer nonstatic methods to static methods

🟒 Avoid Negative Conditionals

🟒 Encapsulate Boundary Conditions

if(level + 1 < tags.length) {
  parts = new Parse(body, tags, level + 1, offset + endTag);
  body = null
}

level + 1 is a boundary operation which is repeated so we can wrap that in a variable like nextLevel = level + 1

🟒 Avoid Long Import Lists by Using Wildcards

🟒 Don’t Inherit Constants

🟒 Use enums and not public static final ints/strings




Honourable mentions :basecamp:

In this section I am going to list down few things which are absolutely legendary but I missed mentioning them. There are tons of resources available online for these topics, you can read them from there.

🟒 The OG S.O.L.I.D principles, no clean code discussion is complete without them

🟒 Object Calisthenics