You are reading about clean code for two reasons. First, you are a programmer. Second, you want to be a better programmer. Good. We need better programmers.
Learning to write clean code is hard work. It requires more than just the knowledge of principles and patterns. You must sweatover it. You must practice it yourself, and watchyourself fail. You must watch others practice it and fail. You must see them stumble andretrace their steps. You must see them agonize over decisions and see the price they pay formaking those decisions the wrong way.
Quotes from many computer scientists are quoted in the book, but I (Mahziar Eghdami) think this is the most comprehensive definition of clean code. that Uncle Bob brought in the book.
Clean code can be read, and enhanced by a developer other than its original author. It has unit and acceptance tests. It has meaningful names. It provides one way rather than many ways for doing one thing. It has minimal dependencies, which are explicitly defined, and provides a clear and minimal API. Code should be literate since depending on the language, not all necessary information can be expressed clearly in code alone.
-- Dave Thomas, CEO of Object Technology International Inc. (formerly OTI, now IBM OTI Labs)
Names are everywhere in software. We name our variables, our functions, our arguments,classes, and packages. We name our source files and the directories that contain them. Wename our jar files and war files and ear files. We name and name and name. Because we do
Choosing good names takes time but saves more than it takes. So take care with your names and change them when you find better ones.
clarity is king.
Bad ❌
const a = 'Mahziar';
Good ✔️
const userName = 'Mahziar';
The name of a variable, function, or class, should answer all the big questions. Itshould tell you why it exists, what it does, and how it is used. If a name requires a com-ment, then the name does not reveal its intent.
Bad ❌
// Check that is the user online?
let state = false;
Good ✔️
let isOnline = false;
Programmers create problems for themselves when they write code solely to satisfy a compiler or interpreter. For example, because you can’t use the same name to refer to two different things in the same scope, you might be tempted to change one name in an arbitrary way. If names must be different, then they should also mean something different.
Bad ❌
getUsersData();
getUsersInfo();
Good ✔️
getUsersGeneralData();
getUsersDetailsData();
Humans are good at words. A significant part of our brains is dedicated to the concept of words. And words are, by definition, pronounceable.
Bad ❌
const genymdhms;
const modymdhms;
Good ✔️
const generationTimestamp;
const modificationTimestamp;
Classes and objects should have noun or noun phrase names like Customer, WikiPage, Account, and Address Parser. Avoid words like Manager, Processor, Data, or Info in the name of a class. A class name should not be a verb.
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.
Users.getUserName
Customars.setPurchaseInfo
For example, don’t use the name whack()to mean kill(). Don’t tell little culture-dependent jokes like eatMyShorts()to mean abort(). Say what you mean. Mean what you say.
Pick one word for one abstract concept and stick with it. for example if you use district word as a concept, and you save the data related to this concept as district, don't name it zone in another module.
The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.
The shorter the functions, the more they help to debug.
FUNCTIONS SHOULD DO ONE THING. THEY SHOULD DO IT WELL. THEY SHOULD DO IT ONLY.
In the following example, we have a function named setup() that goes through three steps: capture, restructure, and store data. so this function is doing three things and we should extract it to three functions.
Bad ❌
setup();
Good ✔️
const appData = getAppDataFromServer();
const organizedAppData = changeAppDataStructure(appData)
setAppDataInLocalStorage(organizedAppData);
The ideal number of arguments for a function is zero. Next comes one, followed closely by two. Three arguments should be avoided where possible. More than three requires very special justification—and then shouldn’t be used anyway. Arguments are hard. They take a lot of con-ceptual power.
Destructuring is a good way to avoid this mistake
no side effects. Functions are not allowed to do more than their type definition says. For example, a function that takes an Int and returns an Int cannot change global variables, access filesystem, do network requests, etc. It can only do some transformations on the input and return some value. also Side effects are lies. because Your function promises to do one thing, but it also does other hidden things.
The function should only work in its own domain
Bad ❌
const addNumberToBlackList = (
blackList, phoneNumberDetails
) => {
const { number, owner } = phoneNumberDetails;
blackList.push({ number, owner });
}
Good ✔️
const addNumberToBlackList = (
blackList, phoneNumberDetails
) => {
const { number, owner } = phoneNumberDetails;
return (...blackList, { number, owner });
}
Do your absolute best to avoid duplicate code. Duplicate code is bad because it means that there's more than one place to alter something if you need to change some logic.
Imagine if you run a restaurant and you keep track of your inventory: all your tomatoes, onions, garlic, spices, etc. If you have multiple lists that you keep this on, then all have to be updated when you serve a dish with tomatoes in them. If you only have one list, there's only one place to update!
Nothing can be quite so helpful as a well-placed comment. Nothing can be quite so damaging as an old crafty comment that propagates lies and misinformation. Comments are not like Schindler’s List. They are not “pure good.” Indeed, comments are, at best, a necessary evil.
The proper use of comments is to compensate for our failure to express ourself in code. Note that I used the word failure. I meant it. Comments are always failures. We must have them because we cannot always figure out how to express ourselves without them, but their use is not a cause for celebration.
When you find yourself in a position where you need to write a comment, think it through and see whether there isn’t some way to turn the tables and express yourself in code.
There are certainly times when code makes a poor vehicle for explanation. Unfortunately, many programmers have taken this to mean that code is seldom, if ever, a good means forexplanation. This is patently false. Which would you rather see? This:
Good ✔️
const addNumberToBlackList = (
blackList, phoneNumberDetails
) => {
const { number, owner } = phoneNumberDetails;
return (...blackList, { number, owner });
}
One of the more common motivations for writing comments is bad code. We write a mod-ule and we know it is confusing and disorganized. We know it’s a mess. So we say to our-selves, “Ooh, I’d better comment that!” No! You’d better clean it!
It is sometimes reasonable to leave “To do” notes in the form of //TODO comments. In the following case, the TODO comment explains why the function has a degenerate implementation and what that function’s future should be. TODOs are jobs that the programmer thinks should be done.
try {
const result = getSelectedThemeByUser(username);
if (result) {
const {
primary_color,
secondary_color,
icons_json
} = result;
setPrimaryColor(primary_color);
setSecondaryColor(secondary_color);
setIconsList(icons_json);
}
} catch {
// TODO: Set Default Values
}
Sometimes people add a comment to the start of a module every time they edit it. Thesecomments accumulate as a kind of journal, or log, of every change that has ever beenmade. I have seen some modules with dozens of pages of these run-on journal entries.
/**
* Changes (from 11-Oct-2001)
* --------------------------
* 11-Oct-2001 : Re-organised the class and moved it to new package
* com.jrefinery.date (DG);
* 05-Nov-2001 : Added a getDescription() method, and eliminated NotableDate
* class (DG);
* 12-Nov-2001 : IBD requires setDescription() method, now that NotableDate
* class is gone (DG); Changed getPreviousDayOfWeek(),
* getFollowingDayOfWeek() and getNearestDayOfWeek() to correct
* bugs (DG);
* 05-Dec-2001 : Fixed bug in SpreadsheetDate class (DG);
* 29-May-2002 : Moved the month constants into a separate interface
* (MonthConstants) (DG);
* 27-Aug-2002 : Fixed bug in addMonths() method, thanks to N???levka Petr (DG);
* 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
* 13-Mar-2003 : Implemented Serializable (DG); * 29-May-2003 : Fixed bug in addMonths method (DG);
* 04-Sep-2003 : Implemented Comparable. Updated the isInRange javadocs (DG);
* 05-Jan-2005 : Fixed bug in addYears() method (1096282) (DG);
*/
Sometimes you see comments that are nothing but noise. They restate the obvious and provide no new information.
// Hooks (React Component state)
const [state, setState] = useState(null);
No, 😲 really? Oh how about this:
class Greeting extends React.Component
{
// Class Constructor
constructor (props) {
// ...
}
}
Sometimes programmers like to mark a particular position in a source file. For example, Irecently found this in a program I was looking through:
// Actions //////////////////////////////////
There are rare times when it makes sense to gather certain functions together beneath abanner like this. But in general they are clutter that should be eliminated—especially thenoisy train of slashes at the end.
You should take care that your code is nicely formatted. You should choose a set ofsimple rules that govern the format of your code, and then you should consistently apply those rules. If you are working on a team, then the team should agree to a single set of formatting rules and all members should comply. It helps to have an automated tool that can apply those formatting rules for you.
Code formatting is about communication, and communication is the professional developer’s first order of business.
so capitalization tells you a lot about your variables, functions, etc. These rules are subjective, so your team can choose whatever they want. The point is, no matter what you all choose, just be consistent.
Bad ❌
const DAYS_IN_WEEK = 7;
const daysInMonth = 30;
const songs = ["Back In Black", "Stairway to Heaven", "Hey Jude"];
const Artists = ["ACDC", "Led Zeppelin", "The Beatles"];
const eraseDatabase = () => {}
const restore_database = () => {}
class animal {}
class Alpaca {}
Good ✔️
const DAYS_IN_WEEK = 7;
const DAYS_IN_MONTH = 30;
const SONGS = ["Back In Black", "Stairway to Heaven", "Hey Jude"];
const ARTISTS = ["ACDC", "Led Zeppelin", "The Beatles"];
function eraseDatabase() {}
function restoreDatabase() {}
class Animal {}
class Alpaca {}
- PascalCase 👨 :mostly used for React Components.
- camelCase 🐫: mostly used for variables and functions names.
- snake_case 🐍: mostly used for naming database fields.
- kebab-case 🥙: mostly used for naming ids and classes in html elements.
- UPPER_SNAKE_CASE ⬆️ 🐍: mostly used for naming config variables
to be continued...
Copyright (C) 2021 MAHZIAR EGHDAMI.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".