== 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!