# Developing Modular Code === ## What is modularity? - Software is 'built up' from smaller elements - Elements are self-contained and independent - Each element handles a specific (set of) task(s) **Simple components** build **complex behavior**. --- ## Modular code think in building blocks --- ## What are these blocks/elements? - functions - functions - classes - modules - libraries/packages - programs === ## Why write modular code? To increase robustness: testing a single module - A well-designed module can be tested. - This helps keep the codebase well-functioning and bug-free. --- ## Why write modular code? To make maintenance easier: testing a module taken from a larger project - Modular code is more readable and understandable. - Modules can be debugged separately. --- ## Why write modular code? To allow reusability: reuse a module in another project - A module can live independent of its original context - It can be reused by another project --- ## Why write modular code? To facilitate scalability: scalability
- Complexity remains low by design - This creates space for scaling up
--- ## Why write modular code? To create opportunities for innovation: tetris shows innovation - Modules increase the capabilities and power of a project - Rearrange old modules for new applications --- development speed === ## A good module... - has a clear interface --- Modules with bad interaction Modules with clear connecting interfaces --- ## A good module... - has a clear interface - performs limited and clearly defined tasks - has a good name - is readable --- ## Readability =/= 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: ```python= def getIndex(inputList,z): zIndex = [n for n,i in enumerate(li) if i == z] return zIndex indexATG = getIndex(myList,'ATG') indexAAG = getIndex(myList,'AAG') ``` --- ## A good module... - has a clear interface - performs limited and clearly defined tasks - has a good name - is readable - is pure/does not have a 'state' --- ## A pure function has no side-effects: ```python= def fahrenheit_to_celsius(temp_f): temp_c = (temp_f - 32.0) * (5.0/9.0) return temp_c >>> temp_c = fahrenheit_to_celsius(temp_f=77.0) >>> print(temp_c) 25.0 ``` --- ## A stateful function changes its environment: ```python= def fahrenheit_to_celsius(temp_f): global temp_c temp_c = (temp_f - f_to_c_offset) * f_to_c_factor >>> f_to_c_offset = 32.0 >>> f_to_c_factor = (5.0/9.0) >>> temp_c = 0.0 >>> print(temp_c) 0.0 >>> fahrenheit_to_celsius(temp_f=77.0) >>> print(temp_c) 25.0 ``` === ## Identifying opportunities for modularization --- ## Focus on readability - Modular code becomes more readable - Code is read more than it is written - Does a reader understand what the code does? - Bad readability can be a "code smell" --- ## Identify future functions - Don't Repeat Yourself (DRY): place reused code into a function - Identify potential functions by their _action_ (e.g. "plotting", "transforming", "extracting", "saving") --- ## Target nested code Nested code is a prime target for modularization: ```python= def checkTemperature(degrees): if degrees < 0: if degrees < -273: if degrees < -459: print("This temperature is impossible.") else: print("This temperature is likely Fahrenheit.") else: print("This temperature is either Celsius or Fahrenheit.") else: print("This temperature is in Kelvin, Celsius, or Fahrhenheit.") ``` --- ## Reduce nestedness by extracting modules: ```python= def validTemp(degrees): if degrees < -459: return FALSE return TRUE def checkTemperature(degrees): if not validTemp(degrees): return "invalid temperature" if degrees < 0: if degrees < -273: print("This temperature is likely Fahrenheit.") else: print("This temperature is either Celsius or Fahrenheit.") else: print("This temperature is in Kelvin, Celsius, or Fahrhenheit.") ``` --- ## Let tests help you - Write tests for each individual module - Use the test-writing procedure to look critically at the module's function: - Is the input/output clear? - What can you not yet test? Extract it into a new module. === ![]() xkcd code lifespan