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