-
Notifications
You must be signed in to change notification settings - Fork 0
Clean Code
CLEAN CODE “We are Authors”
DRY : Don't Repeat Yourself YAGNI : You Ain't Gonna Need It 7 rule : Remembering more than 7 items is difficult. So ensure that we limit the variables/params to a function to less than 7
1.0 Principles
3 Core Principles:-
- Right tool: One Language Per File. Ex: Html in .html , Styles in .css, Javascript in .js
- High Signal to Noise ratio: TED - Terse (using few words), Expressive, Do One thing Noise: - High Cyclomatic Complexity - Excessive Indentation - Zombie Code - Unnecessary Comments - Poorly named structures - Huge Classes - Long methods - Repetition - No Whitespace - Overly verbose
- Self-Documenting: Clear intent Layers of Abstractions Format for readability Favor Code over Comments
NOTE: Every Tech is Potential Evil Linq-to-Sql: No for - Massive Queries Outer Joins Flash/Silverlight: No for - When native is an option Javascript: No for - Sole Validation Proprietary Logic DRY : Don't repeat yourself - No Copy & Paste - Decreases Signal to noise ratio - Increases the number of lines of code (lines in code == weight in airplane) - Maintenance problem - Many of same principles as relational DB normalization
- Naming matters
- Readability : understanding the intent of the code
Dirty: List p = new List() { 5.50m, 10.48m, 12.69m }; decimal t = 0; foreach (var i in p) { t += i; } return t;
Clean: List prices = new List() { 5.50m, 10.48m, 12.69m }; decimal total = 0; foreach (var price in prices) { total += price; } return total;
CLASS Names: Dirty: WebsiteBO Utility Common MyFunctions MikesObjects *Manager / *Processor / *Info
Clean: - 1. Nouns (Not Verbs) 2. Be Specific 3. Single Responsibility 4. Avoid Generic Suffixes User Account QueryBuilder ProductRepository
METHOD names: Dirty: Get Process Pending DoIt Start On_Init, Page_Load,etc. - Named based on when it is called not what it does
Clean: GetRegisteredUsers isvalidSubmission ImportDocument SendEmail
WARNING SIGNS: And, If, Or - Probably doing too many things -> Split
ABBREVIATIONS: No
- Difficult to have a conversation with others.
- Abbreviations may have different meanings.
BOOLEAN Values: Dirty: - open, start, status, login Ex: if(login) {} Clean: - isOpen, done, isActive, loggedIn Ex: if(loggedIn){}
SYMMETRY: Dirty: on/disable quick/slow lock/open slow/max
Clean: on/off fast/slow lock/unlock min/max
- Clear Intent
- Use the right tool
- Bite-size logic
- Sometimes code isn't the answer
ASSIGN BOOLEAN IMPLICITLY Dirty: bool goingOut;
if(cashInwallet > 6) { goingOut = true; } else { goingOut = false; }
Clean: bool goingOut = cashInWallet > 6;
POSITIVE CONDITIONALS: Dirty: if(!isNotLoggedIn) Clean: if(loggedIn)
TERNARY ELEGANCE:
Dirty: int registrationFee;
if(isSpeaker) { registrationFee = 0; } else { registrationFee = 50; }
Clean: int registrationFee = isSpeaker ? 0 : 50;
STRINGLY TYPED:
Dirty: if (employeeType = "manager")
Clean: if (employeeType = Enums.EmployeeType.Manager)
Benefits:
- No Typos
- Intellisense support
- Searchable, References
MAGIC NUMBERS: Dirty: If(age > 21) { } If (status == 2) { }
Clean: Const int legalDrinkingAge = 21; If (age > legalDrinkingAge) { }
If (status == Status.Active) { }
COMPLEX CONDITIONALS If (car.Year > 1980 && (car.Make == “Ford” || car.Make == “Chevrolet”) && car.Odometer < 100000 && car.Vin.StartsWith(“V2”) || car.Vin.StartsWith(“VIA3”)) {
}
Better:
- Intermediate variables
- Encapsulate with a function
Dirty: If (employee.Age > 55 && employee.YearsEmployed > 10 && employee.IsRetired == true) { }
Clean: Bool eligibleForPension = employee.Age > MinretirementAge && employee.YearsEmployed > MinPensionEmploymentYears && employee.IsRetired;
Dirty: If (fileExtension == “mp4” || fileExtension == “mpg” || fileExtension == “avi”) && (isAdmin || isActiveFile)
Clean: If (ValidFileRequest(fileExtension, isActiveFilem isAdmin))
POLYMORPHISM vs ENUMS Instead of Switch statements use Polymorphism : Parent – Child Classes
BE DECLARATIVE C# : LINQ to Objects JavaScript : jLinq Java : Lambdaj Python : Pynq
Dirty: Var matchingUsers = new List();
foreach (var user in users) { If(user.AccountBalance < minimumAccountBalance && user.Status == Status.active) { matchingUsers.Add(user); } }
Return matchingUsers;
Clean: Return users .Where(u => u.AccountBalance < minimumAccountBalance ) .Where(u => u.Status == Status.Active );
Function v/s Method: Method – Methods are associated with an Object
When to Create a Function: Duplication Indentation Unclear Intent – Well named method If code does > 1 Task - SRP
Avoid Duplicity: DRY, Code is liability, Less is more
Excessive Indentation Overview: If there are more than 3 if conditions Solutions:
- Extract Method
- Return Early Use a return when it enhances readability… In certain routines, once you know the answer.. not returning immediately means that you have to write more code. – Steve McConnell, “Code Complete”
- Fail Fast Throw exception as soon as possible Ensure you throw an exception in “default” switch clause. And log the value you ae checking.
Convey Intent: Instead of condition check, encapsulate the logic inside a method which has a meaningful name.
Do One Thing: SRP for a function
- Aids the reader
- Promotes reuse
- Eases naming and testing
- Avoids side-effects
Mayfly Variables: Do not create variables at the beginning as developer has to remember everything Declare variables where its used. JIT Mayfly shortest lifespan 30mins – 24 hours
Parameters: Too many parameters is difficult to understand
- Strive for 0 – 2 parameters
- Easier to understand
- Easier to test
- Helps assure function does one thing
Should not have flag arguments: Dirty: private void Saveuser(User user, bool emailUser) { // some logic to save user If (emailUser) { // send email to user } }
Clean: private void Saveuser(User user) { // some logic to save user }
private void Emailuser(User user) { // send email to user }
What’s Too Long:
- If there are more comments and whitespaces
- Scrolling required
- Function naming issues
- Multiple Conditionals
- Hard to digest (max 7 params/variables)
Funciton should Rarely be over 20 lines, Harldy ever over 100 lines, No more than 3 parameters – Robert C.Martin, “Clean Code”
Exceptions:
- Kinds of Exceptions o Unrecoverable: Null reference, File not found, Access denied o Recoverable: Retry Connection, Try different file, Wait and try again o Ignorable: Logging
- Do not catch an exception if you are not handling it. Let it flow
Dirty: try { // many // lines // of // complicated // code // and // verbose // logic // here } Catch() { // do something here }
Clean: try { SaveThePlanet(); } Catch() { // do something here }
Private void SaveThePlanet() { // many // lines // of // complicated // code // and // verbose // logic // here }
When to Create a Class?
- New Cocept: Model an object, Abstract or real-world
- Low Cohesion: Methods in a class are less linked to each other
- Promote Reuse: Small, targeted
- Reduce Complexity: Solve once, hide away
- Clarify parameters: Complex datastructure
Cohesion: High – Class responsibilities should be strongly-related
- Enhances readability
- Increase likelihood of reuse
- Avoids attracting the lazy: generic names to a class will make you to write every logic about it in that class
- Watch for methods that don’t interact with the rest of the class
- Watch for fields that are used only by One method
- Watch for Classes that change Often
Dirty: Low Cohesion Vehicle class
- Edit vehicle options
- Update pricing
- Schedule mainetenance
- Send maintenance reminder
- Select financing
- Calculate monthly payment
Clean: High Cohesion Vehicle class
- Edit vehicle options
- Update pricing VehicleMaintenance class
- Schedule maintenance
- Send maintenance reminder VehicleFinance class
- Select financing
- Calculate monthly payment
When is a Class to Small?
- Two classes have High Cohesion
- Too many pieces – Too many classes will create difficulty for maintainance
Primitive Obsession: Dirty: private void Saveuser(string firstName, string lastName, string state, string zip, string eyeColor, string phone, string fax, string maidenName)
Clean: private void SaveUser(User user)
- Helps reader conceptualize
- Implicit -> Explicit
- Encapsulation: new property added, will not affect the method signature
- Aids maintenance
- If a method uses only two properties of User class, pass it explicitly so that the intention of the method is clear
Principle of Proximity: Low priority – Only when possible
- Strive to make code read top to bottom when possible
- Keep related actions together
Outline Rule:
- Collapsed code should read like an outline