SlideShare a Scribd company logo
by Dmytro Turskyi (March 2023)
(2008)
By Robert C. Martin (aka “Uncle Bob”)
Agenda
• Meaningful Names
• Functions
• Comments
• Error Handling
• Classes
• Environment
• General
Meaningful Names
• Avoid Mental Mapping
A single-letter name is a poor choice; it’s just a place holder that the reader
must mentally map to the actual concept. There can be no worse reason for
using the name “c” than because “a” and “b” were already taken.
• Method names
Methods should have verb or verb phrase names like postPayment,
deletePage, or save. Accessors, mutators, and predicates should be named
for their value and prefixed with get…, set…, and is…
Meaningful Names
• Use Searchable Names
const int WORK_DAYS_PER_WEEK = 5;
int realDaysPerIdealDay = 4;
int sum = 0;
for (int j = 0; j < NUMBER_OF_TASKS; j++) {
int realTaskDays = taskEstimate[ j ] * realDaysPerIdealDay;
int realTaskWeeks = (realDays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
for (int j = 0; j < 34; j++) {
s += (t [ j ] * 4) / 5;
}
Single-letter names can ONLY be
used as local variables inside short
methods.
The length of a name should
correspond to the size of its scope
Meaningful Names
• Use Intention-Revealing Names
If a name requires a comment, then the name does not reveal its intent.
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
Meaningful Names
• Use Pronounceable Names
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;
private final String recordId = "102";
}
class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
}
If you can’t pronounce it, you can’t
discuss it without sounding like an idiot.
Meaningful Names
• Class Names
Manager, Processor, Data, Info.
or
Meaningful Names
• Class Names
Customer, WikiPage, Account,
AddressParser.
Classes and objects should have noun or
noun phrase names and not include
indistinct noise words:
Manager, Processor, Data, Info.
Functions
• Small!
The first rule of functions is that they should be small.
Functions should hardly ever be ??? lines long.
Blocks within if statements, else statements, while statements, and so on
should be ??? long.
Functions
• Small!
The first rule of functions is that they should be small.
Functions should hardly ever be 20 lines long.
Blocks within if statements, else statements, while statements, and so on
should be one line long. Probably that line should be a function call.
• Do One Thing
To know that a function is doing more than “one thing” is if you can extract
another function from it with a name that is not merely a restatement of its
implementation.
Functions
• One Level of Abstraction per Function
We want the code to read like a top-down narrative.
We want every function to be followed by those at the next level of abstraction
so that we can read the program, descending one level of abstraction at a time
as we read down the list of functions.
public String render() throws Exception {
StringBuffer html = new StringBuffer(“<hr");
if(size > 0)
html.append(" size="")
.append(size + 1).append(“”");
html.append(">");
return html.toString();
}
public String render() throws Exception {
HtmlTag hr = new HtmlTag(“hr");
if (extraDashes > 0)
hr.addAttribute(“size", hrSize(extraDashes));
return hr.html();
}
private String hrSize(int height) {
int hrSize = height + 1;
return String.format("%d", hrSize);
}
Functions
• Use Descriptive Names
Don’t be afraid to make a name long. A long descriptive name is better than
a short enigmatic name. A long descriptive name is better than a long
descriptive comment.
• Dependent Functions.
If one function calls another, they should be vertically close, and the caller
should be above the callee, if at all possible.
Functions
• Function Arguments
The ideal number of arguments for
a function is ??? .
includeSetupPageInto(newPageContent)
or
Functions
• Function Arguments
The ideal number of arguments for
a function is zero (niladic). Next
comes one (monadic), followed
closely by two (dyadic). Three
arguments (triadic) should be
avoided where possible.
includeSetupPage()
includeSetupPageInto(newPageContent)
Functions
• Flag Arguments
Flag arguments are ugly. Passing a
boolean into a function is a truly
terrible practice. It immediately
complicates the signature of the
method, loudly proclaiming that this
function does more than one thing. It
does one thing if the flag is true and
another if the flag is false!
render(boolean isSuite)
renderForSuite()
renderForSingleTest()
Functions
• Have No Side Effects
public boolean checkPassword(String userName, String password) {
User user = UserGateway.findByName(userName);
if (user != User.NULL) {
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password".equals(phrase)) {
Session.initialize();
return true;
}
}
return false;
}
Functions
• Have No Side Effects
Side effects are lies.
public boolean checkPassword(String userName, String password) {
User user = UserGateway.findByName(userName);
if (user != User.NULL) {
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password".equals(phrase)) {
Session.initialize();
return true;
}
}
return false;
}
checkPasswordAndInitializeSession
Functions
• Output Arguments
For example:
appendFooter(s);
Does this function append “s” as the
footer to something? Or does it
append some footer to “s”? Is “s” an
input or an output? It doesn’t take
long to look at the function
signature and see, but anything that
forces you to check the function
signature is equivalent to a double-
take. It’s a cognitive break and
should be avoided.
public void appendFooter(StringBuffer report)
report.appendFooter();
Comments
// Check to see if the employee is eligible
// for full benefits
if ((employee.flags & HOURLY_FLAG) &&
(employee.age > 65))
or
Comments
• Explain Yourself in Code
Only the code can truly tell you
what it does.
Comments are, at best, a
necessary evil.
Rather than spend your time writing
the comments that explain the
mess you’ve made, spend it
cleaning that mess.
Inaccurate comments are far worse
than no comments at all.
if (employee.isEligibleForFullBenefits())
// Check to see if the employee is eligible
// for full benefits
if ((employee.flags & HOURLY_FLAG) &&
(employee.age > 65))
Comments
• Legal Comments
Sometimes our corporate
coding standards force us to
write certain comments for
legal reasons.
// Copyright (C) 2003,2004,2005 by Object
// Mentor, Inc. All rights reserved.
// Released under the terms of the GNU
// General Public License version 2 or later.
• Explanation of Intent
Sometimes a comment goes
beyond just useful information
about the implementation and
provides the intent behind a
decision.
// This is our best attempt to get a race condition
// by creating large number of threads.
for (int i = 0; i < 25000; i++) {
WidgetBuilderThread widgetBuilderThread =
new WidgetBuilderThread(widgetBuilder, text, parent, failFlag);
Thread thread = new Thread(widgetBuilderThread);
thread.start();
}
Comments
• Warning of Consequences
Sometimes it is useful to warn
other programmers about
certain consequences.
public static SimpleDateFormat makeStandardHttpDateFormat() {
//SimpleDateFormat is not thread safe,
//so we need to create each instance independently.
SimpleDateFormat df =
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df;
}
• TODO Comments
Nowadays, most good IDEs
provide special gestures and
features to locate all the //TODO
comments, so it’s not likely that
they will get lost.
//TODO-MdM these are not needed
// We expect this to go away when we do the
// checkout model
protected VersionInfo makeVersion() throws Exception{
return null;
}
Comments
• Amplification
A comment may be used to
amplify the importance of
something that may otherwise
seem inconsequential.
String listItemContent = match.group(3).trim();
// the trim is real important. It removes the starting
// spaces that could cause the item to be recognised
// as another list.
new ListItemWidget(this, listItemContent, this.level + 1);
return buildList(text.substring(match.end()));
• Public APIs
There is nothing quite so helpful
and satisfying as a well-
described public API. It would
be difficult, at best, to write
programs without them.
/// dart doc comment
/**
* JavaDoc comment
*/
Comments
• Commented-Out Code
We’ve had good source code
control systems for a very long
time now. Those systems will
remember the code for us. We
don’t have to comment it out any
more. Just delete the code.
• Position Markers
In general they are clutter that
should be eliminated—
especially the noisy train of
slashes at the end. If you
overuse banners, they’ll fall into
the background noise and be
ignored.
// Actions //////////////////////////////////
InputStreamResponse response = new InputStreamResponse();
response.setBody(formatter.getResultStream(),
formatter.getByteCount());
// InputStream resultsStream = formatter.getResultStream();
// StreamReader reader = new StreamReader(resultsStream);
// response.setContent(reader.read(formatter.getByteCount()));
Error Handling
• Don’t Return Null
When we return null, we are
essentially creating work for
ourselves and foisting problems
upon our callers. All it takes is one
missing null check to send an
application spinning out of control.
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();
}
Error Handling
• Don’t Pass Null
In most programming languages
there is no way to deal with
a null that is passed by a caller
accidentally. Because this is the
case, the rational approach is to
forbid passing null by default. When
you do, you can code with the
knowledge that a null in an
argument list is an indication of a
problem, and end up with far fewer
careless mistakes.
calculator.xProjection(null, new Point(12, 13));
Classes
• Classes Should Be Small!
With functions we measured size by counting physical lines. With classes we use a
different measure. We count ???.
Classes
• Classes Should Be Small!
With functions we measured size by counting physical lines. With classes we use a
different measure. We count responsibilities.
The Single Responsibility Principle (SRP) states that a class or module should have
one, and only one, reason to change.
The name of a class should describe what responsibilities it fulfills. The more
ambiguous the class name, the more likely it has too many responsibilities.
The problem is that too many of us think that we are done once the program works.
We move on to the next problem rather than going back and breaking the
overstuffed classes into decoupled units with single responsibilities.
Classes
public class SuperDashboard extends JFrame implements MetaDataUser
public String getCustomizerLanguagePath()
public void setSystemConfigPath(String systemConfigPath)
public String getSystemConfigDocument()
public void setSystemConfigDocument(String systemConfigDocument)
public boolean getGuruState()
public boolean getNoviceState()
public boolean getOpenSourceState()
public void showObject(MetaObject object)
public void showProgress(String s)
public void setACowDragging(boolean allowDragging)
public boolean allowDragging()
public boolean isCustomizing()
public void setTitle(String title)
public IdeMenuBar getIdeMenuBar()
public void showHelper(MetaObject metaObject, String propertyName)
// ... many non-public methods follow ...
}
public class Version {
public int getMajorVersionNumber()
public int getMinorVersionNumber()
public int getBuildNumber()
}
Environment
• Build Requires More Than One Step
Building a project should be a single
trivial operation. You should not have to
check many little pieces out from source
code control. You should be able to
check out the system with one simple
command and then issue one other
simple command to build it.
svn get mySystem
cd mySystem
ant all
• Tests Require More Than One Step
You should be able to run all the unit tests with just one command. In the best
case you can run all the tests by clicking on one button in your IDE.
General
• Artificial Coupling
In general an artificial coupling is a coupling between two modules that serves no
direct purpose. It is a result of putting a variable, constant, or function in a temporarily
convenient, though inappropriate, location.
For example, general enumsshould not be contained within more specific classes
because this forces the whole application to know about these more specific classes.
The same goes for general purpose static functions being declared in specific
classes.
• Prefer Polymorphism to If/Else or Switch/Case
There may be no more than one switch statement for a given type of selection. The
cases in that switch statement must create polymorphic objects that take the place of
other such switch statements in the rest of the system.
General
• Replace Magic Numbers with Named Constants
In general it is a bad idea to have raw numbers in your code. You should hide them
behind well-named constants. The term “Magic Number” does not apply only to
numbers. It applies to any token that has a value that is not self-describing.
assertEquals(7777, Employee.find(“John Doe”).employeeNumber());
assertEquals(
HOURLY_EMPLOYEE_ID,
Employee.find(HOURLY_EMPLOYEE_NAME).employeeNumber());
General
• Encapsulate
Conditionals
Boolean logic is hard enough to
understand without having to
see it in the context of an if or
while statement. Extract
functions that explain the intent
of the conditional.
if (shouldBeDeleted(timer))
if (timer.hasExpired() &&
!timer.isRecurrent())
• Avoid Negative
Conditionals
Negatives are just a bit harder to
understand than positives. So,
when possible, conditionals
should be expressed as
positives.
if (buffer.shouldCompact())
if (!buffer.shouldNotCompact())
General
• Encapsulate Boundary Conditions
Boundary conditions are hard to keep track of. Put the processing for them in one
place.
if (level + 1 < tags.length) {
parts = new Parse(body, tags, level + 1, offset + endTag);
body = null;
}
int nextLevel = level + 1;
if (nextLevel < tags.length) {
parts = new Parse(body, tags, nextLevel, offset + endTag);
body = null;
}
General
• Constants versus Enums
Don’t keep using the old trick of public static final ints. Enums can
have methods and fields. This makes them very powerful tools that allow much
more expression and flexibility.
public enum HourlyPayGrade {
APPRENTICE {
public double rate() {
return 1.0;
}
},
MASTER {
public double rate() {
return 2.0;
}
};
public abstract double rate();
}
public class HourlyEmployee extends Employee {
private int tenthsWorked;
HourlyPayGrade grade;
public Money calculatePay() {
int straightTime = Math.min(tenthsWorked, TENTHS_PER_WEEK);
int overTime = tenthsWorked - straightTime;
return new Money(
grade.rate() * (tenthsWorked + OVERTIME_RATE * overTime)
);
}
/…
}
Clean Code

More Related Content

What's hot

Clean code: meaningful Name
Clean code: meaningful NameClean code: meaningful Name
Clean code: meaningful Name
nahid035
 

What's hot (20)

Clean code presentation
Clean code presentationClean code presentation
Clean code presentation
 
Clean Code
Clean CodeClean Code
Clean Code
 
The Clean Architecture
The Clean ArchitectureThe Clean Architecture
The Clean Architecture
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Naming Standards, Clean Code
Naming Standards, Clean CodeNaming Standards, Clean Code
Naming Standards, Clean Code
 
Clean code
Clean codeClean code
Clean code
 
Clean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionClean Code: Chapter 3 Function
Clean Code: Chapter 3 Function
 
Clean code
Clean codeClean code
Clean code
 
Clean code
Clean code Clean code
Clean code
 
Writing clean code
Writing clean codeWriting clean code
Writing clean code
 
Clean code
Clean codeClean code
Clean code
 
Clean code: meaningful Name
Clean code: meaningful NameClean code: meaningful Name
Clean code: meaningful Name
 
Clean Code summary
Clean Code summaryClean Code summary
Clean Code summary
 
Clean Code Principles
Clean Code PrinciplesClean Code Principles
Clean Code Principles
 
Strings in Java
Strings in Java Strings in Java
Strings in Java
 
Code Review
Code ReviewCode Review
Code Review
 
Clean code: understanding Boundaries and Unit Tests
Clean code: understanding Boundaries and Unit TestsClean code: understanding Boundaries and Unit Tests
Clean code: understanding Boundaries and Unit Tests
 
Clean Code
Clean CodeClean Code
Clean Code
 
Typescript ppt
Typescript pptTypescript ppt
Typescript ppt
 
Clean code
Clean codeClean code
Clean code
 

Similar to Clean Code

Clean code, Feb 2012
Clean code, Feb 2012Clean code, Feb 2012
Clean code, Feb 2012
cobyst
 
Agile_goa_2013_clean_code_tdd
Agile_goa_2013_clean_code_tddAgile_goa_2013_clean_code_tdd
Agile_goa_2013_clean_code_tdd
Srinivasa GV
 
CLEAN CODING AND DEVOPS Final.pptx
CLEAN CODING AND DEVOPS Final.pptxCLEAN CODING AND DEVOPS Final.pptx
CLEAN CODING AND DEVOPS Final.pptx
JEEVANANTHAMG6
 

Similar to Clean Code (20)

Coding Standards
Coding StandardsCoding Standards
Coding Standards
 
Clean code
Clean codeClean code
Clean code
 
Clean code, Feb 2012
Clean code, Feb 2012Clean code, Feb 2012
Clean code, Feb 2012
 
On Coding Guidelines
On Coding GuidelinesOn Coding Guidelines
On Coding Guidelines
 
Clean code and code smells
Clean code and code smellsClean code and code smells
Clean code and code smells
 
Principled And Clean Coding
Principled And Clean CodingPrincipled And Clean Coding
Principled And Clean Coding
 
Introduction to Software Engineering with C++
Introduction to Software Engineering  with C++Introduction to Software Engineering  with C++
Introduction to Software Engineering with C++
 
Clean code _v2003
 Clean code _v2003 Clean code _v2003
Clean code _v2003
 
The Sieve of Eratosthenes - Part 1
The Sieve of Eratosthenes - Part 1The Sieve of Eratosthenes - Part 1
The Sieve of Eratosthenes - Part 1
 
The Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsThe Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor corrections
 
Agile_goa_2013_clean_code_tdd
Agile_goa_2013_clean_code_tddAgile_goa_2013_clean_code_tdd
Agile_goa_2013_clean_code_tdd
 
Writing Clean Code (Recommendations by Robert Martin)
Writing Clean Code (Recommendations by Robert Martin)Writing Clean Code (Recommendations by Robert Martin)
Writing Clean Code (Recommendations by Robert Martin)
 
Best Coding Practices in Java and C++
Best Coding Practices in Java and C++Best Coding Practices in Java and C++
Best Coding Practices in Java and C++
 
Clean Code 2
Clean Code 2Clean Code 2
Clean Code 2
 
Oops lecture 1
Oops lecture 1Oops lecture 1
Oops lecture 1
 
CLEAN CODING AND DEVOPS Final.pptx
CLEAN CODING AND DEVOPS Final.pptxCLEAN CODING AND DEVOPS Final.pptx
CLEAN CODING AND DEVOPS Final.pptx
 
Metaprogramming
MetaprogrammingMetaprogramming
Metaprogramming
 
The Art of Clean code
The Art of Clean codeThe Art of Clean code
The Art of Clean code
 
C Programming - Refresher - Part IV
C Programming - Refresher - Part IVC Programming - Refresher - Part IV
C Programming - Refresher - Part IV
 
Can't Dance The Lambda
Can't Dance The LambdaCan't Dance The Lambda
Can't Dance The Lambda
 

Recently uploaded

Recently uploaded (20)

Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
Abortion ^Clinic ^%[+971588192166''] Abortion Pill Al Ain (?@?) Abortion Pill...
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
Tree in the Forest - Managing Details in BDD Scenarios (live2test 2024)
 
Breaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdfBreaking the Code : A Guide to WhatsApp Business API.pdf
Breaking the Code : A Guide to WhatsApp Business API.pdf
 
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAGAI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
AI/ML Infra Meetup | Reducing Prefill for LLM Serving in RAG
 
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERRORTROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
TROUBLESHOOTING 9 TYPES OF OUTOFMEMORYERROR
 
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
How Does XfilesPro Ensure Security While Sharing Documents in Salesforce?
 
INGKA DIGITAL: Linked Metadata by Design
INGKA DIGITAL: Linked Metadata by DesignINGKA DIGITAL: Linked Metadata by Design
INGKA DIGITAL: Linked Metadata by Design
 
AI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in MichelangeloAI/ML Infra Meetup | ML explainability in Michelangelo
AI/ML Infra Meetup | ML explainability in Michelangelo
 
A Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data MigrationA Guideline to Zendesk to Re:amaze Data Migration
A Guideline to Zendesk to Re:amaze Data Migration
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
 
top nidhi software solution freedownload
top nidhi software solution freedownloadtop nidhi software solution freedownload
top nidhi software solution freedownload
 
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product UpdatesGraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
GraphSummit Stockholm - Neo4j - Knowledge Graphs and Product Updates
 
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
Paketo Buildpacks : la meilleure façon de construire des images OCI? DevopsDa...
 
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
A Python-based approach to data loading in TM1 - Using Airflow as an ETL for TM1
 
Agnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in KrakówAgnieszka Andrzejewska - BIM School Course in Kraków
Agnieszka Andrzejewska - BIM School Course in Kraków
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FME
 
10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf10 Essential Software Testing Tools You Need to Know About.pdf
10 Essential Software Testing Tools You Need to Know About.pdf
 
AI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning FrameworkAI/ML Infra Meetup | Perspective on Deep Learning Framework
AI/ML Infra Meetup | Perspective on Deep Learning Framework
 

Clean Code

  • 1. by Dmytro Turskyi (March 2023) (2008) By Robert C. Martin (aka “Uncle Bob”)
  • 2. Agenda • Meaningful Names • Functions • Comments • Error Handling • Classes • Environment • General
  • 3. Meaningful Names • Avoid Mental Mapping A single-letter name is a poor choice; it’s just a place holder that the reader must mentally map to the actual concept. There can be no worse reason for using the name “c” than because “a” and “b” were already taken. • Method names Methods should have verb or verb phrase names like postPayment, deletePage, or save. Accessors, mutators, and predicates should be named for their value and prefixed with get…, set…, and is…
  • 4. Meaningful Names • Use Searchable Names const int WORK_DAYS_PER_WEEK = 5; int realDaysPerIdealDay = 4; int sum = 0; for (int j = 0; j < NUMBER_OF_TASKS; j++) { int realTaskDays = taskEstimate[ j ] * realDaysPerIdealDay; int realTaskWeeks = (realDays / WORK_DAYS_PER_WEEK); sum += realTaskWeeks; } for (int j = 0; j < 34; j++) { s += (t [ j ] * 4) / 5; } Single-letter names can ONLY be used as local variables inside short methods. The length of a name should correspond to the size of its scope
  • 5. Meaningful Names • Use Intention-Revealing Names If a name requires a comment, then the name does not reveal its intent. public List<int[]> getThem() { List<int[]> list1 = new ArrayList<>(); for (int[] x : theList) if (x[0] == 4) list1.add(x); return list1; } public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<>(); for (Cell cell : gameBoard) if (cell.isFlagged()) flaggedCells.add(cell); return flaggedCells; }
  • 6. Meaningful Names • Use Pronounceable Names class Customer { private Date generationTimestamp; private Date modificationTimestamp; private final String recordId = "102"; } class DtaRcrd102 { private Date genymdhms; private Date modymdhms; private final String pszqint = "102"; } If you can’t pronounce it, you can’t discuss it without sounding like an idiot.
  • 7. Meaningful Names • Class Names Manager, Processor, Data, Info. or
  • 8. Meaningful Names • Class Names Customer, WikiPage, Account, AddressParser. Classes and objects should have noun or noun phrase names and not include indistinct noise words: Manager, Processor, Data, Info.
  • 9. Functions • Small! The first rule of functions is that they should be small. Functions should hardly ever be ??? lines long. Blocks within if statements, else statements, while statements, and so on should be ??? long.
  • 10. Functions • Small! The first rule of functions is that they should be small. Functions should hardly ever be 20 lines long. Blocks within if statements, else statements, while statements, and so on should be one line long. Probably that line should be a function call. • Do One Thing To know that a function is doing more than “one thing” is if you can extract another function from it with a name that is not merely a restatement of its implementation.
  • 11. Functions • One Level of Abstraction per Function We want the code to read like a top-down narrative. We want every function to be followed by those at the next level of abstraction so that we can read the program, descending one level of abstraction at a time as we read down the list of functions. public String render() throws Exception { StringBuffer html = new StringBuffer(“<hr"); if(size > 0) html.append(" size="") .append(size + 1).append(“”"); html.append(">"); return html.toString(); } public String render() throws Exception { HtmlTag hr = new HtmlTag(“hr"); if (extraDashes > 0) hr.addAttribute(“size", hrSize(extraDashes)); return hr.html(); } private String hrSize(int height) { int hrSize = height + 1; return String.format("%d", hrSize); }
  • 12. Functions • Use Descriptive Names Don’t be afraid to make a name long. A long descriptive name is better than a short enigmatic name. A long descriptive name is better than a long descriptive comment. • Dependent Functions. If one function calls another, they should be vertically close, and the caller should be above the callee, if at all possible.
  • 13. Functions • Function Arguments The ideal number of arguments for a function is ??? . includeSetupPageInto(newPageContent) or
  • 14. Functions • Function Arguments The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. includeSetupPage() includeSetupPageInto(newPageContent)
  • 15. Functions • Flag Arguments Flag arguments are ugly. Passing a boolean into a function is a truly terrible practice. It immediately complicates the signature of the method, loudly proclaiming that this function does more than one thing. It does one thing if the flag is true and another if the flag is false! render(boolean isSuite) renderForSuite() renderForSingleTest()
  • 16. Functions • Have No Side Effects public boolean checkPassword(String userName, String password) { User user = UserGateway.findByName(userName); if (user != User.NULL) { String codedPhrase = user.getPhraseEncodedByPassword(); String phrase = cryptographer.decrypt(codedPhrase, password); if ("Valid Password".equals(phrase)) { Session.initialize(); return true; } } return false; }
  • 17. Functions • Have No Side Effects Side effects are lies. public boolean checkPassword(String userName, String password) { User user = UserGateway.findByName(userName); if (user != User.NULL) { String codedPhrase = user.getPhraseEncodedByPassword(); String phrase = cryptographer.decrypt(codedPhrase, password); if ("Valid Password".equals(phrase)) { Session.initialize(); return true; } } return false; } checkPasswordAndInitializeSession
  • 18. Functions • Output Arguments For example: appendFooter(s); Does this function append “s” as the footer to something? Or does it append some footer to “s”? Is “s” an input or an output? It doesn’t take long to look at the function signature and see, but anything that forces you to check the function signature is equivalent to a double- take. It’s a cognitive break and should be avoided. public void appendFooter(StringBuffer report) report.appendFooter();
  • 19. Comments // Check to see if the employee is eligible // for full benefits if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) or
  • 20. Comments • Explain Yourself in Code Only the code can truly tell you what it does. Comments are, at best, a necessary evil. Rather than spend your time writing the comments that explain the mess you’ve made, spend it cleaning that mess. Inaccurate comments are far worse than no comments at all. if (employee.isEligibleForFullBenefits()) // Check to see if the employee is eligible // for full benefits if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))
  • 21. Comments • Legal Comments Sometimes our corporate coding standards force us to write certain comments for legal reasons. // Copyright (C) 2003,2004,2005 by Object // Mentor, Inc. All rights reserved. // Released under the terms of the GNU // General Public License version 2 or later. • Explanation of Intent Sometimes a comment goes beyond just useful information about the implementation and provides the intent behind a decision. // This is our best attempt to get a race condition // by creating large number of threads. for (int i = 0; i < 25000; i++) { WidgetBuilderThread widgetBuilderThread = new WidgetBuilderThread(widgetBuilder, text, parent, failFlag); Thread thread = new Thread(widgetBuilderThread); thread.start(); }
  • 22. Comments • Warning of Consequences Sometimes it is useful to warn other programmers about certain consequences. public static SimpleDateFormat makeStandardHttpDateFormat() { //SimpleDateFormat is not thread safe, //so we need to create each instance independently. SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z"); df.setTimeZone(TimeZone.getTimeZone("GMT")); return df; } • TODO Comments Nowadays, most good IDEs provide special gestures and features to locate all the //TODO comments, so it’s not likely that they will get lost. //TODO-MdM these are not needed // We expect this to go away when we do the // checkout model protected VersionInfo makeVersion() throws Exception{ return null; }
  • 23. Comments • Amplification A comment may be used to amplify the importance of something that may otherwise seem inconsequential. String listItemContent = match.group(3).trim(); // the trim is real important. It removes the starting // spaces that could cause the item to be recognised // as another list. new ListItemWidget(this, listItemContent, this.level + 1); return buildList(text.substring(match.end())); • Public APIs There is nothing quite so helpful and satisfying as a well- described public API. It would be difficult, at best, to write programs without them. /// dart doc comment /** * JavaDoc comment */
  • 24. Comments • Commented-Out Code We’ve had good source code control systems for a very long time now. Those systems will remember the code for us. We don’t have to comment it out any more. Just delete the code. • Position Markers In general they are clutter that should be eliminated— especially the noisy train of slashes at the end. If you overuse banners, they’ll fall into the background noise and be ignored. // Actions ////////////////////////////////// InputStreamResponse response = new InputStreamResponse(); response.setBody(formatter.getResultStream(), formatter.getByteCount()); // InputStream resultsStream = formatter.getResultStream(); // StreamReader reader = new StreamReader(resultsStream); // response.setContent(reader.read(formatter.getByteCount()));
  • 25. Error Handling • Don’t Return Null When we return null, we are essentially creating work for ourselves and foisting problems upon our callers. All it takes is one missing null check to send an application spinning out of control. 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(); }
  • 26. Error Handling • Don’t Pass Null In most programming languages there is no way to deal with a null that is passed by a caller accidentally. Because this is the case, the rational approach is to forbid passing null by default. When you do, you can code with the knowledge that a null in an argument list is an indication of a problem, and end up with far fewer careless mistakes. calculator.xProjection(null, new Point(12, 13));
  • 27. Classes • Classes Should Be Small! With functions we measured size by counting physical lines. With classes we use a different measure. We count ???.
  • 28. Classes • Classes Should Be Small! With functions we measured size by counting physical lines. With classes we use a different measure. We count responsibilities. The Single Responsibility Principle (SRP) states that a class or module should have one, and only one, reason to change. The name of a class should describe what responsibilities it fulfills. The more ambiguous the class name, the more likely it has too many responsibilities. The problem is that too many of us think that we are done once the program works. We move on to the next problem rather than going back and breaking the overstuffed classes into decoupled units with single responsibilities.
  • 29. Classes public class SuperDashboard extends JFrame implements MetaDataUser public String getCustomizerLanguagePath() public void setSystemConfigPath(String systemConfigPath) public String getSystemConfigDocument() public void setSystemConfigDocument(String systemConfigDocument) public boolean getGuruState() public boolean getNoviceState() public boolean getOpenSourceState() public void showObject(MetaObject object) public void showProgress(String s) public void setACowDragging(boolean allowDragging) public boolean allowDragging() public boolean isCustomizing() public void setTitle(String title) public IdeMenuBar getIdeMenuBar() public void showHelper(MetaObject metaObject, String propertyName) // ... many non-public methods follow ... } public class Version { public int getMajorVersionNumber() public int getMinorVersionNumber() public int getBuildNumber() }
  • 30. Environment • Build Requires More Than One Step Building a project should be a single trivial operation. You should not have to check many little pieces out from source code control. You should be able to check out the system with one simple command and then issue one other simple command to build it. svn get mySystem cd mySystem ant all • Tests Require More Than One Step You should be able to run all the unit tests with just one command. In the best case you can run all the tests by clicking on one button in your IDE.
  • 31. General • Artificial Coupling In general an artificial coupling is a coupling between two modules that serves no direct purpose. It is a result of putting a variable, constant, or function in a temporarily convenient, though inappropriate, location. For example, general enumsshould not be contained within more specific classes because this forces the whole application to know about these more specific classes. The same goes for general purpose static functions being declared in specific classes. • Prefer Polymorphism to If/Else or Switch/Case There may be no more than one switch statement for a given type of selection. The cases in that switch statement must create polymorphic objects that take the place of other such switch statements in the rest of the system.
  • 32. General • Replace Magic Numbers with Named Constants In general it is a bad idea to have raw numbers in your code. You should hide them behind well-named constants. The term “Magic Number” does not apply only to numbers. It applies to any token that has a value that is not self-describing. assertEquals(7777, Employee.find(“John Doe”).employeeNumber()); assertEquals( HOURLY_EMPLOYEE_ID, Employee.find(HOURLY_EMPLOYEE_NAME).employeeNumber());
  • 33. General • Encapsulate Conditionals Boolean logic is hard enough to understand without having to see it in the context of an if or while statement. Extract functions that explain the intent of the conditional. if (shouldBeDeleted(timer)) if (timer.hasExpired() && !timer.isRecurrent()) • Avoid Negative Conditionals Negatives are just a bit harder to understand than positives. So, when possible, conditionals should be expressed as positives. if (buffer.shouldCompact()) if (!buffer.shouldNotCompact())
  • 34. General • Encapsulate Boundary Conditions Boundary conditions are hard to keep track of. Put the processing for them in one place. if (level + 1 < tags.length) { parts = new Parse(body, tags, level + 1, offset + endTag); body = null; } int nextLevel = level + 1; if (nextLevel < tags.length) { parts = new Parse(body, tags, nextLevel, offset + endTag); body = null; }
  • 35. General • Constants versus Enums Don’t keep using the old trick of public static final ints. Enums can have methods and fields. This makes them very powerful tools that allow much more expression and flexibility. public enum HourlyPayGrade { APPRENTICE { public double rate() { return 1.0; } }, MASTER { public double rate() { return 2.0; } }; public abstract double rate(); } public class HourlyEmployee extends Employee { private int tenthsWorked; HourlyPayGrade grade; public Money calculatePay() { int straightTime = Math.min(tenthsWorked, TENTHS_PER_WEEK); int overTime = tenthsWorked - straightTime; return new Money( grade.rate() * (tenthsWorked + OVERTIME_RATE * overTime) ); } /… }