- Introduction
- Variables
- Functions
- Comments
- Code Structure
- Tests
- Objects
- Code smells
- 2002 - Agile Software Development
- 2009 - Clean Code: A Handbook of Agile Software Craftsmanship
- 2011 - The Clean Coder: A Code Of Conduct For Professional Programmers
Note: Quelqu'un peut-il me dire comment reconnaitre un mauvais code ?
SOLID
The single-responsibility principle: "There should never be more than one reason for a class to change."
The open-closed principle: "Software entities ... should be open for extension, but closed for modification."
The Liskov substitution principle: "Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it."
The interface segregation principle: "Many client-specific interfaces are better than one general-purpose interface."
The dependency inversion principle: "Depend upon abstractions, not concretions."
You should name a variable using the same care with which you name a first-born child. - Robert C. Martin
int d; // elapsed time in day
int timeElapsedInDays;
int daysSinceCreation;
int daysElapsedCreation;
int daysSinceModification;
Note: Avez vous une meilleur idee pour nommer la variable ? exception: on peut utiliser des noms plus courts
- "Humans are good at words"
class Customer {
private crtTs: number;
private csInt: number;
}
class Customer {
private creationTimestamp: number;
private customerId: number;
}
.titanic {
float: none;
}
var bobTheBuilder = new ApplicationBuilder(config);
database.holyHandGrenade(); // reset the database
const brokers = 'url.com,url2.com';
brokers.split(','); // ['url.com', 'url2.com']
explode(",", $brokers);
Note: Est-ce qu'un developpeur de php peut nous aider, Comment s'appelle la fonction qui split en PHP ? Fin sur les variables, transitions functions
The first rule of functions is that they should be small. The second rule, is that they should be smaller than that. - Robert C. Martin
Example: HtmlUtils.java from framework 'FitNesse'
public static String testableHtml(PageData pageData, boolean includeSuiteSetup) throws Exception {
WikiPage wikiPage = pageData.getWikiPage();
StringBuffer buffer = new StringBuffer();
if (pageData.hasAttribute("Test")) {
if (includeSuiteSetup) {
WikiPage suiteSetup = PageCrawlerImpl.getInheritedPage(SuiteResponder.SUITE_SETUP_NAME, wikiPage);
if (suiteSetup != null) {
WikiPagePath pagePath = suiteSetup.getPageCrawler().getFullPath(suiteSetup);
String pagePathName = PathParser.render(pagePath);
buffer.append("!include -setup .")
.append(pagePathName)
.append("\n");
}
}
WikiPage setup = PageCrawlerImpl.getInheritedPage("SetUp", wikiPage);
if (setup != null) {
WikiPagePath setupPath = wikiPage.getPageCrawler().getFullPath(setup);
String setupPathName = PathParser.render(setupPath);
buffer.append("!include -setup .")
.append(setupPathName)
.append("\n");
}
}
buffer.append(pageData.getContent());
if (pageData.hasAttribute("Test")) {
WikiPage teardown = PageCrawlerImpl.getInheritedPage("TearDown", wikiPage);
if (teardown != null) {
WikiPagePath tearDownPath =
wikiPage.getPageCrawler().getFullPath(teardown);
String tearDownPathName = PathParser.render(tearDownPath);
buffer.append("\n")
.append("!include -teardown .")
.append(tearDownPathName)
.append("\n");
}
if (includeSuiteSetup) {
WikiPage suiteTeardown = PageCrawlerImpl.getInheritedPage(SuiteResponder.SUITE_TEARDOWN_NAME, wikiPage);
if (suiteTeardown != null) {
WikiPagePath pagePath = suiteTeardown.getPageCrawler().getFullPath(suiteTeardown);
String pagePathName = PathParser.render(pagePath);
buffer.append("!include -teardown .")
.append(pagePathName)
.append("\n");
}
}
}
pageData.setContent(buffer.toString());
return pageData.getHtml();
}
Note: Eurk. On va vite fais essayer de comprendre. WTF!
public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) throws Exception {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
StringBuffer newPageContent = new StringBuffer();
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent.toString());
}
return pageData.getHtml();
}
- Functions should be short, 20 lines is already a lot !
- Functions should have 1 (or 2) indentation level.
- One function = One abstraction level.
Note: Laisser quelques secondes pour comprendre. On lit de haut en bas, comme une histoire
Abstraction Level: The amount of complexity by which a system is viewed or programmed. The higher the level, the less detail. The lower the level, the more detail. Si je ton neveu demande comment fonctionne une voiture et que tu m'explique comment sont fabriqués les freins, tu es au mauvais niveau d'abstraction.
FUNCTIONS SHOULD ONLY DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY. - Robert C. Martin
public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) throws Exception {
if (isTestPage(pageData))
includeSetupAndTeardownPages(pageData, isSuite);
return pageData.getHtml();
}
- "Pour... Si... Alors..."
function async getUser(id: string): Promise<User> {
const user = await db.find({ user: id });
await db.close();
return user;
}
- Be careful with "side effects". A function should only do what the name suggests.
let numbers = [1,2,3,4,5];
const firstThreeNumbers = numbers.splice(0,3);
const lastThreeNumbers = numbers.splice(2,5);
let numbers = [1,2,3,4,5]; // 1,2,3,4,5
const firstThreeNumbers = numbers.splice(0,3);
// firstThreeNumbers = 1,2,3
// AND numbers = 4,5
const lastThreeNumbers = numbers.splice(2,5);
// lastThreeNumbers = undefined
- Limit "in/out" parameters. Or don't use them.
function initDb(config: Config, useHttps: boolean) {
...
}
- Limit booleans parameters
- Limit the numbers of parameters
Don't comment bad code... Rewrite it - Robert C. Martin
- Comments are always failure. Failure to use the coding language to express yourself.
- Code changes. Comments can become liabilities.
- Sometimes, they are still necessary... And it feels bad to use them !
Note: Vous faites un oral d'anglais, vous dites des mots français pour vous rattraper
// Check if employee is eligible for full benefits
if ((employee.flags && HOURLY_FLAG) && (employee.age > 65))
if (employee.isEligibleForFullBenefits())
- "This code is hard to read, i should add comments"
- "NO! You should clean it!"
// does the module from the global list <mod> depend on the
// subsystem we are part of?
if (smodule.getDependSubSystems()
.contains(subSysMod.getSubSystems()))
ArrayList moduleDependees = smodule.getDependSubSystems();
String ourSubSystem = subSysMod.getSubSystem();
if (moduleDependees.contains(ourSubSystem))
// format matched: hh:mm:ss EEE, MMM dd, yyyy
Pattern timeMatcher = Pattern.compile("\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*");
function compareUsers(user1: User, user2: User): boolean {
if(!user1.name || !user2.name) {
// if no name is found, we shall use their id
return user1.id - user2.id;
}
return user1.name > user2.name;
}
// TODO
// function to be removed when the checkout model is released
function makeVersion(): number {
return '0.0.1';
}
- Separate concepts vertically
- Related code should appear vertically dense
- Declare variables close to their usage
- Dependent functions should be close
- Similar functions should be close
- Place functions in the downward direction
- Keep lines short
- Don't use horizontal alignment
- Use white space to associate related things and dissociate weakly related
- Don't break indentation
- One assert per test
- Readable
- Fast
- Independent
- Repeatable
- Hide internal structure
- Prefer data structures
- Avoid hybrid (half object and half data)
- Should be small
- Do ONE thing
- Small number of instance variables
- Base class should know nothing about their derivatives
- Better to have many functions than to pass code into a function
- Prefer non-static methods
- Rigidity (The software is difficult to change)
- Fragility (The software breaks in many places due to a single change)
- Immobility (You can not reuse parts of the code in other projects)
- Needless Complexity
- Needless Repetition
- Opacity (The code is hard to read)
<textarea style="width:70%; min-height:400px"> Main points: Variables : should be named carefully. Functions : should be short ! and keep it at one abstraction level. Comments : should not be your favourite solution. Let's discuss : Should we enforce it ? What could we do to enforce it ? </textarea>