-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #75 from robmoss/training/spectrum-2024-debugging
SPECTRUM 2024 Introduction to Debugging workshop
- Loading branch information
Showing
48 changed files
with
3,437 additions
and
719 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Training events | ||
|
||
We will be running an [Introduction to Debugging](debugging/README.md) workshop at the [SPECTRUM](https://spectrum.edu.au/) Annual Meeting 2024 (23-25 September). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# Introduction to Debugging | ||
|
||
This workshop was prepared for the [SPECTRUM](https://spectrum.edu.au/) Annual Meeting 2024 (23-25 September). | ||
|
||
!!! tip | ||
|
||
**We all make mistakes** when writing code and introduce errors. | ||
|
||
Having good debugging skills means that you can spend **less time fixing your code**. | ||
|
||
See the discussion in our [August 2024 meeting](../../meetings/2024-08-08.md#debugging) for further background. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Acknowledgements | ||
|
||
Thank you to everyone who contributed to these materials, participated in the practice run, and/or provided feedback. | ||
This includes, in no particular order: | ||
|
||
- Eamon Conway | ||
- James Ong | ||
- Michael Lydeamore | ||
- Ada Yan | ||
- Ruarai Tobin | ||
- Lauren Smith | ||
- Roben Delos Reyes | ||
- Nefel Tellioglu | ||
- Tanaphum Wichaita | ||
- Jiahao Diao | ||
- TK Le | ||
- Dionne Argyropoulos |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Building your skills | ||
|
||
!!! tip | ||
|
||
Whenever you debug some code, consider it as an opportunity to learn, reflect, and [build your debugging skills](manifesto.md). | ||
|
||
Pay attention to your experience — what worked well, and what would you do differently next time? | ||
|
||
## Identifying errors | ||
|
||
Write a failing test case, this allows you to verify that the bug can be reproduced. | ||
|
||
## Developing a plan | ||
|
||
What information might help you decide how to begin? | ||
|
||
Can you identify a recent "known good" version of the code that doesn't include the error? | ||
|
||
If you're using version control, have a look at your recent commits and check whether any of them are likely to have introduced or exposed this error. | ||
|
||
## Searching for the root cause | ||
|
||
We've shown how a debugger allows you to pause your code and see what it's actually doing. | ||
This is extremely helpful! | ||
|
||
!!! tip | ||
|
||
Other approaches may be useful, but avoid using trial-and-error. | ||
|
||
To quickly confirm or rule out specific suspicions, you might consider using: | ||
|
||
- `print()` statements; | ||
- using `assert()` to verify whether specific conditions are met; | ||
- manually calling functions from an interactive session (a "[REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop)"); | ||
- reverting or commenting out the most recent changes; or | ||
- using `git bisect` to [identify the commit](../../../guides/using-git/where-did-this-problem-come-from.md) that introduced the error. | ||
|
||
## Fixing the root cause | ||
|
||
Is there an optimal solution? | ||
|
||
This might be the solution that changes as little code as possible, or it might be a solution that involves modifying and/or restructuring other parts of your code. | ||
|
||
## After it's fixed | ||
|
||
If you didn't write a test case to identify the error (see above), now is the time to write a test case to ensure you don't even make the same error again. | ||
|
||
Are there other parts of your code where you might make a similar mistake, for which you could also write test cases? | ||
|
||
Are there coding practices that might make this kind of error easier to find next time? | ||
For example, this might involve dividing your code into smaller functions, using version control to record commits [early and often](../../../guides/version-control/what-should-I-commit.md). | ||
|
||
Have you considered defensive programming practices? | ||
For example, at the start of a function it can often be a good idea to check that all of the arguments have valid values. | ||
|
||
Are there tools or approaches that you haven't used before, and which might be worth trying next time? |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 101 additions & 0 deletions
101
docs/community/training/debugging/example-square-numbers.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# Example: Square numbers | ||
|
||
[Square numbers](https://en.wikipedia.org/wiki/Square_number) are positive integers that are equal to the square of an integer. | ||
Here we have provided example Python and R scripts that print all of the square numbers between 1 and 100: | ||
|
||
<div id="square-numbers-demo" data-cast-file="../square-numbers-demo.cast"></div> | ||
|
||
You can download these scripts to run on your own computer: | ||
|
||
- [square_numbers.py](square_numbers.py) | ||
- [square_numbers.R](square_numbers.R) | ||
|
||
Each script contains three functions: | ||
|
||
- `main()` | ||
- `find_squares(lower_bound, upper_bound)` | ||
- `is_square(value)` | ||
|
||
The diagram below shows how `main()` calls `find_squares()`, which in turn calls `is_square()` many times. | ||
|
||
```mermaid | ||
sequenceDiagram | ||
participant M as main() | ||
participant F as find_squares() | ||
participant I as is_square() | ||
activate M | ||
M ->>+ F: lower_bound = 1, upper_bound = 100 | ||
Note over F: squares = [ ] | ||
F ->>+ I: value = 1 | ||
I ->>- F: True/False | ||
F ->>+ I: value = 2 | ||
I ->>- F: True/False | ||
F -->>+ I: ... | ||
I -->>- F: ... | ||
F ->>+ I: value = 100 | ||
I ->>- F: True/False | ||
F ->>- M: squares = [...] | ||
Note over M: print(squares) | ||
deactivate M | ||
``` | ||
|
||
??? info "Source code" | ||
|
||
=== "Python" | ||
|
||
```py title="square_numbers.py" linenums="1" | ||
--8<-- "square_numbers.py" | ||
``` | ||
|
||
=== "R" | ||
|
||
```R title="square_numbers.R" linenums="1" | ||
--8<-- "square_numbers.R" | ||
``` | ||
|
||
## Stepping through the code | ||
|
||
These recorded terminal sessions demonstrate how to use Python and R debuggers from the command line. | ||
They cover: | ||
|
||
- How to define breakpoints; | ||
- How to inspect the current values of variables; and | ||
- How to step through, and over, lines of code. | ||
|
||
!!! info "Manual breakpoints" | ||
|
||
You can also create breakpoints in your code by calling [`breakpoint()`](https://docs.python.org/3/library/pdb.html) in Python, and [`browser()`](https://adv-r.hadley.nz/debugging.html#browser) in R. | ||
|
||
!!! tip "Interactive debugger sessions" | ||
|
||
If your editor supports running a debugger, **use this feature!** | ||
See these examples for [RStudio](https://support.posit.co/hc/en-us/articles/205612627-Debugging-with-the-RStudio-IDE), [PyCharm](https://www.jetbrains.com/pycharm/features/debugger.html), [Spyder](https://docs.spyder-ide.org/current/panes/debugging.html), and [VS Code](https://code.visualstudio.com/docs/editor/debugging). | ||
|
||
=== "Python debugger" | ||
|
||
<div id="pdb-demo" data-cast-file="../square-numbers-pdb.cast"></div> | ||
|
||
Video timeline: | ||
|
||
1. <a data-video="pdb-demo" data-seek-to="4.7" href="javascript:;">Set a breakpoint</a> | ||
2. <a data-video="pdb-demo" data-seek-to="9.081" href="javascript:;">Show current location</a> | ||
3. <a data-video="pdb-demo" data-seek-to="16.146" href="javascript:;">Step into `is_square()`</a> | ||
4. <a data-video="pdb-demo" data-seek-to="36.744" href="javascript:;">Return from `is_square()`</a> | ||
5. <a data-video="pdb-demo" data-seek-to="40.021" href="javascript:;">Show updated `squares` list</a> | ||
6. <a data-video="pdb-demo" data-seek-to="57.947" href="javascript:;">Add a conditional breakpoint</a> | ||
7. <a data-video="pdb-demo" data-seek-to="69.697" href="javascript:;">Stop at the conditional breakpoint</a> | ||
8. <a data-video="pdb-demo" data-seek-to="76.202" href="javascript:;">Continue until the script ends</a> | ||
|
||
=== "R debugger" | ||
|
||
<div id="r-debug-demo" data-cast-file="../square-numbers-r-debug.cast"></div> | ||
|
||
Video timeline: | ||
|
||
1. <a data-video="r-debug-demo" data-seek-to="6.568" href="javascript:;">Set a breakpoint</a> | ||
2. <a data-video="r-debug-demo" data-seek-to="23.548" href="javascript:;">Step into `is_square()`</a> | ||
3. <a data-video="r-debug-demo" data-seek-to="29.654" href="javascript:;">Return from `is_square()`</a> | ||
4. <a data-video="r-debug-demo" data-seek-to="33.505" href="javascript:;">Show updated `squares` list</a> | ||
5. <a data-video="r-debug-demo" data-seek-to="47.751" href="javascript:;">Add a conditional breakpoint</a> | ||
6. <a data-video="r-debug-demo" data-seek-to="67.77" href="javascript:;">Stop at the conditional breakpoint</a> | ||
7. <a data-video="r-debug-demo" data-seek-to="74.546" href="javascript:;">Continue until the script ends</a> |
50 changes: 50 additions & 0 deletions
50
docs/community/training/debugging/exercise-perfect-numbers.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Exercise: Perfect numbers | ||
|
||
=== "Overview" | ||
|
||
[Perfect numbers](https://en.wikipedia.org/wiki/Perfect_number) are positive integers that are equal to the sum of their divisors. | ||
Here we have provided example Python and R scripts that should print all of the perfect numbers up to 1,000. | ||
|
||
You can download each script to debug on your own computer: | ||
|
||
- [perfect_numbers.py](perfect_numbers.py) | ||
- [perfect_numbers.R](perfect_numbers.R) | ||
|
||
=== "Python" | ||
|
||
```py title="perfect_numbers.py" linenums="1" | ||
--8<-- "perfect_numbers.py" | ||
``` | ||
|
||
=== "R" | ||
|
||
```R title="perfect_numbers.R" linenums="1" | ||
--8<-- "perfect_numbers.R" | ||
``` | ||
|
||
!!! bug "But there's a problem ..." | ||
|
||
If we run these scripts, we see that **they don't print anything**: | ||
|
||
<div id="demo" data-cast-file="../perfect-numbers-first-run.cast"></div> | ||
|
||
How should we begin investigating? | ||
|
||
!!! tip "Interactive debugger sessions" | ||
|
||
If your editor supports running a debugger, **use this feature!** | ||
See these examples for [RStudio](https://support.posit.co/hc/en-us/articles/205612627-Debugging-with-the-RStudio-IDE), [PyCharm](https://www.jetbrains.com/pycharm/features/debugger.html), [Spyder](https://docs.spyder-ide.org/current/panes/debugging.html), and [VS Code](https://code.visualstudio.com/docs/editor/debugging). | ||
|
||
??? note "Some initial thoughts ..." | ||
|
||
- Are we actually running the `main()` function at all? | ||
|
||
- The `main()` function is almost certainly not the cause of this error. | ||
|
||
- The `is_perfect()` function is very simple, so it's unlikely to be the cause of this error. | ||
|
||
- The `divisors_of()` function doesn't look obviously wrong. | ||
|
||
- But there must be a mistake **somewhere**! | ||
|
||
- Let's **use a debugger** to investigate. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Exercise: Python vs R | ||
|
||
=== "Overview" | ||
|
||
Here we have provided SIR ODE model implementations in Python and in R. | ||
Each script runs several scenarios and produces a plot of infection prevalence for each scenario. | ||
|
||
You can download each script to debug on your computer: | ||
|
||
- [sir_ode.py](sir_ode.py) | ||
- [sir_ode.R](sir_ode.R) | ||
|
||
=== "Python" | ||
|
||
```py title="sir_ode.py" linenums="1" | ||
--8<-- "sir_ode.py" | ||
``` | ||
|
||
=== "R" | ||
|
||
```R title="sir_ode.R" linenums="1" | ||
--8<-- "sir_ode.R" | ||
``` | ||
|
||
!!! bug "The model outputs differ!" | ||
|
||
Here are prevalence time-series plots produced by each script: | ||
|
||
=== "Python plot" | ||
|
||
<figure markdown="span"> | ||
![Python outputs](sir_ode_python.png) | ||
<figcaption>Model outputs for the Python script.</figcaption> | ||
</figure> | ||
|
||
=== "R plot" | ||
|
||
<figure markdown="span"> | ||
![R outputs](sir_ode_r.png) | ||
<figcaption>Model outputs for the R script.</figcaption> | ||
</figure> | ||
|
||
!!! tip "Interactive debugger sessions" | ||
|
||
If your editor supports running a debugger, **use this feature!** | ||
See these examples for [RStudio](https://support.posit.co/hc/en-us/articles/205612627-Debugging-with-the-RStudio-IDE), [PyCharm](https://www.jetbrains.com/pycharm/features/debugger.html), [Spyder](https://docs.spyder-ide.org/current/panes/debugging.html), and [VS Code](https://code.visualstudio.com/docs/editor/debugging). | ||
|
||
??? note "Some initial thoughts ..." | ||
|
||
- Is it obvious whether one of the figures is correct and the other is wrong? | ||
|
||
- The `sir_rhs()` functions in the two scripts appear to be equivalent — but are they? | ||
|
||
- The `default_settings()` functions appear to be equivalent — but are they? | ||
|
||
- The `run_model_scaled_beta()` and `run_model_scaled_gamma()` functions also appear to be equivalent. | ||
|
||
- Where might you begin looking? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
first_function <- function() { | ||
total <- 0 | ||
for (x in seq(49)) { | ||
y <- second_function(x) | ||
total <- total + y | ||
} | ||
total | ||
} | ||
|
||
second_function <- function(a) { | ||
result <- 3 * a^2 + 5 * a | ||
result | ||
} | ||
|
||
total <- first_function() | ||
cat("Total =", total, "\n") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
def first_function(): | ||
total = 0 | ||
for x in range(1, 50): | ||
y = second_function(x) | ||
total = total + y | ||
|
||
return total | ||
|
||
|
||
def second_function(a): | ||
result = 3 * a**2 + 5 * a | ||
return result | ||
|
||
|
||
total = first_function() | ||
print(f'Total = {total}') |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Learning objectives | ||
|
||
In this workshop, we will introduce the concept of "debugging", and demonstrate techniques and tools that can help us efficiently identify and remove errors from our code. | ||
|
||
After completing this workshop, participants will: | ||
|
||
+ Understand that debugging can be divided into a sequence of actions; | ||
|
||
+ Understand the purpose of each of these actions; | ||
|
||
+ Be familiar with techniques and tools that can help perform these actions; | ||
|
||
+ Be able to apply these techniques and tools to their own code. | ||
|
||
!!! info | ||
|
||
By achieving these learning objectives, participants should be able to find and correct errors in their code more quickly and with greater confidence. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import matplotlib.pyplot as plt | ||
import matplotlib.cm as cm | ||
|
||
example_counts = [1, 2, 3, 4, 5] | ||
plt.plot(example_counts, cbap=cm.Blues) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Debugging manifesto | ||
|
||
<figure markdown="span"> | ||
![A debugging manifesto poster.](debugging-manifesto-poster.jpg){ align=left, width="50%" } | ||
<figcaption markdown="span"> | ||
[Julia Evans](https://jvns.ca/) and [Tanya Brassie](https://tanyabrassie.com/): [Debugging Manifesto Poster](https://store.wizardzines.com/products/poster-debugging-manifesto), 2024. | ||
</figcaption> | ||
</figure> | ||
|
||
!!! info | ||
|
||
See the [Resources](resources.md) page for links to more of Julia Evans' articles, stories, and zines about debugging. |
Oops, something went wrong.