100% found this document useful (5 votes)
795 views26 pages

Clean Code

The document discusses principles and best practices for writing clean code, including: - Giving variables and functions meaningful, pronounceable names that clearly convey their purpose. - Keeping functions small and focused on doing one thing at a high level of abstraction. Functions should have few arguments, avoid switch statements, and not cause side effects. - Writing unit tests that follow the principles of test-driven development, having one assert per test, and being fast, independent, repeatable, self-validating, and timely. - Designing classes according to principles like the single responsibility principle, open-closed principle, and law of Demeter to keep code well-structured, modular, and extensible

Uploaded by

Dao Vy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (5 votes)
795 views26 pages

Clean Code

The document discusses principles and best practices for writing clean code, including: - Giving variables and functions meaningful, pronounceable names that clearly convey their purpose. - Keeping functions small and focused on doing one thing at a high level of abstraction. Functions should have few arguments, avoid switch statements, and not cause side effects. - Writing unit tests that follow the principles of test-driven development, having one assert per test, and being fast, independent, repeatable, self-validating, and timely. - Designing classes according to principles like the single responsibility principle, open-closed principle, and law of Demeter to keep code well-structured, modular, and extensible

Uploaded by

Dao Vy
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 26

Clean Code

Keeping your code readable


By: Arnoldo Rodriguez
@arnoldocolin

Giving Meaningful names

Intention revealing
Pronounceable
Distinctable
Class names should be nouns / noun verbs
Method names should be verbs / verb
phrase
One Word per concept

Names: Intention Revealing & Pronounceable


edt

end_date_time

sdt

start_date_time

nme

name

fname
stotal

VS

full_name
subtotal

pgup

page_up

lng

longitud

Names: Distinctable, never duplicate...


info

description

destroy

delete

name

fullname

place
house
process

VS

location
home
execute

Names: Class names should be a...

Noun
User
Form
Friend

Noun phrase
Signup
DiscountCalculator
TripFinder

Names: Method names should be a...

Verb
invite
authorize
validate

Verb Phrase
find_location
has_friendship_with
send_email

Functions should...

be small (do 1 thing, 1 level of abstraction)


never use switch statements
1, 2, 3 arguments, no more!
Do something or answer something
have no side effects

Functions: Do 1 thing & 1 Level of Abstraction


class Order
# Wrong: calculating several things
def total
subtotal = items.sum(:price)
discount = items.sum(:discount)
subtotal - discount
end
end

class Order
# Good. One level of abstraction, One thing
# Remember to declare utility functions just
# below where they are being called
def total
subtotal - discount
end
def subtotal
items.sum(:price)
end
def discount
items.sum(:discount)
end
end

Not OK

Ok!

Functions: Never use switch statements


class Payment
attr_reader payment_method

class Payment
attr_reader payment_method

def process
case payment_method.class
when "CreditCart"
when "Deposit"
when "Cash"
end
end

# A switch statement hides an


# opportunity to use
# polymorphism or duck typing
def process
payment_method.purchase(self)
end
end

Not OK

Ok!

Functions: Zero arguments is the winner!


No arguments to remember
Use instance variables, but remember the cohesion
principle:
All methods (in a class) should use most of the
instance variables in that class

Functions: One argument, Ask? or Transform not both


class User
# This is asking something
def has_friendship_with(another_user)
Friendship.exists?(self, another_user)
end
# This is transforming something
def change_password(new_password)
self.password = new_password
end
end

Functions: Two arguments sucks

Avoid or convert to one argument using


instance variables.
Give functions better names.
# Hard to remember gotta google it bitch!
asserts_equal(expected, actual)
# Easy to remember no need for the api
asserts_expected_to_eq_actual(expected, actual)

Functions: Three arguments, avoid at all costs

If you cant then use:


argument objects
argument lists
# send options hash for a list html options
def text_field_tag(name, value, html_options={})
end
# convert x, y coordinates into a center object
def make_circle(center, radius)
end

Functions: Make sure they have no side effects


# The side effect is sending an email notification
def create_account(attributes={})
account = Account.create(attributes)
send_notification_email(account) unless account.new_record?
end
# We can give the function a better name
# though violates the do 1 thing
# the best solution is to abstract it to a new object signup
def create_account_and_notify(attributes={})
end

Comments are...
Shitz
A pain in the ass to maintain
To be avoided if we follow good design
practices

Exceptions: return exceptions instead of error codes


# Using an error code
def withdraw(amount)
if amount > balance
return -1
else
balance -= amount
end
end

Not OK

# Using an exception, easier coz it give us


#context
def withdraw(amount)
raise BalanceException if amount > balance
balance -= amount
end

Ok!

Unit tests should follow...


3 Laws of TDD
One assert per test
F.I.R.S.T.

Unit Tests: 3 Laws of TDD


First: You may not write production code until you have
written a failing unit test.
Second: You may not write more of a unit test than is
sufficient to fail
Third: You may not write more production code than is
sufficient to pass the currently failing test.

Unit Tests: One assert per test

Use the Given, When, Then to test one


concept per test.

Unit Tests: F.I.R.S.T.


Fast: Tests should be fast.
Independent: Tests should not depend on each other.
Repeatable: Tests should be repeatable in any
environment.
Self-Validating: Test should have a boolean output.
Timely: Unit Tests should be write just before
production code.

Classes should...

Keep variables & utility functions private


Follow the Single Responsibility Principle
Follow the Open-Closed principle
Follow the Dependency inversion Principle
Follow the law of Demeter

Classes: Single Responsibility Principle


# Several responsibilities
class User
attr_accessor first_name, last_name, email
def full_name
"#{first_name} #{last_name}"
end
def send_confirmation_email
end
def recover_password
end
end

# By dividing responsibilities
# we ended up with more objects
class User
attr_accessor first_name, last_name, email
def full_name
"#{first_name} #{last_name}"
end
end
class PasswordRetriever
def retrieve
end
end
class Signup
def sign_up
end
private
def send_confirmation_email
end
end

Not OK

Ok!

Classes: Open-Close Principle


# Everytime we want a new SQL method
# we will have to open and change the class
# clearly violates Open-Close Principle
class SQL
def insert
# codez, codez...
end

# Using inheritance we follow the Open-Close #


Principle
# A class must be Open for extension but
#Close for modification
class SQL
# superclass codez goes here...
end

def select
# codez, codez...
end
end

class Insert < SQL


# specialization codez goes here...
end
class Select < SQL
# specialization codez goes here...
end

Not OK

Ok!

Classes: Dependency Inversion


class Report
# Class dependent, what if we need another format?
def export_pdf
PDFExporter.export(self)
end
# Inverting the dependency, we can use any format now
def export(format = PDFExporter)
format.export(self)
end
end
# Endless possibilities
report = Report.new
report.export(PDFExporter)
report.export(XLSExporter)
report.export(NumbersExporter)
report.export(HTMLExporter)

Classes: Law of Demeter


Method F of class C should only call methods of these
(only use one dot):
C
An object created by F
An object passed as an argument to F
An object held in an instance variable of C
class jockey
# we don't need to tell the paws to move
def run_horse
horse.paws.move(speed: fast)
end
end

Not OK

class jockey
# use only one dot!
def run_horse
horse.run
end
end

Ok!

A simple design is one that...

Runs all tests


Has no duplication
Expresses intent
Minimizes the number of classes
Refactor (make it work, make it right)

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy