334 lines
5.6 KiB
Plaintext
334 lines
5.6 KiB
Plaintext
|
== Clean code
|
||
|
|
||
|
=== !
|
||
|
|
||
|
image::clean_code.jpg[]
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
=== what is good code?
|
||
|
|
||
|
[.fragment]
|
||
|
image::wtfm.jpg[]
|
||
|
|
||
|
=== good code
|
||
|
|
||
|
[%step]
|
||
|
* It works
|
||
|
* Is easy to understand
|
||
|
* Is easy to change
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
=== Bad code: code smells
|
||
|
|
||
|
[%step]
|
||
|
* Duplicated code
|
||
|
* Unnecessary complexity
|
||
|
* A single change needs to be applied in many places at the same time.
|
||
|
* Methods do too many things
|
||
|
* Too many nested if / loops
|
||
|
* Too many parameters
|
||
|
* ...
|
||
|
|
||
|
//---------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
=== How to improve code quality?
|
||
|
|
||
|
[.fragment]
|
||
|
"Refactoring is the process of changing a software system in such a way that it does not alter the function of the code yet improves its internal structure."
|
||
|
-- Martin Fowler, Refactoring: Improving the Design of Existing Code (1999)
|
||
|
|
||
|
//---------------------------------------------------------
|
||
|
|
||
|
=== KISS
|
||
|
|
||
|
[.fragment]
|
||
|
Keep it Simple, Stupid
|
||
|
|
||
|
//---------------------------------------------------------
|
||
|
|
||
|
=== Avoid code duplication
|
||
|
|
||
|
image::dont-repeat-yourself.jpg[]
|
||
|
|
||
|
=== !
|
||
|
|
||
|
* Probably the most common and worst mistake in programming
|
||
|
* Avoid at all cost!
|
||
|
|
||
|
=== refactoring code duplication
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def f1():
|
||
|
# read file
|
||
|
...
|
||
|
# use complex method to calculate a
|
||
|
|
||
|
def f2():
|
||
|
# read file
|
||
|
...
|
||
|
# use complex method to calculate b
|
||
|
|
||
|
----
|
||
|
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def read_file()
|
||
|
def complex_method()
|
||
|
|
||
|
def f1():
|
||
|
read_file()
|
||
|
complex_method(a)
|
||
|
|
||
|
def f2():
|
||
|
read_file()
|
||
|
complex_method(b)
|
||
|
|
||
|
----
|
||
|
|
||
|
=== !
|
||
|
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def f1():
|
||
|
# read file
|
||
|
...
|
||
|
# calculate a
|
||
|
|
||
|
def f2():
|
||
|
# read file
|
||
|
...
|
||
|
# calculate b
|
||
|
|
||
|
def higher_function()
|
||
|
if (condition)
|
||
|
f1()
|
||
|
else
|
||
|
f2()
|
||
|
----
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def read_file()
|
||
|
def complex_method()
|
||
|
|
||
|
def higher_function()
|
||
|
read_file()
|
||
|
if (condition)
|
||
|
complex_method(a)
|
||
|
else
|
||
|
complex_method(b)
|
||
|
|
||
|
----
|
||
|
|
||
|
=== A special case
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def f1():
|
||
|
# same code
|
||
|
...
|
||
|
# method 1
|
||
|
...
|
||
|
# same code
|
||
|
|
||
|
def f2():
|
||
|
# same code
|
||
|
...
|
||
|
# method 2
|
||
|
...
|
||
|
# same code
|
||
|
|
||
|
----
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def method_1():
|
||
|
...
|
||
|
def method_2():
|
||
|
...
|
||
|
|
||
|
#functions are just another type of objects!
|
||
|
def f(in_method):
|
||
|
# same code
|
||
|
...
|
||
|
in_method()
|
||
|
...
|
||
|
# same code
|
||
|
|
||
|
def higher_function():
|
||
|
f(method_1)
|
||
|
f(method_2)
|
||
|
----
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------
|
||
|
|
||
|
=== Each function should do one thing
|
||
|
|
||
|
[.fragment]
|
||
|
“The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that”
|
||
|
|
||
|
=== size is not everything!
|
||
|
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def function_1():
|
||
|
# code here
|
||
|
return function_2(results_1)
|
||
|
|
||
|
def function_2(input_2):
|
||
|
# code here
|
||
|
return function_3(results_2)
|
||
|
|
||
|
def function_3(input_3):
|
||
|
# code here
|
||
|
return function_4(results_3)
|
||
|
|
||
|
def function_4(input_4):
|
||
|
# code here
|
||
|
return results_4
|
||
|
|
||
|
----
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def main_function():
|
||
|
results_1 = function_1()
|
||
|
results_2 = function_2(results_1)
|
||
|
results_3 = function_3(results_2)
|
||
|
return function_4(results_3)
|
||
|
|
||
|
----
|
||
|
|
||
|
|
||
|
//---------------------------------------------------------
|
||
|
|
||
|
=== Use comments
|
||
|
|
||
|
[.fragment]
|
||
|
**Proper** use of commenting can
|
||
|
[%step]
|
||
|
* make code maintenance much easier
|
||
|
* help finding bugs faster
|
||
|
* make your code more readable to other people
|
||
|
* make your code more readable to yourself (in six months)
|
||
|
|
||
|
=== Don't over-comment your code
|
||
|
|
||
|
[%step]
|
||
|
* comments are a necessary evil
|
||
|
* comments cover up naming failures
|
||
|
* comments must evolve with code
|
||
|
|
||
|
=== when and how to write comments
|
||
|
|
||
|
[%step]
|
||
|
* **Always try to explain yourself in code.**
|
||
|
* Don't be redundant.
|
||
|
* Use them in complex expressions.
|
||
|
* Use as explanation of intent.
|
||
|
* Use as clarification of code.
|
||
|
* Use as warning of consequences.
|
||
|
* Don't comment out code: remove it (and use version control)
|
||
|
|
||
|
//---------------------------------------------------------
|
||
|
|
||
|
=== Naming Conventions
|
||
|
|
||
|
[%step]
|
||
|
* Use names that are easy to understand.
|
||
|
* Format them consistently.
|
||
|
* Names must help understanding what a piece of code does.
|
||
|
* Avoid single variable names.
|
||
|
|
||
|
=== example: replacing comments with good naming
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
# This function calculates prices, compares to sales
|
||
|
# promotions, checks if prices are valid,
|
||
|
# then send an email of promotion to user
|
||
|
def doSomeThings():
|
||
|
|
||
|
# Calculate prices
|
||
|
...
|
||
|
...
|
||
|
# Compare prices with sales promotions
|
||
|
...
|
||
|
...
|
||
|
# Check if calculated prices are valid
|
||
|
...
|
||
|
...
|
||
|
# Send promotions to users
|
||
|
...
|
||
|
...
|
||
|
|
||
|
----
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def sendPromotionEmailToUsers():
|
||
|
calculatePrices();
|
||
|
comparePricesWithSalesPromotions();
|
||
|
checkIfCalculatedPricesAreValid();
|
||
|
sendPromotionEmail();
|
||
|
|
||
|
----
|
||
|
|
||
|
//---------------------------------------------------------
|
||
|
|
||
|
=== keep a consistent format
|
||
|
|
||
|
[.fragment]
|
||
|
[.col2]
|
||
|
--
|
||
|
[%step]
|
||
|
* useCamelCase
|
||
|
* OrPascalCase
|
||
|
* or_snake_case
|
||
|
* or-kebab-case
|
||
|
* But not all of them together
|
||
|
--
|
||
|
|
||
|
[.fragment]
|
||
|
[.source.col2,python]
|
||
|
----
|
||
|
|
||
|
def my_function():
|
||
|
print("Hello in a function")
|
||
|
|
||
|
def myFunction():
|
||
|
print("Ey, I'm a different function")
|
||
|
|
||
|
def my-Function():
|
||
|
print("I'm yet another function, good luck choosing the right one")
|
||
|
|
||
|
def my_FunctionIs-A-Terrible_mess():
|
||
|
print("Imagine how things turn when you have several thousand lines of code...")
|
||
|
|
||
|
----
|
||
|
|
||
|
=== !
|
||
|
|
||
|
Some languages (ex. python) have a "standard" [jep]#https://www.python.org/dev/peps/pep-0008[pep 08]# format, check it out!
|