# 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
---
## What are these blocks/elements?
- functions
- functions
- classes
- modules
- libraries/packages
- programs
===
## Why write modular code?
To increase robustness:
- 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:
- Modular code is more readable and understandable.
- Modules can be debugged separately.
---
## Why write modular code?
To allow reusability:
- A module can live independent of its original context
- It can be reused by another project
---
## Why write modular code?
To facilitate scalability:
- Complexity remains low by design
- This creates space for scaling up
---
## Why write modular code?
To create opportunities for innovation:
- Modules increase the capabilities and power of a project
- Rearrange old modules for new applications
---
===
## A good module...
- has a clear interface
---
---
## 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.
===
![]()