Side Effects
© 2020 Morgan C. Benton code4your.life
What are "SIDE EFFEcts"
I hate this term.
Usually we think of "side effects" as the unwanted impacts of a medication or some actions.
However, in programming it is the opposite. In software, "side effects" describe intended outcomes and are what make software useful to people.
© 2020 Morgan C. Benton code4your.life
Examples of Side Effects
Side effects are generally unpredictable and involve read/write or input/output operations, such as:
- obtaining user input, e.g. from a form
- displaying output on the screen
- reading or writing a file from a disk
- reading or writing data from a database
- getting data from a remote URL
The technical term for this is non-deterministic behavior
© 2020 Morgan C. Benton code4your.life
Deterministic
Systems or processes that always produce the same result, i.e. predictable:
- 2 + 2 = 4
- capitalize("bob") => "Bob"
- data transformation
- math
non-deterministic
Systems or process that produce unpredictable, sometimes random, results:
- user input
- HTTP requests
- reading/writing to disk/DB
- displaying to a screen
- printing to paper
- audio/video playback
Non-deterministic behavior?
© 2020 Morgan C. Benton code4your.life
"side effects"
Good things about
side effects
Side effects are what makes software useful.
It doesn't matter how robust your machine learning algorithm, or meteorological model, or gaming physics engine if the results of those computations can't be written to a disk, displayed on a screen, or transmitted across a network, your software does nothing useful.
© 2020 Morgan C. Benton code4your.life
BAD things about
side effects
Side effects are hard to test.
If you can't predict what a user is going to type into a form, or whether writing to the database is successful, or whether data requested from a URL returns as expected, it is hard to know if errors are caused by bad code or by some other failure of the system.
Such errors can diminish or eliminate the positive effects of software.
© 2020 Morgan C. Benton code4your.life
© 2020 Morgan C. Benton code4your.life
for x in range(1, 101):
if x % 15 is 0:
print('FizzBuzz') # <== side effect
elif x % 3 is 0:
print('Fizz') # <== side effect
elif x % 5 is 0:
print('Buzz') # <== side effect
else:
print(x) # <== side effect
def fizzbuzz(x):
return 'FizzBuzz' if x % 15 is 0 else x
def fizz(x):
return 'Fizz' if x % 3 is 0 else x
def buzz(x):
return 'Buzz' if x % 5 is 0 else x
for x in range(1, 101):
print(fizz(buzz(fizzbuzz(x)))) # <== side effect
Mostly Untestable
Mostly Testable
Code Examples
guidelines
© 2020 Morgan C. Benton code4your.life
- ALL useful code will contain some side effects
- Restructure your code to move side effects "to the edges," i.e. to the very beginning or end of a process
- Side effects can almost always be separated from the rest of your code
- Wrap the steps of your process in functions that can be tested and composed to accomplish your goal
- Write automated unit tests for the functions that do not contain side effects
"Pure" functions
© 2020 Morgan C. Benton code4your.life
"Pure" functions:
- Do NOT contain side effects
- Do NOT mutate (i.e. make changes to) any global variables
- Return exactly one value
- Are deterministic, i.e. given the same input, they always return the same output
examples of converting impure functions to Pure
© 2020 Morgan C. Benton code4your.life
user input
"""
Process: User types in a number representing MPG,
which gets converted to KPL and printed.
"""
# CONSTANTS
KPM = 1.60934 # kilometers/mile
GPL = 0.264172 # gallons/liter
# IMPURE
def convert():
mpg = input('What is your MPG?')
print('Your KPL is: ' + (mpg * KPM * GPL))
# PURE
def convert(mpg):
return mpg * KPM * GPL
mpg = input('What is your MPG?')
print('Your KPL is: ' + convert(mpg))
© 2020 Morgan C. Benton code4your.life
reading File input
"""
Process: Open a file that contains a list of
tempertature readings, and calculate
the average.
"""
# IMPURE
def calculateAvgTemp():
f = open('temps.txt') # <== side effect
temps = f.read().split()
avg = 0
for x in temps:
avg += float(x) / len(temps)
print(avg) # <== side effect
# PURE
def calculateAvgTemp(data):
temps = data.split()
avg = 0
for x in temps:
avg += float(x) / len(temps)
return avg
f = open('temps.txt')
print(calculateAvgTemp(f.read()))
© 2020 Morgan C. Benton code4your.life
25.8
15.6
22.0
19.2
23.3
21.9
temps.txt
Making an HTTP Request
"""
Process: Retrieve the current weather for Washington, DC
from the metaweather.com free REST API, search
the results to find today's weather and output
the weather state.
See: https://www.metaweather.com/api/
"""
# Import 3rd party library for making HTTP requests
from requests import get
from datetime import datetime
# CONSTANTS
URL = 'https://www.metaweather.com/api/location/2514815/'
TODAY = datetime.today().strftime('%Y-%m-%d')
# IMPURE
def getTodaysWeather():
result = get(URL) # <== side effect
data = result.json()
for day in data['consolidated_weather']:
if day['applicable_date'] == TODAY:
print(day['weather_state_name']) # <== side effect
# PURE
def getTodaysWeather(days):
for day in days:
if day['applicable_date'] == TODAY:
return day['weather_state_name']
else:
return 'Unknown'
data = get(URL).json()
print(getTodaysWeather(data['consolidated_weather']))
© 2020 Morgan C. Benton code4your.life
Summary
- A "side effect" in software is non-deterministic behavior, usually associated with input/output
- Side effects are what makes software useful, BUT
- Side effects are HARD TO TEST
- Whenever possible:
- Isolate side effects from the rest of your program
- Write pure, easily testable functions
- Follow the TDD process
© 2020 Morgan C. Benton code4your.life
Side Effects
By Morgan Benton
Side Effects
Introduction to the concept of "side effects" in computer programming. Example code in a variety of languages is provided to demonstrate the main types and their impacts on TDD and testability in general.
- 853