Principles of Clean Code
Principles of Clean Code
Fall 2024
What is Clean Code?
• “Elegant and Efficient” -Bjarne Stroustrup, inventor of C++
• “Clean code can be read and enhanced by a developer other than its
original author” -Dave Thomas, godfather of the Eclipse strategy
• “Clean code always looks like it was written by someone who cares”
-Michael Feathers, author of Working Effectively with Legacy Code
2
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Key Features of Clean Code
• Modularity
• Readability
• Efficiency
• Error Handling
• Tests
3
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Modularity
• Organizing software into independent and interchangeable modules,
each encapsulating specific functionalities.
• Two relevant concepts
Ø Coupling
Ø Cohesion
• Fundamental design principle: low coupling and high cohesion
4
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Coupling
• Coupling refers to the degree of interdependence between different modules
• Consequences of high coupling
Ø Reduced understandability
Ø Higher error rates
Ø Testing gets more challenging
Ø Changes to one module may require modifications in multiple interconnected modules
Ø Limited reusability
• Strategies to reduce coupling include
Ø Proper usage of encapsulation
Ø Conforming to the Dependency Inversion Principle
5
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Cohesion
• Cohesion refers to the degree of interconnectedness among elements
within a module
• Consequences of low cohesion
Ø Reduced understandability
Ø Higher error rates
Ø Changes to one part of the system may have unexpected side effects
Ø Limited reusability
• One of the most effective strategies to increase cohesion is to conform
to the Single Responsibility Principle
6
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Clean Classes
• Classes should be small
Ø Single Responsibility Principle
• Classes should be cohesive
Ø Small number of instance variables
Ø The more instance variables a method manipulates the more cohesive that
method is to its class
7
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Clean Functions
• Functions should be small
Ø Blocks within if statements, else statements, while statements, and so on should
be one line long (probably a function call)
Ø The indent level of a function should not be greater than two
• Functions should do one thing only, and they should do it well
• One level of abstraction per function
• Use a descriptive name, even if it’s long
• Keep function arguments to a minimum
Ø Easier to understand
Ø Easier to test
• Functions should either do something or answer something, but not both
8
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Readability: Meaningful Names
• Use intention-revealing names
Ø This can make it much easier to understand and change the code
Ø If a name requires a comment, then the name does not reveal its intent
• Make meaningful distinctions
Ø Number series and noise words are meaningless distinctions
Ø E.g. Product, ProductData, ProductInfo
• Use pronounceable names
Ø This matters because programming is a social activity
• Use searchable names
Ø The length of a name should correspond to the size of its scope
9
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Readability: Meaningful Names (continued)
• Classes and objects should have noun or noun phrase names
Ø E.g. Account, Customer
• Methods should have verb or verb phrase names
Ø E.g. postPayment, deletePage
• Pick one word per concept
Ø For example, it’s confusing to have fetch, retrieve, and get as equivalent
methods of different classes
• Avoid using the same word for two purposes
10
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Readability: Comments
• It’s better to make the code so clear and expressive that it does not need
comments in the first place. For example:
vs.
11
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
Test Code
• Test code is as important as production code
• Unit tests keep the code maintainable and reusable
Ø Without tests, every change is a possible bug
• Readability might be more important in unit tests than it is in production code
• One concept and one assert per test
• Clean tests follow five rules (F.I.R.S.T)
Ø Fast
Ø Independent
Ø Repeatable
Ø Self-validating
Ø Timely
12
Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship, © 2009 Pearson Education, Inc.
What is Refactoring?
• “Refactoring is the process of changing a software system in such a
way that it does not alter the external behavior of the code yet
improves its internal structure.” – Martin Fowler
• Code quality deteriorates with time, even for a well-designed system
• Advantages of refactoring:
Ø Improving software design
Ø Making software easier to understand
Ø Finding bugs more easily
Ø Speeding up development
13
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
How to Refactor?
• Apply changes in a sequence of small steps
• Do not add any new functionality
• Make sure that all existing tests pass and add new ones if need be
14
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Extract Method
• Issue: You have a code fragment that can be grouped together.
• Refactoring: Turn the fragment into a method whose name explains the purpose
of the method.
• Example
15
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Replace Method with Method Object
• Issue: You have a long method that uses local variables in such a way that you
cannot apply Extract Method.
• Refactoring: Turn the method into its own object so that all the local variables
become fields on that object.
• Example
16
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Consolidate Conditional Expression
• Issue: You have a sequence of conditional tests with the same result.
• Refactoring: Combine into a single conditional expression and extract it.
• Example
17
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Consolidate Duplicate Conditional Fragments
18
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Remove Control Flag
• Issue: You have a variable that is acting as a control flag for a series of boolean
expressions.
• Refactoring: Use a break or return instead.
• Example
19
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Replace Nested Conditional with Guard Clauses
• Issue: A method has conditional behavior that does not make clear the normal
path of execution.
• Refactoring: Use guard clauses for all the special cases.
• Example
20
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Replace Magic Number with Symbolic Constant
21
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Parameterize Method
• Issue: Several methods do similar things but with different values contained in the
method body.
• Refactoring: Create one method that uses a parameter for the different values. If
the old methods are still used, their bodies should be replaced with a call to the
new one.
• Example
Employee Employee
fivePercentRaise() raise(percentage)
tenPercentRaise()
22
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Replace Parameter with Explicit Methods
• Issue: You have a method that runs different code depending on the values of an
enumerated parameter.
• Refactoring: Create a separate method for each value of the parameter.
• Example
23
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Introduce Explaining Variable
• Issue: You have a complicated expression.
• Refactoring: Put the result of the expression, or parts of the expression, in a
temporary variable with a name that explains the purpose.
• Example
double price() {
return _quantity * _itemPrice - Math.max(0, _quantity - 500) * _itemPrice * 0.05 + Math.min(_quantity * _itemPrice * 0.1, 100.0);
}
double price() {
final double basePrice = _quantity * _itemPrice;
final double quantityDiscount = Math.max(0, _quantity - 500) *_itemPrice * 0.05;
final double shipping = Math.min(basePrice * 0.1, 100.0);
return basePrice - quantityDiscount + shipping;
}
24
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Extract Class
• Issue: You have one class doing work that should be done by two.
• Refactoring: Create a new class and move the relevant fields and methods from
the old class into the new class.
• Example
25
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Extract Superclass
• Issue: You have two classes with similar features.
• Refactoring: Create a superclass and move the common features to the superclass.
• Example Person
getName()
Student
getName()
getID()
Professor
Student Professor
getName()
getID() getRank()
getRank()
26
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Extract Subclass
• Issue: A class has features that are used only in some instances.
• Refactoring: Create a subclass for that subset of features.
• Example
Person
getName()
Person getAddress ()
getName()
getAddress ()
getSalary()
Employee
getSalary()
27
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Pull up Field/Method
• Issue: You have classes with identical fields/methods.
• Refactoring: Move them to the superclass.
• Example Person
Person
name
getName()
Student Professor
name name
id rank Student Professor
getName() getName() id rank
getID() getRank() getID() getRank()
28
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Push down Field/Method
• Issue: Field/method of a superclass is relevant only for some of its subclasses.
• Refactoring: Move it to those subclasses.
• Example Person
Person
name
name
employeeID
Student Professor
Student Professor
studentID employeeID
studentID rank rank
getRank() cgpa()
cgpa() getRank()
29
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Replace Inheritance with Delegation
• Issue: A subclass uses only part of a superclass’s interface or does not want to
inherit data.
• Refactoring: Create a field for the superclass, adjust methods to delegate to the
superclass, and remove the subclassing.
• Example
Vector
Stack Vector
Stack
30
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Replace Delegation with Inheritance
• Issue: You're using delegation and are often writing many simple delegations for
the entire interface.
• Refactoring: Make the delegating class a subclass of the delegate.
• Example
Person
Employee Person
Employee
31
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Replace Conditional with Polymorphism
• Issue: You have a conditional that chooses different behavior depending on the
type of an object.
• Refactoring: Move each leg of the conditional to an overriding method in a
subclass. Make the original method abstract.
• Example
32
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.
Refactoring: Introduce Null object
• Issue: You have repeated checks for a null value.
• Refactoring: Replace the null value with a null object.
• Example
33
Fowler, Martin. Refactoring: Improving the Design of Existing Code. Boston, MA, USA: Addison-Wesley, 1999.