Module: good-practices-lesson

<!-- .slide: data-state="title" --> # Developing Modular Code <!-- .slide: data-state="standard" --> === ## What is modularity? Simple components combined to produce complex behavior. - Software can be 'built up' from smaller elements. <!-- .element: class="fragment" data-fragment-index="3" --> - Elements are self-contained and independent. <!-- .element: class="fragment" data-fragment-index="4" --> - Each element handles a specific (set of) task(s). <!-- .element: class="fragment" data-fragment-index="5" --> <figure style="text-align: center; margin-top: 20px;"> <img height="300" alt="modularity" src="./media/modular-code/modern_times.jpg" style="margin-bottom: -10px;"> <figcaption style="font-size: 0.3em; color: #666;">Charlie Chaplin in <i>Modern Times</i> (1936).<br>© Roy Export Company Establishment; photograph, the Museum of Modern Art/Film Stills Archive, New York City</figcaption> </figure> === <!-- .slide: data-state="standard" --> ## Modular code <div style="display: flex; justify-content: center; align-items: center; margin-top: 20px;"> <img width="400" alt="cohesive" src="./media/modular-code/small_cohesive_units.png" style="margin-right: 20px;"> <img width="400" alt="bohemoth" src="./media/modular-code/customized_bohemoth.png" class="fragment" data-fragment-index="1"> </div> === <!-- .slide: data-state="standard" --> ## What are these blocks/elements? <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px; max-width: 100%;"> <img src="./media/modular-code/building_blocks.png" alt="building blocks" style="max-width: 40%; height: auto; margin-right: 20px;"> <div> <ul> <li class="fragment" data-fragment-index="1">functions</li> <li class="fragment" data-fragment-index="2">classes</li> <li class="fragment" data-fragment-index="3">modules</li> <li class="fragment" data-fragment-index="4">libraries/packages</li> <li class="fragment" data-fragment-index="5">programs</li> <li class="fragment" data-fragment-index="5">...</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## Why write modular code? To increase robustness <img width="200" alt="testing a single module" src="./media/modular-code/testing_module.png"> - A well-designed module can be tested. - This helps keep the codebase well-functioning and bug-free. === <!-- .slide: data-state="standard" --> ## Why write modular code? To make maintenance easier: <img width="300" alt="testing a module taken from a larger project" src="./media/modular-code/testing_module_maintenance.png"> - Modular code is more readable and understandable. - Modules can be debugged separately. - Modules only need to be improved/optimized once. === <!-- .slide: data-state="standard" --> ## Why write modular code? To allow reusability: <img width="400" alt="reuse a module in another project" src="./media/modular-code/reuse_module.png"> - A module can live independent of its original context. - It can be reused by another project. === <!-- .slide: data-state="standard" --> ## Why write modular code? To facilitate scalability: <div style="display: flex; align-items: center;"> <img alt="scalability" src="./media/modular-code/scalability.png" style="max-width: 40%; height: auto; margin-right: 20px;"> <div> <ul> <li>Complexity remains low by design.</li> <li>This creates space for scaling up.</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## Why write modular code? To create opportunities for innovation: <img alt="tetris shows innovation" src="./media/modular-code/tetris_innovation.png" style="max-width: 50%; height: auto;"> - Modules increase the capabilities and power of a project. - Rearrange old modules for new applications. === <!-- .slide: data-state="standard" --> ## Why write modular code? To save time: <img width="600" alt="development speed" src="./media/modular-code/development-speed.svg"> === <!-- .slide: data-state="standard" --> ## A good module... <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px;"> <img src="./media/modular-code/units.png" alt="units" width="300" style="margin-right: 20px;"> <div> <ul> <li class="fragment" data-fragment-index="1">performs limited and clearly defined tasks</li> <li class="fragment" data-fragment-index="2">has a good name</li> </ul> </div> </div> === <!-- .slide: data-state="standard"--> ## Naming your module - be descriptive and clear - focus on human intelligibility - follow language specific conventions - avoid abbreviations <div style="text-align: center; margin-top: 20px;"> <img alt="naming" src="./media/modular-code/naming_stuff.jpg" style="max-width: 100%; height: auto; max-height: 300px;"> </div> <!-- .element: class="fragment" data-fragment-index="2" --> === <!-- .slide: data-state="standard" --> ## A good module... <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px;"> <img src="./media/modular-code/units.png" alt="units" width="300" style="margin-right: 20px;"> <div> <ul> <li>performs limited and clearly defined tasks</li> <li>has a good name</li> <li class="fragment" data-fragment-index="1">is readable</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## More readable != shorter code Shorter: ```python indexATG = [n for n,i in enumerate(myList) if i == 'ATG'] indexAAG = [n for n,i in enumerate(myList) if i == 'AAG'] ``` More modular: <!-- .element: class="fragment" data-fragment-index="2" --> ```python def getIndex(inputList,z): zIndex = [n for n,i in enumerate(inputList) if i == z] return zIndex indexATG = getIndex(myList,'ATG') indexAAG = getIndex(myList,'AAG') ``` <!-- .element: class="fragment" data-fragment-index="2" --> === <!-- .slide: data-state="standard" --> ## A good module... <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px;"> <img src="./media/modular-code/units.png" alt="units" width="300" style="margin-right: 20px;"> <div> <ul> <li>performs limited and clearly defined tasks</li> <li>has a good name</li> <li>is readable</li> <li class="fragment" data-fragment-index="1">is pure and predictable</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## An impure function... ... does not always give the same result: ```python def fahrenheit_to_celsius(temp_list, converted_temps=[]): for temp in temp_list: temp_c = (temp - 32.0) * (5.0/9.0) converted_temps.append(temp_c) return converted_temps >>> fahrenheit_to_celsius([32.0, 77.0]) # [0.0, 25.0] ``` **Q: What will happen when we call the function a second time?** <!-- .element: class="fragment" data-fragment-index="2" --> ```python >>> fahrenheit_to_celsius([32.0, 77.0]) # [0.0, 25.0, 0.0, 25.0] ``` <!-- .element: class="fragment" data-fragment-index="3" --> === <!-- .slide: data-state="standard" --> ## A pure function... ... always gives the same result: ```python def fahrenheit_to_celsius(temp_list, converted_temps=None): if converted_temps == None: converted_temps = [] for temp in temp_list: temp_c = (temp - 32.0) * (5.0/9.0) converted_temps.append(temp_c) return converted_temps >>> fahrenheit_to_celsius([32.0, 77.0]) # [0.0, 25.0] >>> fahrenheit_to_celsius([32.0, 77.0]) # [0.0, 25.0] ``` === <!-- .slide: data-state="standard" --> ## A good module... <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px;"> <img src="./media/modular-code/units.png" alt="units" width="300" style="margin-right: 20px;"> <div> <ul> <li>performs limited and clearly defined tasks</li> <li>has a good name</li> <li>is readable</li> <li>is pure and predictable</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## Identifying opportunities for modularization <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px;"> <img src="./media/modular-code/testing_module.png" alt="testing a single module" width="300" style="margin-right: 20px;"> <div> <ul> <li class="fragment" data-fragment-index="2">poor readability</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## Readable code Modular code becomes more readable - Code is read more than it is written <!-- .element: class="fragment" data-fragment-index="2" --> - Does a reader understand what the code does? <!-- .element: class="fragment" data-fragment-index="3" --> - Bad readability can be a "code smell" <!-- .element: class="fragment" data-fragment-index="4" --> <figure style="text-align: center; margin-top: 20px;"> <img width="400" alt="smelly" src="./media/modular-code/Smelly-Code-Featured.avif" style="margin-bottom: -10px;"> <figcaption style="font-size: 0.3em; color: #666;">SIphotography/Depositphotos</figcaption> </figure> <!-- .element: class="fragment" data-fragment-index="4" --> === <!-- .slide: data-state="standard" --> ## Identifying opportunities for modularization <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px;"> <img src="./media/modular-code/testing_module.png" alt="testing a single module" width="300" style="margin-right: 20px;"> <div> <ul> <li>poor readability</li> <li class="fragment" data-fragment-index="1">repetition</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## Repetitive code - Don't Repeat Yourself (DRY): place reused code into a function - Identify functions units by their _action_ - (e.g. "plot", "transform", "extract", "save") <div style="text-align: center; margin-top: 20px;"> <img alt="DRY" src="./media/modular-code/dry-vs-wet-code.jpg" style="max-width: 100%; height: auto; max-height: 300px;"> </div> === <!-- .slide: data-state="standard" --> ## Identifying opportunities for modularization <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px;"> <img src="./media/modular-code/testing_module.png" alt="testing a single module" width="300" style="margin-right: 20px;"> <div> <ul> <li>poor readability</li> <li>repetition</li> <li class="fragment" data-fragment-index="1">nested code</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## Target nested code Nested code is a prime target for modularization: ```python def sum_even_numbers(bottom, top): if top > bottom: sum = 0 for x in range(bottom, top): if x % 2 == 0: sum += x return sum return 0 sum_even_numbers(2, 14) # 42 ``` === <!-- .slide: data-state="standard" --> ## Reduce nestedness... ... by extracting modules: ```python def _filter_even(number): if number % 2 == 0: return number return 0 def sum_even_numbers(bottom, top): if top < bottom: return 0 sum = 0 for x in range(bottom, top): sum += _filter_even(x) return sum sum_even_numbers (2,14) # 42 ``` === <!-- .slide: data-state="standard" --> ## Identifying opportunities for modularization <div style="display: flex; justify-content: center; align-items: flex-start; margin-top: 20px;"> <img src="./media/modular-code/testing_module.png" alt="testing a single module" width="300" style="margin-right: 20px;"> <div> <ul> <li>poor readability</li> <li>repetition</li> <li>nested code</li> </ul> </div> </div> === <!-- .slide: data-state="standard" --> ## Let tests help you - Write tests for each individual module <!-- .element: class="fragment" data-fragment-index="2" --> - Use the test-writing procedure to look critically at the module's function: <!-- .element: class="fragment" data-fragment-index="3" --> - Is the input/output clear? <!-- .element: class="fragment" data-fragment-index="3" --> - What can you not yet test? Extract it into a new module.