Skip to content

Clean Code

Sandesh Kota edited this page Jan 9, 2018 · 9 revisions

CLEAN CODE “We are Authors”

0.0 Principles – Global Collection

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:-

  1. Right tool: One Language Per File. Ex: Html in .html , Styles in .css, Javascript in .js
  2. 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
  3. 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

2.0 Naming

  • 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

3.0 Conditionals

  1. Clear Intent
  2. Use the right tool
  3. Bite-size logic
  4. 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 );

4.0 Functions

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 }

5.0 Classes

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

6.0 Comments

  • A Necessity and a Crutch

General Rules:

  • Prefer expressive code over comments
  • Use comments ONLY when code alone can’t be sufficient

Comments to Avoid:

  1. Redundant Dirty: Int i =1; // Set i = 1

  2. Intent Dirty: // Assure user’s account is deactivated If (user.Status == Status.Inactive) Clean: o Improved function naming o Intermediate variable o Constant or enum o Extract conditional to function

  3. Apologies and Warnings Dirty: // sorry, this crashes a lot so I’m just swallowing the exception // To be refactored

// Great sins against code // begin here…

Clean: o Fix it before commit / merge o Add a TODO marker comment if you must

  1. Zombie Code – Commented Code a. Risk Aversion – comment to solve b. Hoarding mentality – may be useful

  2. Divider Comments a. Used to divide a method to sections

  3. Brace Tracker Comments a. For Conditions, explaining the braces i. // end user login ii. // end user for loop

  4. Bloated Header a. Explaining the class responsibility at the header b. With Author, CreatedDate etc.. – Can be accessed via Source Control

  5. Defect Log a. Do not log defect fix IDs i. // DEFECT #PRJ-5233 for null check

  6. Clean Comments a. TODO Refactor out duplication – Can be seen in “Task List” windows of Visual Studio b. Summary Comments - Only when the class itself cannot explain the intent i. Describes intent at general level higher than the code ii. Often useful to provide high level overview of classes c. Documentation i. // see www.facebook.com/api for documentation

  7. Ask yourself before writing a Comment a. Could I express what I’m about to type in “code”? b. Am I explaining bad code I’ve just written instead of refactoring? c. Should this simply be a message in a source control commit?

7.0 Refactoring Demo

  • No short names for variables
  • No good, bad, ok variables (mostly for bool)
  • Reduce Indentations (levels, cyclomatic complexity)
  • Comments: remove zombie code, defect numbers, explaing same
  • Mayfly variables: move variables as down as possible
  • Guard Clasue: clauses in a different method (basically if condition which stops the method execution)
  • Return Early: Exit from a method as soon as possible.
  • Table driven method: No hard coding of values – put it into a table | Enum | Const
  • No catching exceptions: Unless needed
  • Run Tests after refactoring

Clone this wiki locally