From f67650b91111f0d712ff2e7d81a8e25575a491b5 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 15:03:18 +0100
Subject: [PATCH 01/98] High level structural change to the code review section
As per #217 adjusted the structure of the document according to the
sketch. Removed sections that won't be needed, and added place holder
sections for the new components.
---
_episodes/41-code-review.md | 226 ++++++++----------------------------
1 file changed, 49 insertions(+), 177 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 15b8c7fd5..e7b63508d 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -65,32 +65,6 @@ and something you should adopt in your development process too.
where one or several people from the team (different from the code's author)
check the software by viewing parts of its source code.
-> ## Group Exercise: Advantages of Code Review
-> Discuss as a group: what do you think are the reasons behind, and advantages of, code review?
-> > ## Solution
-> > The purposes of code review include:
-> > - improving internal code readability, understandability, quality and maintainability
-> > - checking for coding standards compliance, code uniformity and consistency
-> > - checking for test coverage and detecting bugs and code defects early
-> > - detecting performance problems and identifying code optimisation points
-> > - finding alternative/better solutions.
-> >
-> > An effective code review prevents errors from creeping into your software
-> > by improving code quality at an early stage of the software development process.
-> > It helps with learning, i.e. sharing knowledge about the codebase,
-> > solution approaches,
-> > expectations regarding quality,
-> > coding standards, etc.
-> > Developers use code review feedback from more senior developers
-> > to improve their own coding practices and expertise.
-> > Finally, it helps increase the sense of collective code ownership and responsibility,
-> > which in turn helps increase the "bus factor"
-> > and reduce the risk resulting from information and capabilities
-> > being held by a single person "responsible" for a certain part of the codebase
-> > and not being shared among team members.
-> {: .solution}
-{: .challenge}
-
Code review is one of the most useful team code development practices -
someone checks your design or code for errors, they get to learn from your solution,
having to explain code to someone else clarifies
@@ -109,49 +83,6 @@ Since the cost of bug fixes grows in orders of magnitude throughout the software
it is far more efficient to find and fix defects
as close as possible to the point where they were introduced.
-There are several **code review techniques** with various degree of formality
-and the use of a technical infrastructure, including:
-
-- **Over-the-shoulder code review**
- is the most common and informal of code review techniques and involves
- one or more team members standing over the code author's shoulder
- while the author walks the reviewers through a set of code changes.
-- **Email pass-around code review**
- is another form of lightweight code review where the code author
- packages up a set of changes and files and sends them over to reviewers via email.
- Reviewers examine the files and differences against the code base,
- ask questions and discuss with the author and other developers,
- and suggest changes over email.
- The difficult part of this process is the manual collection the files under review
- and noting differences.
-- **Pair programming**
- is a code development process that incorporates continuous code review -
- two developers sit together at a computer,
- but only one of them actively codes whereas the other provides real-time feedback.
- It is a great way to inspect new code and train developers,
- especially if an experienced team member walks a younger developer through the new code,
- providing explanations and suggestions through a conversation.
- It is conducted in-person and synchronously but it can be time-consuming
- as the reviewer cannot do any other work during the pair programming period.
-- **Fagan code inspection**
- is a formal and heavyweight process of finding defects in specifications or designs
- during various phases of the software development process.
- There are several roles taken by different team members in a Fagan inspection
- and each inspection is a formal 7-step process with a predefined entry and exit criteria.
- See [Fagan inspection](https://en.wikipedia.org/wiki/Fagan_inspection)
- for full details on this method.
-- **Tool-assisted code review**
- process uses a specialised tool to facilitate the process of code review,
- which typically helps with the following tasks:
- (1) collecting and displaying the updated files and highlighting what has changed,
- (2) facilitating a conversation between team members (reviewers and developers), and
- (3) allowing code administrators and product managers
- a certain control and overview of the code development workflow.
- Modern tools may provide a handful of other functionalities too, such as metrics
- (e.g. inspection rate, defect rate, defect density).
-
-Each of the above techniques have their pros and cons and varying degrees practicality -
-it is up to the team to decide which ones are most suitable for the project and when to use them.
We will have a look at the **tool-assisted code review process**
using GitHub's built-in code review tool - **pull requests**.
It is a lightweight tool, included with GitHub's core service for free
@@ -245,106 +176,8 @@ The following diagram depicts the branches that you should have in the repositor
Adapted from Git Tutorial by sillevl (Creative Commons Attribution 4.0 International License)
-To achieve this, the following steps are needed.
-
-#### Step 1: Adding Collaborators to a Shared Repository
-
-You need to add the other team member(s) as collaborator(s) on your repository
-to enable them to create branches and pull requests.
-To do so, each repository owner needs to:
-
-1. Head over to Settings section of your software project's repository in GitHub.
- {: .image-with-shadow width="900px"}
-2. Select the **vertical** tab 'Collaborators' from the left and click the 'Add people' button.
- {: .image-with-shadow width="900px"}
-3. Add your collaborator(s) by their GitHub username(s), full name(s) or email address(es).
- {: .image-with-shadow width="900px"}
-4. Collaborator(s) will be notified of your invitation to join your repository
- based on their notification preferences.
-5. Once they accept the invitation, they will have the collaborator-level access to your repository
- and will show up in the list of your collaborators.
-
-See the full details on
-[collaborator permissions for personal repositories](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-user-account/managing-user-account-settings/permission-levels-for-a-user-account-repository)
-to understand what collaborators will be able to do within your repository.
-Note that repositories owned by an organisation have a
-[more granular access control](https://docs.github.com/en/get-started/learning-about-github/access-permissions-on-github)
-compared to that of personal repositories.
-
-#### Step 2: Preparing Your Local Environment for a Pull Request
-
-1. Obtain the GitHub URL of the shared repository you will be working on and clone it locally
- (make sure you do it outside your software repository's folder you have been working on so far).
- This will create a copy of the repository locally on your machine
- along with all of its (remote) branches.
- ~~~
- $ git clone
- $ cd
- ~~~
- {: .language-bash}
-2. Check with the repository owner (your team member)
- which feature (SR1.1.1 or SR1.2.1) they implemented in the
- [previous exercise](/32-software-design/index.html#implement-requirements)
- and what is the name of the branch they worked on.
- Let's assume the name of the branch was `feature-x`
- (you should amend the branch name for your case accordingly).
-3. Your task is to add tests for the code on `feature-x` branch.
- You should do so on a separate branch called `feature-x-tests`,
- which will branch off `feature-x`.
- This is to enable you later on to create a pull request
- from your `feature-x-tests` branch with your changes
- that can then easily be reviewed and compared with `feature-x`
- by the team member who created it.
-
- To do so, branch off a new local branch `feature-x-tests` from the remote `feature-x` branch
- (making sure you use the branch names that match your case).
- Also note that, while we say "remote" branch `feature-x` -
- you have actually obtained it locally on your machine when you cloned the remote repository.
- ~~~
- $ git checkout -b feature-x-tests origin/feature-x
- ~~~
- {: .language-bash}
-
- You are now located in the new (local) `feature-x-tests` branch
- and are ready to start adding your code.
-#### Step 3: Adding New Code
-
-> ## Exercise: Implement Tests for the New Feature
-> Look back at the
-> [solution requirements](/31-software-requirements/index.html#solution-requirements)
-> (SR1.1.1 or SR1.2.1)
-> for the feature that was implemented in your shared repository.
-> Implement tests against the appropriate specification in your local feature branch.
->
-> *Note: Try not to not fall into the trap of
-> writing the tests to test the existing code/implementation -
-> you should write the tests to make sure the code satisfies the requirements
-> regardless of the actual implementation.
-> You can treat the implementation as a
-> [black box](https://en.wikipedia.org/wiki/Black-box_testing) -
-> a typical approach to software testing -
-> as a way to make sure it is properly tested against its requirements
-> without introducing assumptions into the tests about its implementation.*
-{: .challenge}
-
-> ## Testing Based on Requirements
-> Tests should test functionality,
-> which stem from the software requirements,
-> rather than an implementation.
-> Tests can be seen as a reflection of those requirements -
-> checking if the requirements are satisfied.
-{: .callout}
-
-Remember to commit your new code to your branch `feature-x-tests`.
-
-~~~
-$ git add -A
-$ git commit -m "Added tests for feature-x."
-~~~
-{: .language-bash}
-
-#### Step 4: Submitting a Pull Request
+### Raising a pull request
When you have finished adding your tests
and committed the changes to your local `feature-x-tests`,
@@ -373,17 +206,44 @@ you have to do the following:
You should receive a similar pull request from other team members on your repository.
-#### Step 5: Code Review
+### Things to look for in a code review
+
+Outline the kinds of things you are looking for in a code review:
+
+* Readable
+* Minimal
+* Clean structure
+* Documentation
-1. The repository moderator/code reviewers reviews your changes
- and provides feedback to you in the form of comments.
-2. Respond to their comments and do any subsequent commits,
- as requested by reviewers.
-3. It may take a few rounds of exchanging comments and discussions until
- the team is ready to accept your changes.
+#### Exercise: review some code
-Perform the above actions on the pull request you received,
-this time acting as the moderator/code reviewer.
+Points the attendee to review code looking for these things
+
+#### Solution
+
+Highlights the kind of problems they should have found
+
+### Making sure code is valid
+
+Explain principle of checking for suitable tests
+
+#### Exercise: review the code for suitable tests
+
+#### Solution
+
+List of tests, highlighting the ones that are missing
+
+### What not to look for
+
+Covering what is a poor use of time to look for in reviews
+
+### Responding to review comments
+
+Technical explanation of how to respond to comments, also etiquette.
+
+### Exercise: responding and addressing comments
+
+Get people to address review comments, perhaps with dialogue
#### Step 6: Closing a Pull Request
@@ -465,6 +325,18 @@ and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-
they need to fix the requested changes or discuss more;
`APPROVED` to let the author they can merge their pull request.
+## Making code easy to review
+
+Info on how to make code easier for others to review
+
+## Empathy in review comments
+
+Info on importance of empathy
+
+## Designing a review process
+
+Considerations on how to design an effective code review process for your team.
+
> ## Exercise: Code Review in Your Own Working Environment
>
> At the start of this episode we briefly looked at a number of techniques for doing code review,
From 1fa9a338dd7bcfa27336190ae3dc7d82d010e049 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 15:27:25 +0100
Subject: [PATCH 02/98] Make exercises use the correct syntax to work
---
_episodes/41-code-review.md | 35 ++++++++++++++++++++---------------
1 file changed, 20 insertions(+), 15 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index e7b63508d..8b66176d9 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -215,23 +215,27 @@ Outline the kinds of things you are looking for in a code review:
* Clean structure
* Documentation
-#### Exercise: review some code
-
-Points the attendee to review code looking for these things
-
-#### Solution
-
-Highlights the kind of problems they should have found
+> ## Exercise: review some code
+>
+> Points the attendee to review code looking for these things
+>
+>> ## Solution
+>>
+>> Highlights the kind of problems they should have found
+> {: .solution}
+{: .challenge}
### Making sure code is valid
Explain principle of checking for suitable tests
-#### Exercise: review the code for suitable tests
-
-#### Solution
-
-List of tests, highlighting the ones that are missing
+> ## Exercise: review the code for suitable tests
+>
+>> ## Solution
+>>
+>> List of tests, highlighting the ones that are missing
+> {: .solution}
+{: .challenge}
### What not to look for
@@ -241,9 +245,10 @@ Covering what is a poor use of time to look for in reviews
Technical explanation of how to respond to comments, also etiquette.
-### Exercise: responding and addressing comments
-
-Get people to address review comments, perhaps with dialogue
+> ## Exercise: responding and addressing comments
+>
+> Get people to address review comments, perhaps with dialogue
+{: .challenge}
#### Step 6: Closing a Pull Request
From dc0a6c8a08b61dd20ce2d41ad2661474b97be2b2 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 15:34:51 +0100
Subject: [PATCH 03/98] Add exercise for initial code review
Includes solution of the kinds of problem to spot
---
_episodes/41-code-review.md | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 8b66176d9..b110e270e 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -217,11 +217,34 @@ Outline the kinds of things you are looking for in a code review:
> ## Exercise: review some code
>
-> Points the attendee to review code looking for these things
+> Go back to the pull request you created, and review the code, looking for the kinds
+> of problems that we have just discussed. There are examples of all the 4 main areas
+> in the pull request, so try to make at least one suggestion for each area.
>
>> ## Solution
>>
->> Highlights the kind of problems they should have found
+>> Here are some of the things you might have found were wrong with the code:
+>>
+>> **Is the code readable**
+>>
+>> * Unclear function name `s_dev` - uses an uncommon abbreviation increasing mental load
+>> when reading code that calls this function
+>> * Variable `number` not clear what it contains - prefer buiness name like `mean` or `mean_of_data`
+>>
+>> **Is the code minimal**
+>>
+>> * Could have used `np.std` to compute standard deviation of data without having to reimplement
+>> from scratch.
+>>
+>> **Does the code have a clean structure**
+>>
+>> * Have the function return the data, rather than having the graph name (a view layer consideration)
+>> leak into the model code.
+>>
+>> **Is the documentation up to date and correct**
+>>
+>> * The docs say it returns the standard deviation, but it actually returns a dictionary containing
+>> the standard deviation.
> {: .solution}
{: .challenge}
From d9cbea7e1049ed03fb575fa59839f9705de4aa54 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 15:53:21 +0100
Subject: [PATCH 04/98] Add exercise for reviewing code looking for sufficent
tests
---
_episodes/41-code-review.md | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index b110e270e..0d743445d 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -254,9 +254,38 @@ Explain principle of checking for suitable tests
> ## Exercise: review the code for suitable tests
>
+> Remind yourself of the specification of UR1.1.1 and write a list of
+> tests you'd expect to see for this feature. Review the code again and
+> expand this list to include any other edge cases the code makes you think
+> of. Finally, go through the tests in the PR and work out which tests are present.
+> Request changes for any tests that you think are missing.
+>
>> ## Solution
>>
->> List of tests, highlighting the ones that are missing
+>> Your list might include the following:
+>>
+>> 1. Standard deviation for one patient with multiple observations.
+>> 2. Standard deviation for two patients.
+>> 3. Graph includes a standard deviation graph.
+>> 4. Standard deviation function should raise an error if given empty data.
+>> 5. Computing standard deviation where deviation is different from variance.
+>> 6. Standard deviation function should give correct result given negative inputs.
+>> 7. Function should work with numpy arrays
+>>
+>> Looking at the tests in the PR, you might be content that tests for 1, 4 and 7 are present
+>> so you would request changes to add tests 2, 3, 5 and 6.
+>>
+>> In looking at the test you hopefully noticed that the test for numpy arrays is currently
+>> spuriously passing as it does not use the return value from the function in the assert.
+
+>> You may have spotted that the function actually computes the variance rather than
+>> the standard deviation. Perhaps that is even what made you think to add the test
+>> for some data where the variance and standard deviation are different.
+>> In more complex examples, it is often easier to spot code that looks like it could be wrong
+>> and think of a test that will exercise it. This saves embarassement if the code turns out
+>> to be right, means you have the missing test written if it is wrong, and is often quicker
+>> than trying to execute the code in your head to find out if it is correct.
+>>
> {: .solution}
{: .challenge}
From 10a93a1ffbc16f4c83bf7e378f14934253b85809 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 16:40:49 +0100
Subject: [PATCH 05/98] Fix missing blockquote marker
---
_episodes/41-code-review.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 0d743445d..b4d7183dd 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -277,7 +277,7 @@ Explain principle of checking for suitable tests
>>
>> In looking at the test you hopefully noticed that the test for numpy arrays is currently
>> spuriously passing as it does not use the return value from the function in the assert.
-
+>>
>> You may have spotted that the function actually computes the variance rather than
>> the standard deviation. Perhaps that is even what made you think to add the test
>> for some data where the variance and standard deviation are different.
From 83d77d151c137794b1023ec0fe0f1c676959fdfb Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 16:41:32 +0100
Subject: [PATCH 06/98] Add exercise for responding to review comments
Swapped the review exercise round so putting comments on other peoples
repositories as this doesn't require setting up collaborators, making
things simpler.
---
_episodes/41-code-review.md | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index b4d7183dd..965e62155 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -217,9 +217,10 @@ Outline the kinds of things you are looking for in a code review:
> ## Exercise: review some code
>
-> Go back to the pull request you created, and review the code, looking for the kinds
-> of problems that we have just discussed. There are examples of all the 4 main areas
-> in the pull request, so try to make at least one suggestion for each area.
+> Pick someone else in the group and go to the pull request they created.
+> Review the code, looking for the kinds of problems that we have just discussed.
+> There are examples of all the 4 main areas in the pull request,
+> so try to make at least one suggestion for each area.
>
>> ## Solution
>>
@@ -299,7 +300,15 @@ Technical explanation of how to respond to comments, also etiquette.
> ## Exercise: responding and addressing comments
>
-> Get people to address review comments, perhaps with dialogue
+> Look at the PR that you created on your repo, that should now have someone elses comments
+> on it.
+> For each comment, either reply explaining why you don't think the change is necessary
+> or make the change and push a commit fixing it. You can reply to the comment indicating you
+> have done it.
+>
+> At the same time, people will be addressing your comments. If you're happy that your
+> comment has been suitably addressed, you can mark it as resolved. Once you're happy they
+> have all been addressed, you can approve the PR.
{: .challenge}
#### Step 6: Closing a Pull Request
From 3b1930f5a7e93ad2d05d7c3e3009d13c7edb84cf Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 17:07:37 +0100
Subject: [PATCH 07/98] Make solution comment follow guidelines of providing an
actionable alternative
---
_episodes/41-code-review.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 965e62155..eb94c3d6d 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -229,7 +229,7 @@ Outline the kinds of things you are looking for in a code review:
>> **Is the code readable**
>>
>> * Unclear function name `s_dev` - uses an uncommon abbreviation increasing mental load
->> when reading code that calls this function
+>> when reading code that calls this function, prefer `standard_deviation`.
>> * Variable `number` not clear what it contains - prefer buiness name like `mean` or `mean_of_data`
>>
>> **Is the code minimal**
From 8fd3ead03da6196a7de770e8cc45c0d92ddbf073 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 17:08:03 +0100
Subject: [PATCH 08/98] Add section on what to look out for in a code review
Remove the bullet points from the end section that are now covered by
this section.
---
_episodes/41-code-review.md | 68 ++++++++++++++++++++++++++++---------
1 file changed, 52 insertions(+), 16 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index eb94c3d6d..78f79312d 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -208,12 +208,59 @@ You should receive a similar pull request from other team members on your reposi
### Things to look for in a code review
-Outline the kinds of things you are looking for in a code review:
+Reviewing code effectively takes practise. However, here is some guidance on the
+kinds of things you should be looking for when reviewing a piece of code.
+
+Start by understanding what the code _should_ do, by reading the specification/user requriement,
+the pull request description and talking to the developer.
+
+Once you're happy, start reading the code (skip any tests for now). You're
+going to be assessing the code in 4 key areas:
+
+* Is the code readable
+* Is the code a minimal change
+* Is the structure of the code clear
+* Is there appropriate and up-to-date documentation
+
+#### Is the code readable
+
+Think about do the names of the variables, do they [follow guidelines for good
+names?](../15-coding-conventions/index.html#l#naming-conventions)
+
+Do you understand what conditions in if statements are for?
+
+#### Is the code a minimal change
+
+Does the code reimplement anything that already exists, either
+elsewhere in the codebase or in a library you know about?
+
+Does the code implement something that isn't on the ticket?
+
+#### Is the structure of the code clear
+
+Do functions do just one thing? Have appropriate design
+patterns been used (e.g. separating out the model logic from
+any view considerations)?
+
+#### Is there appropriate and up-to-date documentation
+
+If functionality has changed, has corresponding documentation been
+updated. If new functions have been added, do they have appropriate
+levels of documentation. Does the documentation make sense?
+
+Are there clear and useful comments that explain complex designs
+and focus on the "why/because" rather than the "what/how"?
+
+### Effective comments
+
+Make sure your comments are specific and actionable.
+
+Try to be as specific as you can, rather than "this code is unclear"
+prefer, "I don't understand what values this variable can hold".
+
+Make it clear in the comment if you want something to change as part
+of this PR. Ideally provide an idea (e.g. better variable name).
-* Readable
-* Minimal
-* Clean structure
-* Documentation
> ## Exercise: review some code
>
@@ -336,16 +383,7 @@ Swarmia](https://www.swarmia.com/blog/a-complete-guide-to-code-reviews/?utm_term
and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/)):
1. Decide the focus of your code review process, e.g., consider some of the following:
- - code design and functionality -
- does the code fit in the overall design and does it do what was intended?
- - code understandability and complexity -
- is the code readable and would another developer be able to understand it?
- tests - does the code have automated tests?
- - naming - are names used for variables and functions descriptive,
- do they follow naming conventions?
- - comments and documentation -
- are there clear and useful comments that explain complex designs well
- and focus on the "why/because" rather than the "what/how"?
2. Do not review code too quickly and do not review for too long in one sitting.
According to
[“Best Kept Secrets of Peer Code Review” (Cohen, 2006)](https://www.amazon.co.uk/Best-Kept-Secrets-Peer-Review/dp/1599160676) -
@@ -359,8 +397,6 @@ and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-
e.g. reserve them for critical portions of code and avoid nit-picking on small details.
Try using automated checks and linters when possible,
e.g. for consistent usage of certain terminology across the code and code styles.
-4. Communicate clearly and effectively -
- when reviewing code, be explicit about the action you request from the author.
5. Foster a positive feedback culture:
- give feedback about the code, not about the author
- accept that there are multiple correct solutions to a problem
From 344374d675e87bf35d11066d24607944139ebad4 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 17:16:13 +0100
Subject: [PATCH 09/98] Add section about how to check code is suitably tested
and correct
Removed associated steps from the list at the end
---
_episodes/41-code-review.md | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 78f79312d..6fe29f5e3 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -298,7 +298,26 @@ of this PR. Ideally provide an idea (e.g. better variable name).
### Making sure code is valid
-Explain principle of checking for suitable tests
+The other key thing you want to verify in code review is that the code is correct and
+well tested. One approach to do this is to build up a list of tests you expect to see
+(and the results you'd expect them to have), and then verify that all these tests are
+present and correct.
+
+Start by listing out all the tests you'd expect to see based on the specification.
+
+As you are going through the code, add to this list with any more tests you think
+of, making sure to add tests for:
+
+* All paths through the code.
+* Making each if statement be evaluated as `True` and `False`.
+* All loops are exercised with empty, single and multi-element sequences.
+* Edge cases that you spot.
+* Any code that you're not sure how it behaves under certain circumstances.
+
+Once you have built the list, go through the tests in the PR. Make sure
+the tests test what you expect (so inspect them closely!). Add a comment
+to the PR for any tests that are on your list that you can't find a suitable
+test in the PR for.
> ## Exercise: review the code for suitable tests
>
@@ -382,8 +401,6 @@ Here are some examples of best practices for you to consider
Swarmia](https://www.swarmia.com/blog/a-complete-guide-to-code-reviews/?utm_term=code%20review&utm_campaign=Code+review+best+practices&utm_source=adwords&utm_medium=ppc&hsa_acc=6644081770&hsa_cam=14940336179&hsa_grp=131344939434&hsa_ad=552679672005&hsa_src=g&hsa_tgt=kwd-17740433&hsa_kw=code%20review&hsa_mt=b&hsa_net=adwords&hsa_ver=3&gclid=Cj0KCQiAw9qOBhC-ARIsAG-rdn7_nhMMyE7aeSzosRRqZ52vafBOyMrpL4Ypru0PHWK4Rl8QLIhkeA0aAsxqEALw_wcB)
and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/)):
-1. Decide the focus of your code review process, e.g., consider some of the following:
- - tests - does the code have automated tests?
2. Do not review code too quickly and do not review for too long in one sitting.
According to
[“Best Kept Secrets of Peer Code Review” (Cohen, 2006)](https://www.amazon.co.uk/Best-Kept-Secrets-Peer-Review/dp/1599160676) -
From 9e7fffbb76f48606de44fc52acad01594a6aa81f Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Thu, 27 Jul 2023 17:16:29 +0100
Subject: [PATCH 10/98] Fix spelling mistake of embarrassement
---
_episodes/41-code-review.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 6fe29f5e3..2a68ccfea 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -349,7 +349,7 @@ test in the PR for.
>> the standard deviation. Perhaps that is even what made you think to add the test
>> for some data where the variance and standard deviation are different.
>> In more complex examples, it is often easier to spot code that looks like it could be wrong
->> and think of a test that will exercise it. This saves embarassement if the code turns out
+>> and think of a test that will exercise it. This saves embarrassment if the code turns out
>> to be right, means you have the missing test written if it is wrong, and is often quicker
>> than trying to execute the code in your head to find out if it is correct.
>>
From 0bbf46c821519510641673572e3b40dd8e88a25d Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Tue, 1 Aug 2023 15:16:52 +0100
Subject: [PATCH 11/98] Add a section on what not to look for in a code review
---
_episodes/41-code-review.md | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 2a68ccfea..6516bd853 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -358,7 +358,27 @@ test in the PR for.
### What not to look for
-Covering what is a poor use of time to look for in reviews
+The overriding priority for reviewing code should be making sure progress is being made -
+don't let perfect be the enemy of good here. Further, research has shown that the first hour
+of reviewing code is the most effective, with diminishing returns after that.
+
+To that end, here are a few things you shouldn't be trying to spot when reviewing:
+
+#### Linting issues, or anything else that an automated tool can spot
+
+Get the CI to do this - this will save the reviewer time, be more accurate
+and avoid needless conflict.
+
+#### Bugs
+
+It is easier to make sure there are sufficient tests - you are not an accurate
+computer simulator anyway.
+
+#### Issues that pre-date the change
+
+You may spot something that the reviewer didn't introduce and think they could
+fix it while in the area, but this can be a rabbit hole. A better approach would be to
+raise a PR after this one has been merged fixing the thing you spotted.
### Responding to review comments
From abbda406731a5c2f45537532ad9075b257131f0e Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Tue, 1 Aug 2023 15:27:59 +0100
Subject: [PATCH 12/98] Add section on responding to review comments
---
_episodes/41-code-review.md | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 6516bd853..f49ddbc70 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -382,7 +382,23 @@ raise a PR after this one has been merged fixing the thing you spotted.
### Responding to review comments
-Technical explanation of how to respond to comments, also etiquette.
+When you receive comments on your review, there are a few different things that you will want
+to do.
+
+With some, you will understand and agree with what the reviewer is saying. With these comments,
+you should make the change to your code on your branch. Once you've made the change you can
+commit it. It might be helpful to add a thumbs up reaction to the comment, so the reviewer knows
+you have addressed it.
+
+TODO: screenshot of adding a emoji reaction.
+
+With some, the comment might not make total sense. You can reply to comments for clarification.
+
+TODO: screenshot of adding a comment.
+
+However, if you disagree, or are really lost on what they are driving it, it will be best to
+talk to them in person. Discussions done on code reviews can often feel quite adversarial -
+discussing what the best solution is in person can often defuse this.
> ## Exercise: responding and addressing comments
>
From 4ce0614bde028fbd0deb10f835b2c891490ba7fd Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Tue, 1 Aug 2023 16:20:29 +0100
Subject: [PATCH 13/98] Add section about making code easy to review
---
_episodes/41-code-review.md | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index f49ddbc70..b19a32876 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -482,7 +482,27 @@ and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-
## Making code easy to review
-Info on how to make code easier for others to review
+There are a few things you can do when raising a pull request to make it
+as easy as possible for the reviewer to review your code:
+
+The most important thing to keep in mind is how long your pull request is. Smaller
+changes, that just make one small improvement, will be much quicker and easier to
+review. There is no golden rule, but 100 - 500 lines is a good size. More than
+1000 lines is almost certainly too big.
+
+Even within a single review, try to keep each commit to be making one logical change.
+This can help if your review would otherwise be too large. In particular, if you've
+reformatted, refactored and changed the behavior of the code make sure each of these
+is in a separate commit (i.e reformat the code, commit, refactor the code, commit, alter
+the behavior of the code, commit).
+
+Make sure you write a clear description of the content and purpose of the change.
+This should be provided as the pull request description.
+This should provide the context that reading the code will make more sense.
+
+It is also a good idea to review your code yourself. In doing this you will spot
+the more obvious issues with your code, allowing your reviewer to focus on the
+things you cannot spot.
## Empathy in review comments
From a2a2457069cf18a1f22581521e9e69a76f5814f6 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Tue, 1 Aug 2023 16:27:28 +0100
Subject: [PATCH 14/98] Add section about empathy in review
---
_episodes/41-code-review.md | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index b19a32876..0f99d0eaf 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -450,10 +450,6 @@ and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-
e.g. reserve them for critical portions of code and avoid nit-picking on small details.
Try using automated checks and linters when possible,
e.g. for consistent usage of certain terminology across the code and code styles.
-5. Foster a positive feedback culture:
- - give feedback about the code, not about the author
- - accept that there are multiple correct solutions to a problem
- - sandwich criticism with positive comments and praise
7. Utilise multiple code review techniques -
use email,
pair programming,
@@ -506,7 +502,22 @@ things you cannot spot.
## Empathy in review comments
-Info on importance of empathy
+Code is written by humans (mostly!), and code review is a form of communication. As such
+empathy is really important for effective reviewing.
+
+When reviewing code, it can be sometimes frustrating when code is confusing, particularly
+as it will be implemented differently to how you would have done it. However, it is important
+as a reviewer to be compassionate to the person whose code you are reviewing. Specifically:
+
+* Identify positives in code as and when you find them (particularly if it is an improvement on
+something you've previously fed back on in a previous review).
+* Remember different doesn't mean better - only request changes if the code is wrong or hard to understand.
+* Limit the number of non-critical suggestions to a few - you are aiming for better rather than perfect.
+* Ask questions to understand why something has been done a certain way rather than assuming you
+know a better way.
+* If a conversation is taking place on a review and hasn't been resolved by a
+single back-and-forth exchange, then schedule a conversation to discuss instead
+(recording the result on the PR).
## Designing a review process
From cd06ebdb942d4c5a0f2f593f50d04f584bd2807b Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Tue, 1 Aug 2023 16:44:30 +0100
Subject: [PATCH 15/98] Add considerations for a code review process
---
_episodes/41-code-review.md | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 0f99d0eaf..2299fe4e4 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -521,7 +521,26 @@ single back-and-forth exchange, then schedule a conversation to discuss instead
## Designing a review process
-Considerations on how to design an effective code review process for your team.
+To maximize the benefit of a code review it needs a process that is followed by everyone
+involved, and that everyone believes that process provides value.
+
+One way to foster this is to design the process as a team. When you're doing this you
+should consider:
+
+* Do all changes need to go through code review
+* What technologies will you use to manage the review process
+* How quickly do you expect someone to review the code once you've raised a PR?
+* How long should be spent reviewing code?
+* What kind of issues are (and aren't) appropriate to raise in a PR?
+* How will someone know when they are expected to take action (e.g. review a PR).
+
+Once you've introduced a review process, you should monitor (either formally or
+informally) how well it is working.
+
+It is important that reviews are processed quickly, to avoid costly context switching.
+We recommend aiming for 3 hours to get a first review, with the PR being merged the same
+day in most cases. If you are regularly missing these targets, then you should review
+where things are getting stuck and work out what you can do to move things along.
> ## Exercise: Code Review in Your Own Working Environment
>
From 36aa45d4838eade71a42be8345314eb51a5de00b Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 12:34:52 +0100
Subject: [PATCH 16/98] Add back in the different kinds of code review
Without going into detail, shows that there are other options that can
be looked into.
---
_episodes/41-code-review.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 2299fe4e4..62aff1cc0 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -83,6 +83,14 @@ Since the cost of bug fixes grows in orders of magnitude throughout the software
it is far more efficient to find and fix defects
as close as possible to the point where they were introduced.
+There are several **code review techniques** with various degree of formality
+and the use of a technical infrastructure, including:
+
+ - Over-the-shoulder code review
+ - Pair programming
+ - [Fagan code inspection]((https://en.wikipedia.org/wiki/Fagan_inspection))
+ - Tool assisted code review
+
We will have a look at the **tool-assisted code review process**
using GitHub's built-in code review tool - **pull requests**.
It is a lightweight tool, included with GitHub's core service for free
From 6bfdf169cec93df6cfd2c5355d5e02672dd9e90c Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 14:21:34 +0100
Subject: [PATCH 17/98] Rework the code review in action section
Exercise has changed, so update the text to reflect this.
It is a little confusing that you raise a PR on your own repository, and
then comment on a different one, but this does allow for not needing to
work out the collaboration.
---
_episodes/41-code-review.md | 42 ++++++++++++++++---------------------
1 file changed, 18 insertions(+), 24 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 62aff1cc0..8f2bfe5e4 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -152,31 +152,25 @@ you will need to specify the base branch and the head branch.
## Code Review and Pull Requests In Action
Let's see this in action -
-you and your fellow learners are going to be organised in small teams
-and assume to be collaborating in the shared repository model.
-You will be added as a collaborator to another team member's repository
-(which becomes the shared repository in this context)
-and, likewise, you will add other team members as collaborators on your repository.
-You can form teams of two and work on each other's repositories.
-If there are 3 members in your group you can go in a round robin fashion
-(the first team member does a pull request on the second member's repository
-and receives a pull request on their repository from the third team member).
-If you are going through the material on your own and do not have a collaborator,
-you can do pull requests on your own repository from one to another branch.
-
-Recall [solution requirements SR1.1.1 and SR1.2.1](../31-software-requirements/index.html#solution-requirements)
+you are going to act as a reviewer on a change to the codebase raised by a
+fictional colleague on one of your course mates' repository.
+Once this is done, you will then take on the role of the fictional colleague
+and respond to the review on your repository.
+If you are completing this course by yourself, you can raise the review on
+your own repository, review it there and finally respond to your own review
+comments. This is actually a very sensible thing to do in general - looking
+at your own code in a review window will allow you to spot mistakes you
+didn't see before!
+
+Recall [solution requirements SR1.1.1](../31-software-requirements/index.html#solution-requirements)
from an earlier episode.
-Your team member has implemented one of them according to the specification
-(let's call it `feature-x`)
-but tests are still missing.
-You are now tasked with implementing tests on top of that existing implementation
-to make sure the new feature indeed satisfies the requirements.
-You will propose changes to their repository
-(the shared repository in this context)
-via pull request (acting as the code author)
-and engage in code review with your team member (acting as a code reviewer).
-Similarly, you will receive a pull request on your repository from another team member,
-in which case the roles will be reversed.
+Your fictional colleague has implemented it according to the specification
+and pushed it to a branch `std-dev`.
+You will turn this branch into a pull request for your fictional colleague on your
+repository.
+You will then engage in code review for the change (acting as a code reviewer) on
+a course mates repository.
+Once complete, you will respond to the pull request on your repository from another team member,.
The following diagram depicts the branches that you should have in the repository.
{: .image-with-shadow width="800px"}
From 606f996d93d908663b048d11d2e14e8c10a55d31 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 14:38:21 +0100
Subject: [PATCH 18/98] Update the section about raising a review
---
_episodes/41-code-review.md | 36 ++++++++++++++++--------------------
1 file changed, 16 insertions(+), 20 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 8f2bfe5e4..d8716cb08 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -179,34 +179,30 @@ Adapted from
Date: Fri, 4 Aug 2023 14:45:09 +0100
Subject: [PATCH 19/98] Update closing pull request for new exercise structure
---
_episodes/41-code-review.md | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index d8716cb08..e9a911504 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -411,18 +411,16 @@ discussing what the best solution is in person can often defuse this.
> have all been addressed, you can approve the PR.
{: .challenge}
-#### Step 6: Closing a Pull Request
+### Closing a Pull Request
-1. Once the moderator approves your changes, either one of you can merge onto the base branch.
+1. Once the reviewer approves your changes, the person whose repository it is can
+ merge onto the base branch.
Typically, it is the responsibility of the code's author to do the merge
but this may differ from team to team.
{: .image-with-shadow width="900px"}
2. Delete the merged branch to reduce the clutter in the repository.
-Repeat the above actions for the pull request you received.
-
-If the work on the feature branch is completed and it is sufficiently tested,
-the feature branch can now be merged into the `develop` branch.
+Repeat the above actions for the pull request on your repository.
## Best Practice for Code Review
From 390fc7ee498acef9c2753dd2516850cc91c2651a Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 14:51:13 +0100
Subject: [PATCH 20/98] Merge suggestion for trying code review techniques into
the intro
Rather than have an unsorted list, work the useful recommendations into
relevant sections of the course.
---
_episodes/41-code-review.md | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index e9a911504..94d1cdaa5 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -91,8 +91,9 @@ and the use of a technical infrastructure, including:
- [Fagan code inspection]((https://en.wikipedia.org/wiki/Fagan_inspection))
- Tool assisted code review
-We will have a look at the **tool-assisted code review process**
-using GitHub's built-in code review tool - **pull requests**.
+It is worth trying multiple code review techniques to see what works
+best for your team. We will have a look at the **tool-assisted code review process**, which is likely to be the most effective and efficent.
+We will use GitHub's built-in code review tool - **pull requests**.
It is a lightweight tool, included with GitHub's core service for free
and has gained popularity within the software development community in recent years.
@@ -446,15 +447,6 @@ and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-
e.g. reserve them for critical portions of code and avoid nit-picking on small details.
Try using automated checks and linters when possible,
e.g. for consistent usage of certain terminology across the code and code styles.
-7. Utilise multiple code review techniques -
- use email,
- pair programming,
- over-the-shoulder,
- team discussions and
- tool-assisted or
- any combination that works for your team.
- However, for the most effective and efficient code reviews,
- tool-assisted process is recommended.
9. From a more technical perspective:
- use a feature branch for pull requests as you can push follow-up commits
if you need to update your proposed changes
From 03a591912d429b4d272e654fba6078eb80a76b93 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 14:58:38 +0100
Subject: [PATCH 21/98] Remove bit about sticking to a process
This is covered in Designing a review process
---
_episodes/41-code-review.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 94d1cdaa5..d766b851c 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -427,8 +427,6 @@ Repeat the above actions for the pull request on your repository.
There are multiple perspectives to a code review process -
from general practices to technical details relating to different roles involved in the process.
-It is critical for the code's quality, stability and maintainability
-that the team decides on this process and sticks to it.
Here are some examples of best practices for you to consider
(also check these useful code review blogs from [
Swarmia](https://www.swarmia.com/blog/a-complete-guide-to-code-reviews/?utm_term=code%20review&utm_campaign=Code+review+best+practices&utm_source=adwords&utm_medium=ppc&hsa_acc=6644081770&hsa_cam=14940336179&hsa_grp=131344939434&hsa_ad=552679672005&hsa_src=g&hsa_tgt=kwd-17740433&hsa_kw=code%20review&hsa_mt=b&hsa_net=adwords&hsa_ver=3&gclid=Cj0KCQiAw9qOBhC-ARIsAG-rdn7_nhMMyE7aeSzosRRqZ52vafBOyMrpL4Ypru0PHWK4Rl8QLIhkeA0aAsxqEALw_wcB)
From a973929f627706e363088730d94df32feeac99d6 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:07:08 +0100
Subject: [PATCH 22/98] Move citations for length of time spent reviewing and
code length inline
These are important points that are covered by other parts of the
episode, so include the relevant source material.
---
_episodes/41-code-review.md | 19 +++++++------------
1 file changed, 7 insertions(+), 12 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index d766b851c..f99a7e8da 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -358,8 +358,10 @@ test in the PR for.
### What not to look for
The overriding priority for reviewing code should be making sure progress is being made -
-don't let perfect be the enemy of good here. Further, research has shown that the first hour
-of reviewing code is the most effective, with diminishing returns after that.
+don't let perfect be the enemy of good here.
+According to [“Best Kept Secrets of Peer Code Review” (Cohen, 2006)](https://www.amazon.co.uk/Best-Kept-Secrets-Peer-Review/dp/1599160676)
+it has been shown that the first hour of reviewing code is the most effective,
+with diminishing returns after that.
To that end, here are a few things you shouldn't be trying to spot when reviewing:
@@ -432,14 +434,6 @@ Here are some examples of best practices for you to consider
Swarmia](https://www.swarmia.com/blog/a-complete-guide-to-code-reviews/?utm_term=code%20review&utm_campaign=Code+review+best+practices&utm_source=adwords&utm_medium=ppc&hsa_acc=6644081770&hsa_cam=14940336179&hsa_grp=131344939434&hsa_ad=552679672005&hsa_src=g&hsa_tgt=kwd-17740433&hsa_kw=code%20review&hsa_mt=b&hsa_net=adwords&hsa_ver=3&gclid=Cj0KCQiAw9qOBhC-ARIsAG-rdn7_nhMMyE7aeSzosRRqZ52vafBOyMrpL4Ypru0PHWK4Rl8QLIhkeA0aAsxqEALw_wcB)
and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/)):
-2. Do not review code too quickly and do not review for too long in one sitting.
- According to
- [“Best Kept Secrets of Peer Code Review” (Cohen, 2006)](https://www.amazon.co.uk/Best-Kept-Secrets-Peer-Review/dp/1599160676) -
- the first hour of review matters the most as
- detection of defects significantly drops after this period.
- [Studies into code review](https://smartbear.com/resources/ebooks/the-state-of-code-review-2020-report/)
- also show that you should not review more than 400 lines of code at a time.
- Conducting more frequent shorter reviews seems to be more effective.
3. Decide on the level of depth for code reviews
to maintain the balance between the creation time and time spent reviewing code -
e.g. reserve them for critical portions of code and avoid nit-picking on small details.
@@ -469,8 +463,9 @@ as easy as possible for the reviewer to review your code:
The most important thing to keep in mind is how long your pull request is. Smaller
changes, that just make one small improvement, will be much quicker and easier to
-review. There is no golden rule, but 100 - 500 lines is a good size. More than
-1000 lines is almost certainly too big.
+review. There is no golden rule, but [studies into code review](https://smartbear.com/resources/ebooks/the-state-of-code-review-2020-report/)
+show that you should not review more than 400 lines of code at a time so this is
+a reasonable target to aim for. More than 1000 lines is almost certainly too big.
Even within a single review, try to keep each commit to be making one logical change.
This can help if your review would otherwise be too large. In particular, if you've
From 30e46d152fda61d86a3d184068bffca5d4253123 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:09:19 +0100
Subject: [PATCH 23/98] Move additional reading links to the end of the episode
---
_episodes/41-code-review.md | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index f99a7e8da..a608d6bc6 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -427,13 +427,6 @@ Repeat the above actions for the pull request on your repository.
## Best Practice for Code Review
-There are multiple perspectives to a code review process -
-from general practices to technical details relating to different roles involved in the process.
-Here are some examples of best practices for you to consider
-(also check these useful code review blogs from [
-Swarmia](https://www.swarmia.com/blog/a-complete-guide-to-code-reviews/?utm_term=code%20review&utm_campaign=Code+review+best+practices&utm_source=adwords&utm_medium=ppc&hsa_acc=6644081770&hsa_cam=14940336179&hsa_grp=131344939434&hsa_ad=552679672005&hsa_src=g&hsa_tgt=kwd-17740433&hsa_kw=code%20review&hsa_mt=b&hsa_net=adwords&hsa_ver=3&gclid=Cj0KCQiAw9qOBhC-ARIsAG-rdn7_nhMMyE7aeSzosRRqZ52vafBOyMrpL4Ypru0PHWK4Rl8QLIhkeA0aAsxqEALw_wcB)
-and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/)):
-
3. Decide on the level of depth for code reviews
to maintain the balance between the creation time and time spent reviewing code -
e.g. reserve them for critical portions of code and avoid nit-picking on small details.
@@ -548,4 +541,14 @@ where things are getting stuck and work out what you can do to move things along
> - Any particular practices you would use?
{: .challenge}
+## Other reading
+
+There are multiple perspectives to a code review process -
+from general practices to technical details relating to different roles involved in the process.
+We have discussed the main points, but do check these useful code review blogs from [
+Swarmia](https://www.swarmia.com/blog/a-complete-guide-to-code-reviews/?utm_term=code%20review&utm_campaign=Code+review+best+practices&utm_source=adwords&utm_medium=ppc&hsa_acc=6644081770&hsa_cam=14940336179&hsa_grp=131344939434&hsa_ad=552679672005&hsa_src=g&hsa_tgt=kwd-17740433&hsa_kw=code%20review&hsa_mt=b&hsa_net=adwords&hsa_ver=3&gclid=Cj0KCQiAw9qOBhC-ARIsAG-rdn7_nhMMyE7aeSzosRRqZ52vafBOyMrpL4Ypru0PHWK4Rl8QLIhkeA0aAsxqEALw_wcB)
+and [Smartbear](https://smartbear.com/learn/code-review/best-practices-for-peer-code-review/).
+
+The key thing is to try it, and iterate the process until it works well for your team.
+
{% include links.md %}
From 987f052b951f957c4057168dead022396eb887a5 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:10:02 +0100
Subject: [PATCH 24/98] Remove discussion about timings as covered in Designing
a review process
---
_episodes/41-code-review.md | 3 ---
1 file changed, 3 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index a608d6bc6..a8edb3ad2 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -427,9 +427,6 @@ Repeat the above actions for the pull request on your repository.
## Best Practice for Code Review
-3. Decide on the level of depth for code reviews
- to maintain the balance between the creation time and time spent reviewing code -
- e.g. reserve them for critical portions of code and avoid nit-picking on small details.
Try using automated checks and linters when possible,
e.g. for consistent usage of certain terminology across the code and code styles.
9. From a more technical perspective:
From 83dd9c36e75daab9691d9e539ea8d838689cb0a6 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:24:30 +0100
Subject: [PATCH 25/98] Add more references to the size of PR
---
_episodes/41-code-review.md | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index a8edb3ad2..018e5a325 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -432,10 +432,6 @@ Repeat the above actions for the pull request on your repository.
9. From a more technical perspective:
- use a feature branch for pull requests as you can push follow-up commits
if you need to update your proposed changes
- - avoid large pull requests as they are more difficult to review.
- You can refer to some [studies](https://jserd.springeropen.com/articles/10.1186/s40411-018-0058-0)
- and [Google recommendations](https://google.github.io/eng-practices/review/developer/small-cls.html)
- as to what a "large pull request" is but be aware that it is not exact science.
- don't force push to a pull request as it changes the repository history
and can corrupt your pull request for other collaborators
- use pull request states in GitHub effectively (based on your team's code review process) -
@@ -455,7 +451,10 @@ The most important thing to keep in mind is how long your pull request is. Small
changes, that just make one small improvement, will be much quicker and easier to
review. There is no golden rule, but [studies into code review](https://smartbear.com/resources/ebooks/the-state-of-code-review-2020-report/)
show that you should not review more than 400 lines of code at a time so this is
-a reasonable target to aim for. More than 1000 lines is almost certainly too big.
+a reasonable target to aim for.
+You can refer to some [studies](https://jserd.springeropen.com/articles/10.1186/s40411-018-0058-0)
+and [Google recommendations](https://google.github.io/eng-practices/review/developer/small-cls.html)
+as to what a "large pull request" is but be aware that it is not exact science.
Even within a single review, try to keep each commit to be making one logical change.
This can help if your review would otherwise be too large. In particular, if you've
From 27cb1c63e4719f1a8334e9f7973fb77b2f0c4634 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:25:02 +0100
Subject: [PATCH 26/98] Remove instruction to use branches
This is the only way explained in this episode, and you'd have to go out
of your way to do it any other way.
---
_episodes/41-code-review.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 018e5a325..6f7e82fd7 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -430,8 +430,6 @@ Repeat the above actions for the pull request on your repository.
Try using automated checks and linters when possible,
e.g. for consistent usage of certain terminology across the code and code styles.
9. From a more technical perspective:
- - use a feature branch for pull requests as you can push follow-up commits
- if you need to update your proposed changes
- don't force push to a pull request as it changes the repository history
and can corrupt your pull request for other collaborators
- use pull request states in GitHub effectively (based on your team's code review process) -
From 4260e2cacaf7da1def8dd00cd9f68d70a55be3ef Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:26:44 +0100
Subject: [PATCH 27/98] Remove advice about force pushing
While this is generally good advice, some open source repositories will
require force-pushing to keep commit history tidy. Further, this is good
advice in general, not related to pull requests, and most people won't
have come across the idea of force-pushing anway, so no need to confuse
them.
It also isn't accurate, it can't corrupt the pull request, it can just
get the reviewer tied in a bit of a knot if they don't know what they
are doing and pulled the code locally.
---
_episodes/41-code-review.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 6f7e82fd7..6e9bb4e78 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -430,8 +430,6 @@ Repeat the above actions for the pull request on your repository.
Try using automated checks and linters when possible,
e.g. for consistent usage of certain terminology across the code and code styles.
9. From a more technical perspective:
- - don't force push to a pull request as it changes the repository history
- and can corrupt your pull request for other collaborators
- use pull request states in GitHub effectively (based on your team's code review process) -
e.g. in GitHub you can open a pull request in a `DRAFT` state
to show progress or request early feedback;
From 377839267142c50c107c4a284e79d2ad970ff99c Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:28:06 +0100
Subject: [PATCH 28/98] Move info about using PR states in GH to process
section
---
_episodes/41-code-review.md | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 6e9bb4e78..97377c870 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -430,13 +430,6 @@ Repeat the above actions for the pull request on your repository.
Try using automated checks and linters when possible,
e.g. for consistent usage of certain terminology across the code and code styles.
9. From a more technical perspective:
- - use pull request states in GitHub effectively (based on your team's code review process) -
- e.g. in GitHub you can open a pull request in a `DRAFT` state
- to show progress or request early feedback;
- `READY FOR REVIEW` when you are ready for feedback;
- `CHANGES REQUESTED` to let the author know
- they need to fix the requested changes or discuss more;
- `APPROVED` to let the author they can merge their pull request.
## Making code easy to review
@@ -500,6 +493,13 @@ should consider:
* What kind of issues are (and aren't) appropriate to raise in a PR?
* How will someone know when they are expected to take action (e.g. review a PR).
+You could also consider using pull request states in GitHub:
+ - Open a pull request in a `DRAFT` state to show progress or request early feedback;
+ - `READY FOR REVIEW` when you are ready for feedback
+ - `CHANGES REQUESTED` to let the author know
+ they need to fix the requested changes or discuss more;
+ - `APPROVED` to let the author they can merge their pull request.
+
Once you've introduced a review process, you should monitor (either formally or
informally) how well it is working.
From a7bbb4d9ae53af3c1d1b0063ad21aebcee42e3c7 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:28:41 +0100
Subject: [PATCH 29/98] Remove linting advice as covered in what not to review
---
_episodes/41-code-review.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 97377c870..8102499b6 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -427,8 +427,6 @@ Repeat the above actions for the pull request on your repository.
## Best Practice for Code Review
- Try using automated checks and linters when possible,
- e.g. for consistent usage of certain terminology across the code and code styles.
9. From a more technical perspective:
## Making code easy to review
From 8b3496fe1382ceaf5e059d3fe6ff80c93dcbfd8b Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 15:28:50 +0100
Subject: [PATCH 30/98] Remove empty section
---
_episodes/41-code-review.md | 4 ----
1 file changed, 4 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 8102499b6..ebd90752d 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -425,10 +425,6 @@ discussing what the best solution is in person can often defuse this.
Repeat the above actions for the pull request on your repository.
-## Best Practice for Code Review
-
-9. From a more technical perspective:
-
## Making code easy to review
There are a few things you can do when raising a pull request to make it
From 15eed1aac8e008eeb298a4b589750c17c12a4f61 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 16:34:39 +0100
Subject: [PATCH 31/98] Line by line edit of new content
---
_episodes/41-code-review.md | 67 +++++++++++++++++++++----------------
1 file changed, 38 insertions(+), 29 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index ebd90752d..bde3a764c 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -92,7 +92,7 @@ and the use of a technical infrastructure, including:
- Tool assisted code review
It is worth trying multiple code review techniques to see what works
-best for your team. We will have a look at the **tool-assisted code review process**, which is likely to be the most effective and efficent.
+best for you and your team. We will have a look at the **tool-assisted code review process**, which is likely to be the most effective and efficient.
We will use GitHub's built-in code review tool - **pull requests**.
It is a lightweight tool, included with GitHub's core service for free
and has gained popularity within the software development community in recent years.
@@ -154,7 +154,7 @@ you will need to specify the base branch and the head branch.
Let's see this in action -
you are going to act as a reviewer on a change to the codebase raised by a
-fictional colleague on one of your course mates' repository.
+fictional colleague on one of your course mate's repository.
Once this is done, you will then take on the role of the fictional colleague
and respond to the review on your repository.
If you are completing this course by yourself, you can raise the review on
@@ -170,8 +170,8 @@ and pushed it to a branch `std-dev`.
You will turn this branch into a pull request for your fictional colleague on your
repository.
You will then engage in code review for the change (acting as a code reviewer) on
-a course mates repository.
-Once complete, you will respond to the pull request on your repository from another team member,.
+a course mate's repository.
+Once complete, you will respond to the pull request on your repository from another team member.
The following diagram depicts the branches that you should have in the repository.
{: .image-with-shadow width="800px"}
@@ -207,13 +207,14 @@ of the pull request you just opened.
### Things to look for in a code review
-Reviewing code effectively takes practise. However, here is some guidance on the
+Reviewing code effectively takes practice. However, here is some guidance on the
kinds of things you should be looking for when reviewing a piece of code.
-Start by understanding what the code _should_ do, by reading the specification/user requriement,
-the pull request description and talking to the developer.
+Start by understanding what the code _should_ do, by reading the specification/user requirements,
+the pull request description and talking to the developer. In this case, understand what SR1.1.1
+means.
-Once you're happy, start reading the code (skip any tests for now). You're
+Once you're happy, start reading the code (skip the test code for now). You're
going to be assessing the code in 4 key areas:
* Is the code readable
@@ -226,7 +227,9 @@ going to be assessing the code in 4 key areas:
Think about do the names of the variables, do they [follow guidelines for good
names?](../15-coding-conventions/index.html#l#naming-conventions)
-Do you understand what conditions in if statements are for?
+Do you understand what conditions in each if statements are for?
+
+Do the function names match the behavior of the function.
#### Is the code a minimal change
@@ -241,29 +244,35 @@ Do functions do just one thing? Have appropriate design
patterns been used (e.g. separating out the model logic from
any view considerations)?
+However, if you finding yourself suggesting a full redesign,
+then this is best done in person. Ideally big design questions
+would be addressed before code is written. If that hasn't happened,
+it is normally better to iterate on an imperfect architecture
+rather than throwing it away and starting again, but this will
+depend on the code in question.
+
#### Is there appropriate and up-to-date documentation
If functionality has changed, has corresponding documentation been
-updated. If new functions have been added, do they have appropriate
-levels of documentation. Does the documentation make sense?
+updated? If new functions have been added, do they have appropriate
+levels of documentation? Does the documentation make sense?
Are there clear and useful comments that explain complex designs
and focus on the "why/because" rather than the "what/how"?
-### Effective comments
+### Effective review comments
-Make sure your comments are specific and actionable.
+Make sure your review comments are specific and actionable.
Try to be as specific as you can, rather than "this code is unclear"
prefer, "I don't understand what values this variable can hold".
Make it clear in the comment if you want something to change as part
-of this PR. Ideally provide an idea (e.g. better variable name).
-
+of this PR. Ideally provide a concrete suggestion (e.g. better variable name).
> ## Exercise: review some code
>
-> Pick someone else in the group and go to the pull request they created.
+> Pick someone else in the group and go to the pull request they created on their repo.
> Review the code, looking for the kinds of problems that we have just discussed.
> There are examples of all the 4 main areas in the pull request,
> so try to make at least one suggestion for each area.
@@ -276,7 +285,7 @@ of this PR. Ideally provide an idea (e.g. better variable name).
>>
>> * Unclear function name `s_dev` - uses an uncommon abbreviation increasing mental load
>> when reading code that calls this function, prefer `standard_deviation`.
->> * Variable `number` not clear what it contains - prefer buiness name like `mean` or `mean_of_data`
+>> * Variable `number` not clear what it contains - prefer business name like `mean` or `mean_of_data`
>>
>> **Is the code minimal**
>>
@@ -286,7 +295,7 @@ of this PR. Ideally provide an idea (e.g. better variable name).
>> **Does the code have a clean structure**
>>
>> * Have the function return the data, rather than having the graph name (a view layer consideration)
->> leak into the model code.
+>> leak into the model code.
>>
>> **Is the documentation up to date and correct**
>>
@@ -308,10 +317,10 @@ As you are going through the code, add to this list with any more tests you thin
of, making sure to add tests for:
* All paths through the code.
-* Making each if statement be evaluated as `True` and `False`.
+* Making each `if` statement be evaluated as `True` and `False`.
* All loops are exercised with empty, single and multi-element sequences.
* Edge cases that you spot.
-* Any code that you're not sure how it behaves under certain circumstances.
+* Any circumstances that you're not sure how certain code would behave.
Once you have built the list, go through the tests in the PR. Make sure
the tests test what you expect (so inspect them closely!). Add a comment
@@ -447,7 +456,7 @@ the behavior of the code, commit).
Make sure you write a clear description of the content and purpose of the change.
This should be provided as the pull request description.
-This should provide the context that reading the code will make more sense.
+This should provide the context needed to read the code.
It is also a good idea to review your code yourself. In doing this you will spot
the more obvious issues with your code, allowing your reviewer to focus on the
@@ -456,26 +465,26 @@ things you cannot spot.
## Empathy in review comments
Code is written by humans (mostly!), and code review is a form of communication. As such
-empathy is really important for effective reviewing.
+empathy is important for effective reviewing.
When reviewing code, it can be sometimes frustrating when code is confusing, particularly
as it will be implemented differently to how you would have done it. However, it is important
as a reviewer to be compassionate to the person whose code you are reviewing. Specifically:
* Identify positives in code as and when you find them (particularly if it is an improvement on
-something you've previously fed back on in a previous review).
+ something you've previously fed back on in a previous review).
* Remember different doesn't mean better - only request changes if the code is wrong or hard to understand.
-* Limit the number of non-critical suggestions to a few - you are aiming for better rather than perfect.
+* Only provide a few non-critical suggestions - you are aiming for better rather than perfect.
* Ask questions to understand why something has been done a certain way rather than assuming you
-know a better way.
+ know a better way.
* If a conversation is taking place on a review and hasn't been resolved by a
-single back-and-forth exchange, then schedule a conversation to discuss instead
-(recording the result on the PR).
+ single back-and-forth exchange, then schedule a conversation to discuss instead
+ (recording the results of the discussion in the PR).
## Designing a review process
-To maximize the benefit of a code review it needs a process that is followed by everyone
-involved, and that everyone believes that process provides value.
+To be effective, code review needs to be a process that is followed by everyone
+developing the code. Everyone should believe that process provides value.
One way to foster this is to design the process as a team. When you're doing this you
should consider:
From 852f99eb7903234ea05d180aba7936547c686dbc Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 16:40:57 +0100
Subject: [PATCH 32/98] Update final exercise to be more related to the process
Tweaked this since we're now exclusively focusing on a tool driven code
review. By thinking about the process it makes it more likely they will
go away and implement it. Further, by identifying problems these can be
discussed in the class .
---
_episodes/41-code-review.md | 24 +++++++-----------------
1 file changed, 7 insertions(+), 17 deletions(-)
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index bde3a764c..b3ce22963 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -513,27 +513,17 @@ where things are getting stuck and work out what you can do to move things along
> ## Exercise: Code Review in Your Own Working Environment
>
-> At the start of this episode we briefly looked at a number of techniques for doing code review,
-> and as an example,
-> went on to see how we can use GitHub Pull Requests to review team member code changes.
-> Finally, we also looked at some best practices for doing code reviews in general.
+> In this episode we have looked at how to use a tool driven code review process
+> using GitHub pull requests. We've also looked at some best practices for doing
+> code reviews in general.
>
> Now think about how you typically develop code,
> and how you might institute code review practices within your own working environment.
-> Write down briefly for your own reference (perhaps using bullet points)
-> some answers to the following questions:
+> Write down a process for a tool assisted code review, answering the questions
+> above.
>
-> - Which 2 or 3 key circumstances would code review be most useful for you and your colleagues?
-> - Referring to the first section of this episode above,
-> which type of code review would be most useful for each circumstance
-> (and would work best within your own working environment)?
-> - Taking one of these circumstances where code review would be most beneficial,
-> how would you organise such a code review, e.g.:
-> - Which aspects of the codebase would be the most useful to cover?
-> - How often would you do them?
-> - How long would the activity take?
-> - Who would ideally be involved?
-> - Any particular practices you would use?
+> Once complete, discuss with the rest of the class what challenges you think
+> you'd face in implementing this process in your own working environment.
{: .challenge}
## Other reading
From 58cabd05c53aba21047656dbe5227506f561699f Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 17:07:14 +0100
Subject: [PATCH 33/98] Remove diagram
It is no longer accurate and I don't feel is necessary any more.
---
_episodes/41-code-review.md | 7 -
fig/exercise-feature-branch.svg | 433 --------------------------------
2 files changed, 440 deletions(-)
delete mode 100644 fig/exercise-feature-branch.svg
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index b3ce22963..632521683 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -172,13 +172,6 @@ repository.
You will then engage in code review for the change (acting as a code reviewer) on
a course mate's repository.
Once complete, you will respond to the pull request on your repository from another team member.
-The following diagram depicts the branches that you should have in the repository.
-
-{: .image-with-shadow width="800px"}
-
-Adapted from Git Tutorial by sillevl (Creative Commons Attribution 4.0 International License)
-
-
### Raising a pull request for your fictional colleague
diff --git a/fig/exercise-feature-branch.svg b/fig/exercise-feature-branch.svg
deleted file mode 100644
index 569ecadd3..000000000
--- a/fig/exercise-feature-branch.svg
+++ /dev/null
@@ -1,433 +0,0 @@
-
-
-
-
-
- image/svg+xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
From cb9ea5e4ea4dd587326aa7a6afc0309ff05bd779 Mon Sep 17 00:00:00 2001
From: Thomas Kiley
Date: Fri, 4 Aug 2023 17:25:16 +0100
Subject: [PATCH 34/98] Add screenshots for responding to a comment and
reacting with an emoji
---
_episodes/41-code-review.md | 4 ++--
fig/github-add-emoji.png | Bin 0 -> 33012 bytes
fig/github-respond-to-review-comment.png | Bin 0 -> 31503 bytes
3 files changed, 2 insertions(+), 2 deletions(-)
create mode 100644 fig/github-add-emoji.png
create mode 100644 fig/github-respond-to-review-comment.png
diff --git a/_episodes/41-code-review.md b/_episodes/41-code-review.md
index 632521683..c2b5ac249 100644
--- a/_episodes/41-code-review.md
+++ b/_episodes/41-code-review.md
@@ -393,11 +393,11 @@ you should make the change to your code on your branch. Once you've made the cha
commit it. It might be helpful to add a thumbs up reaction to the comment, so the reviewer knows
you have addressed it.
-TODO: screenshot of adding a emoji reaction.
+
With some, the comment might not make total sense. You can reply to comments for clarification.
-TODO: screenshot of adding a comment.
+
However, if you disagree, or are really lost on what they are driving it, it will be best to
talk to them in person. Discussions done on code reviews can often feel quite adversarial -
diff --git a/fig/github-add-emoji.png b/fig/github-add-emoji.png
new file mode 100644
index 0000000000000000000000000000000000000000..34a5062e647d37aa6c770d98f0c619d5d003a1c0
GIT binary patch
literal 33012
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 gs=6f!F&Og>BHk@2e1}u3`{vmfSf<
zz>(YD$NxD;Zh+8_(w}r`6Ar^Vb?PVhchZ1`*lV|o3o6vINN)V^MC1t8se3;`GiM)|
zI4pFavpn`09iczI9}5A&27X%ul&w(B)J@QlMNf6)c`q;)^-pF=sYB%XD}>BG0TzT^
z@+j;c;KJY60sZXb1ty!}atOaI{$w4iiv?(){fG*7zVkv)0^S*AzQM1l6>o
z6OciOaRrqQYSIuTMc}t5*lGLBD+CwT`<;?H=a313UTogH;vqu>1I?-&Smd#~FuSMu
zmR(9kEo;Xcgh-O{*N6m?E>&F24JH+}@o;J4KP_?r=JS53_;3g_aCnzSlh>aE5dOlV
zj=6X*8MN!~js_nc9s;DJYKGpjTXZvi|TXVWN
zF#F*OU~TO)Q>eGSJ5t9YFlSY@Wc6UtQT&lr#==V2k*6z=)8h3P}rL@2NRKXggn~5Gt
zAXl$NY?MVEG9nZ;2-P)t6&WfH*S?R%6-v;TpDxjX{M-f@6Z&Zi4DiLDf8Mn{oGA^#
z+obp;;|aUkVC2hSu{P34xqde|TRKtV%+X#^*(UUu>}b7gDmuENkAljW$nJRFP|i^j
z9tsjJUTOg=)M=uakD_e7C%NVg_|lzg%yzO`Pp|e?AkuAcOpRWgbUIMf;HX09ob;!`
zw+XU8aT>!>=m=*vpk8opUS1k6QLEccudV*VeO)=TyTQv~?E-G`LYrO6dYa%YDyQrMH@sXvP`G%q(dINp5O1>A%SGp1z@&Nb$A
zuoWlj-?AILXm*DHsIn96P1=GUp#+!*6u|G
zyg57ETaMkESn*PQDhpXe_E3l1L?&ci)Y;Hpx--!3Q_ah^?Fay^>-6nl9MC}@_4$!U0^JDev0=1cX!GV>y
z17y5Xrfi+7b%?rj*&KNA0a0P_l3<(H`qz+5n@5?~84>SSR$|f>`$6B#LZ3Wer+b?Y
z6=u>wbJADyv0qBSDf5^>wh~YP1}kXqOcjY4Da7O^>=i--zrWFt0V@>^2xCtpFdX9^
zK#)Zjxc50hmEOa5sm-2|kBN(h{p5Ck?o)m?btgZ~_(~y$;(HoEoOnFrX2U2p8rNaN
z(mQTeE<-$?dFEO0Qj=qdMPIK>9$osB)p&_FJt13>R-R_*L{9JyNi?JN5U8=$zI~}`
zZE;!R*MW9b)638{x8fd8^Te$qSMvxR@vU6P3eKWrDt48@L1+?Em%mH-iw=!tFgsNp
z9Z_ZXjBLQTeScurCVIv%oqdXL)VAU_GQvL@;3F6!G*x2igq%1M)xOB+bj)vpzGdlj
zc^OQ(_vebdz4}v$hZFv@SEC^{(e=1@+3kkZveM*K5rqaVE4&sSHT>cQa;=OblUY9Rfew`bG>$NXt*Yx(8;x$h>7gpumj
z#$*F980_w!AN?fWwkvGh@MFqTpv!fJe1&CNOgk
zV`XAc*<^!m%q|M%xjAQ(b4=R^Eq%&ITp~B=8Z8maKK_^PzOQteZFapSjkD#eI&%II
z;1*%%W`qy(iOLd+h&3~v?E!ST8D+nU>z6_33WJi_%PCy<^;XMTm1dSPJM=x-H8tk?
zy)q^%*_H+dvFs`T(S0P2p+#=|HLc-5FHu`E14e-8=jsll#(k`3AK~}dk~PmhJp=@1
z1{hW5d`lhRv1NAQhvu7;A@Gg=pctfl;^nOs-Z3)%zyT6(s47{u(MGDE>7?)!LORx
zLBUTPahS`OCy{5#UA;Ag3-${w>#aP$%9Sn~Jxk3{Y6_iqhUX7w%k#~745oB&ZoFPL
zzpp#5pab!on4ZNIEtXcXBc4Y-z4^1G`r!+e(q|2+^(fzt?6&|q8lxR}cl#9q7MJ_@
zCl*q;G4R;YEGYD%yjE1BsV;T?1Ue6VeH}6Ml!Zc(f28+S-H0oKR{8zSOP%S}BRi4O
ztp}*pIMccd`Ywf|e7wn{i|-WAdZyCoX3R)8#y!uME#q5rSEy>6uJ_gbYiA4~7g7Z!c%_h}D!%`wLByi@jfH6I`xBWcbBJMOo`faD8{zaOm_N
zpZhwRq}-iO9zHSO3yLo|Hl;*CULzo|P>IWykioFAJ=Pb()H}T@BK5l5`*nU)9|^IM
z+SwDA!pIDYiUV5{ZRU|s?+S+%?YMIKgd#+Bb{m#R;kwy{roA{lZ9yhe7%(l_oqr64
z*ACSd{c4x{b-Hrw&tA6V>JTw5@eq1zdXcSJ9ee%c$U^}0G
z=!+t)JBjo|LO|#fm6U$sp}1d=GUdZZc{$JA5u$8--PFoQNTBbPASNaz5$`!R)%?r5
zK6u)6%r}o(n8D3KHmPuHrVA;Ycsz~Axsy^ltLyG@sN6svh0Ep)t5iC}ZUsEY%@FZd
zDh-vbv)VXkSIV;9NV<3%NA1!?CD(E!dWG#!(WTz3e&)%w?u4gCf7Ozum-yk^<6bgX
z-|R4FCG*j6K$cf2akcYR_q$?a$#+EKIr@inBj#5}vc|(>xIRy2xA!fZv$a3N#I11$
zZ!AKLu5zHMkR2JRgnGA56P_RLnfodARvz`blV#eNf1MBzfT6U?3KZFl6$$)vi==cd
z6|ymHcd}7L8&puANU_-cwCoy(LCGf32U8CDzuFN3;eC4
z<2En+T@O}COXk~qRvoK(Tp@My)ui5ZZOwaAf~*ou=)@?{d^lU1Z7}WPiHS>f`k!m5r9von;Z5
zq?Gm1Fq#EE5l7zk-9pSHM-1^JN6kFjSc8WG`pub5b~bd+xdnA41}
z2Iw0}w9&8vCgvwG-vxXxP|j&qSYV5h&Zep9Um~q#U{Il=hq=a%2u;kunaGf9d*4FZr7s*ufN|1zgrn?=AG^n
z%X2%zY8Z|am=`NK742x+Q!8~|0t4Z9z$E=BDa=bmA_UQFbS>35TlIqBG3+noj7}SH
ztz-^QypEF<%?XS(4-
zd?EZQha4s!OdrZxnS)?=vqZx8c-q#nVyTwR*TI)Pw0yB*(7&Z=eMJNGd`as>d{yVZ
z0#Z*rY)A7D56H!~I;+`SrPwkcKkQC#_^)inz2~<0CF9G=*~O_9$;`t<@*S$N^pRqN
zjm{H_#8dLS(ubMhwyRm`L#76|IHN1{9j{L!S7z4Whp7UkC*Gn%co4Gbc3Nt6K0OWG
zQ?IxFuL`mv1*3dXae)SN0X^<;D_qa(0*XirFV0Wqjqtw-Am61A^h~foO~N>6;n%$3
z`a-GMx=<~nZAa4?I3|B!NKF|sJf#~`N%k@haXW=ByY}`~Cs3JUTY3#teS}-+%f?W-
ziR)qAaV!H0en07)SC+51^mYOZ?hz?AHa56PtIMbc{UD;?;p=KlbTkd_yd5w82g9uZ_Fg=SB+SeApu+r4;UmQl&RfS
zzetBZL${J(!uMOM=mzhN_lqKg?<>Y}4E_uG^g8!;v$2R`)Y9YyY6IEH_^?68lc^#-
zzloJA^O_R5i$$=0-3b1DS8j(nievhG-Aa?^u?&>dP50_@Gvuq3<+6>*a#8U^?X5%Z
zX>=C-E4BE`vb6Fr=O963Ag$J;A2USDQl*}C+O9}4I|`@M=?o3`ZB3mI9|a!M
zilB=TQeQp3TV4R*yYE0n00~T2au{@UGr0jw+bBw{C+lU2g}Q0<`!3d7zj$1#M65hd
zMWKJHvb$0{$MxIGjq}D)lK^dEm4l;A{!Cb}w0!&kvf9`(bv|8zfCgoQNhIC&9MVuf
z%5YK1C3Xcw1Pa%sqDm=9bH9a%Ze-4QJVP4fwLM@YA5{|Hb5oS2%vU>;(o^6GP6F&T
zuH||`b@TYJOt`0z>jUx02Dk%(9FD-LvwpCJ8jq`O!RW*QNiU|=OtbptPbsrsh4M{?
zK1EVPI}f(cfj;Q|q^jIbrzPud`KZ7|YDm3S9!%UL
z{0*OH^K2{M3ug?b>{iO3w#q`5XiJk7a|eHfY4fag@T+2cn+tDtKJ9>)tbo8B&`FUt
z&(A;^{~33clR)3f$QRYf#f^pu_c+t#*0ALTixmC^-hmrGv_p-1)Z(wJUUayG;2=rUp
zT0o3Zu2=hNVCex9KJw|@?~)&F*T@Jko2v6y>VuKi9eGkF-Jr#!&P1Cq&
zlnZn{E!3HE8h!6W_HN@JC9<=6?v7FDdjjd5W%pjS-5fgU3`e$pdh`Oa7+7XNpSM>I
zAFqj?%;N}`D^LEQc_KX#UR_xq%oYpm?S&sIN4#9^l5T942eMl&I`yB*^(LYs{H6W|
zpL7jiC4DTO@jG85r6U%*+z~nyc+<$W56ZoR^9TQ@c7ax>W3{zFvdMPKB#@)Oi+Hrd
zm05kdCk&Sk$ocuK(=Q}pbF=Ue?&9h10Lgh6b=;)VzQ-j)^o|;V7
zvJ26>$ocLx12Nupy8o-`0)fGwolp8#|5PrmpH+16<=&0y*Z?PVvET$afh)qH-TBZ#
z@xvX)IR~Lcd}*dtEu2_+++$|CiAH&cTf;LaM?zLKw3HuDC&!EReSVUeE1E5p0t6P0
z6RfR{i%thu155w-H~$N_r02HvGe=qY<(T45sAo*#H!(yc|H$GNn@gI9k|me2jo-iBtr*gnUM)WO403)5=oK3kzkezkdc`*s7;pc;rU$axuT!GWLfJd_X!#3)X9C|>l)5!0D
zK%_yEpbC=u(|^w`6~P|pd@2s>a1ZEpe{-YjHrG`Kvx&MBy=m@+$DI3)%J%#{;H2&7?M!afeApt=dk4aNYg}K=e7+HmHO?Y-&RvMY0(@PRg-}MpX=RK
z&IfK&iG*^+wvr=qc+O>Oz8jUC?8JSs75$}@Qo6X+23()zE%nqieY%n@e$xvv!n~Mg
zPqX*UNEVjg}m0x++kbu6AeN9D0SXgy|IeLjtO3U{-o_^b4CwWVSKKRoVf#wus<9`uWT
zoiC~tI$){YjxTx;Z=-ZM^1ZSQsw5o}(45TnWs)CCxxb*)s0pa2{2aaba5yA9sn
zp72Y5|B`FReeo(UpE&C8`KFyQTtKYCLQ@0284u!`=gBsOUiM2E{rL35@~_GJm-F=+
z-l4uz4Z;?;fxV2~@LOB=7sn?a%u=aULWv`+YWwZ3iQ-OW#Mk;;y#bpl
zl7WH34fa2^Hj79=ag)quoX~$Te`OD>Kc(8~nyEkqNG*ZCF`xYvh8puZ)O&0xUT$|A
z%pNm;k}WK-P!#MFL0)p!%mLlhQQvM8qx=+;m
zMJBzz8=zPeYxBRGxV`Y;1^vwh2&OUMDGA{HL8eCv`hNbc$7antD7lJ18
zNuNPOTC&w?^Q845qHZ*=Re_-3vm%h@V;p_X>Gy_3Y&76=!xGM@4bT_=ZmtFVl$&{?
zP5*ZOWqzYwN#@04yPE|4r&a2LSC_Bnp~#g6-kgVc{!gUjUzjG!r%wlLDA$KN7FNqS)4P7ej0vuNIf{4Z9=}fhgaN
zpfp{;I>`443)eS*ZrXhgKI8Ud_Is<2yPh4qN^?G0>A)zBdRy?rEuUFdtN;X<?%1ha1xI}gY}V)-hA;$f!z)=pMvQEuQ5N6hrIj1_i$95EgXXDxw-#0
z+?tNyZl+hYhhv1H%|S70J#B?5`gFg3)iZ?~KZz{{UX?(5^X80#(Ai@n=&M1Ixotr8
z`J#0@GBPro`AjIZ*Ll?gZ}dezN>o&Iu0j{-3%lh)EVC?o)QMh!SNbkEaOX~#fE;>X!E}9GUHu!U=6IB)*^NGg6Zb3V(a+!vOMQ@w+i#GwY!J9)pk{q|26FW9z
z7C6oR3LIt1JT|YtQGBuXlJc>7((nj8J&e^IjHR~o8_pF9z|`^!c5_6(eyb%Q!VA9G
zn#`9OGGthf%6NCMx2MLxy*+(4pn;U`SvjIG+LpLknV{`?w>1DSJY%z-yNCC=r@K0>
zO)|2(Uc97V5000rbEpZI9lZ|+@~UP32+B`)HT%&A9cOHHyn|2(=45~iosJinV-(2S
zYps@>0DQN99fpGlk1n={_@6En1}S5h-w3~NieVzSUTYHyZGq4I&~d`YwC*Bd2n`&V
z*F{cMjSJv6R`8D6wm5|}x
zI6xd$5>c0Bclx9Bv%S1yG7=co){+pBQ2LRR2E36_fnH1IBe%}6TE|Ctr^0j|a!J!g
z+K02u17P>7Y30!!SNEIfXn$V98fS3ft{w05d0$h8wG)G_t!=Z@@nFo?h}jBctzU$0
zt%(5yWi8edec>cL26>XbBv2G^`JV{hI~dHGhSzoKJjo=u4anEEc|6c)-*0gagO_%oLi|Tr
zp^X#yK`@>5q4#}r0mLh0TTZ0=NO%Z91Q|!*+bKco)iw{<4*ef13KyPVvMB`+M3w@v
zYJbbSVqD1lVJfOumyaLXE>{Hq%VSIvM^hR^+E8PZBZbYJ63>8g%DOdbm)g?nXYj*i
zt(O;D<1`fBM?9D+G)@O|FNZ6cj8@5W+4Bh(_s6BZz4`)%?HDTgxLgaDPq4N2mKjZ&
zzg!NcSP#6vnoVH_ICB!gp)jehrM1XbCnVR;(kQ|Qizbiykz^W2uU^+LWk9(#+@Avg
zf)ds8B=1k#)mNWvxNa5|qm}JJZSHq=Ne38IxRE`ka}`<4i2@x4W0?YX7uyoz;^NZM
z46>OBchM=2=A}V!t6?>pDsa6zsL2+!#R~rH@U<&|_l^CFK%fjT&*kq1)aQlqHw*z7
z(Z>TApQ{;>qWrd1W70MQ^?4=$1@wTIKBoJ0zE&kP{`j!g;WO12G=3Gia!15rMTciV
zxaFwjx(^Azdck`!^elzad0nq+YwUvh_3vt3rYjhE-kLlS3OhAcDco&@Fs2XObzXYo
zrMo6)IN>M|}`g!6uY
zNqeYER4O-WXSEbU{W>2`+xd0i>7+}8LP&|DMELo6>Qhp0Hujwnau@Dj3C>W
z1j4DbhF)+ekhjSwX}5Mc5sL_B10Q96xatGKxZ5kE=X%=Pr#Uag8hP9t-SX$VNE0B!
zde<9y;x&UoIA6CYQ~Mwi2^Tvf4}%iINwWpBE5#4^<$23Uu5RxxZ)oImMd2n`P(6^w
zb3-J<`}2p0$k23Zz`8}Gr@HFGSrKYln6`4Pk`c?Mg<^>c(`C|<0p-T3I|o;$q5P1m
zT7a%Zj9sfnorP*6+OF;PU|c-C`a}}m)?l1D9J{gU@$q%Go4xREwAEaN0267NTAdjj
zQ;ANvD=RBLsDOADLZx!8r=1jQTpC3a_|KWegmiRtCiA4WL-l1p>-tpVE=D~g;j!#y
z;bRF}B_Qo0f&xp9K(UlXteS$XMrM >SPGZiZUF(>z_j
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
DJ9q|q
literal 0
HcmV?d00001
diff --git a/fig/github-respond-to-review-comment.png b/fig/github-respond-to-review-comment.png
new file mode 100644
index 0000000000000000000000000000000000000000..726f3951cabfb5271a66be7fb4579146872d17de
GIT binary patch
literal 31503
zcmeFZWmH^Ev^Gc*2$Grxg1ZHGcTe!(F2TLA;10ndNN{(jq33ko
z_kQ1eGjrFvbLY>jS@WaUS?Bbr+Eu%@Jhk_(6Q=l43LT9I4FLfGT}E1583EyG6Y%?p
z@)UT&Um7Y3T%I^8ONk=<7$w;SZV*jHr>E0e+T1dQ##E=Z
zV(TSW>RhDbar~nM2F})QzYD?=MWO8O*_9jUjep^e1l$BRW`ijLu|z{(U7!IM6nlSN
zKln=@Z}vfFwz#zUdVKhq;UK#39J+7|J5ektIw@f;(Uui`9m9d3CC1-njiAibuo+w2
zq~#`$+5Xo+AJPF&MM$zqo{$=lb}sc_2FOC5F8HGlFurB|1*c%XN>N7LcyEi(aEew*
z#tx?{9qP9ljb%&2&^5r=&xa=I4<7+#Anf=Zw;Ph1RHrojo+dEX1wS&7`lIfjPo4~V
zCNw}pQJg?mM0e^xp$XuVx76^S`d3Y}3jfZCi2naDqj5%fH{GcJ%$r-JLKv7n7VQoQ
zepy3oeF|Je)3g4s*@2h~Zge?bF4t}tbgJ~tQ-ZgR<)v+eh-zwTy1Pp{IE2gh508w9
z6)VNS$v8<=x(4Ose6~l`=KQGJ?0K@`)+)F&3+c;J7yG$*y*GI^>GrB^@v1KQ`4syM
zoU-(4u}_7fu5Lz33W(ficVGTRn-*88R|uHQV|QS-#e2#Nx)W`%qzAhx|7f7o98JV>
zHc6j=FK%_`?B)qIp6b);y#u;IL8ZAo0ELH#CnTs`9WLU$-#d&Z%^+bd8+#bxg|z!E$^Luit!fMV%n)=-wIIJzDyzH&|mWn8j>XEsYS9pef|s>l``^FA(-wh
z#4pz8!0aG7&dbBar$V0bq;rV;ohvOgjke{TXZ?zQh#=AJDU_qD;n0nS>g+?{YCKjt|Pdv6KLj46N_oNTx66U_@++|5a-6pZcgQI=f>zfPFISkVFW3MPUe
zH#E$HpXtuQcYO7|MTmI*@>zYfAnv!X*=##Fyz2QkCDBMxQ}=d=gsPX4xam_d;QrxZ
zUPrUZYq@3U=h1z}txNAhr+uj-kMk6vDEIx-n^=BA-Mg#CsL4)vs~0tvW3I&2ofa!=n4x<
zu$Sabw%gI3A4x+E3p-=Pt(2#x?roj9i^|Jm@S%Ie+POld^m|iLNdRu0cMIyoQnAjG
z+aYKU`ADQ0jd-pRSQ1TVR*YPssH&Py;NxaGjLetR_BdTwF-Edj^3(c;uYo4UVaSdPe8JJ-_$6qDWrz(WQDRZS)TI;ng)<*FO7`{KU4wvtaX;kJ+vIPs>eN);M*l;cE
z;VKD+=X~SxXXT+HqvnxQ|4U)0-z!s0qVdCTCkndzr*|uOV+1jrQ8N#3xVUU5Oy5tM
z40Dnju!~pNT^}vw52-`Wv@Gc@Ug|!1m+b-j)42s2|5>{ewACgqjpZ+=Enc?hazwOC
z@%+0unDj>v@wi5ytQ79XR2`U(kx}mBM@{@m>*?Agq0Ec3)Ln9n-7}jIJaWkGhuN*`
z*4w+|#g9jguAYlLVj0AIHS2}zd>>(1OM&eWZs=HMH`IG>reM9@gTiXGCP1STNWmZ$tz8AV0z7x?uo7L(cHGYK_+GmHFvv7u1ht&EM)q%lg
ziN}#AU*uEJiya2ugG(8o0OE*MmYmhXAFWS+Y{ihxH+$OL+a@{d3Dga(Ml&tjPBdS#
z**cj`9NxA=9+zv#rRu)3w_OIN9Dhuku!pX0ElIX9J`?vlT*hoT7hoE1RY;E%__7hX;FM3-AJ$8tXTTgb<##*5kHJmyt
zgf|N-D?}4+-O*v^*P|K`mtH72t-R(;>At_WK=1X@bn$wKt=C+Ob%;yL^gMjaiQ`i-A`@mP1;friKu)RJRtG731xRWUT*D@igrGp#xE5%
z2naFOYmfGvX3UBUib$g3p|o%S^xPtD{uNsywdn}H-k{z1>#25}%yCH1KDpCwhMppY
zQ%Cb9vC@-g*R_iA0p(F9Dk#gcxN)Cfh|+)J806@oP%Cx7(36^NrH5-z8p|5C|xm(hM`RvMfhnbBSOK6
zyXfrv9RHmb74mUJMQt~$LuB>cGg8S0Yy7ou(MYRhtbz_Wz5Z-zacUA95Zdi&t?vC$
zB1ES>5EgNKg38thZ_}PKE}^vXAC3|C%idSnoMUY_H_t`{-Alnq4el7872CIJ6Wi*;
z&6S@QdXi6NN_!u0+4jc6i(BF??a=@~
z;cD#|K{vMr(idS7{chV!*GjJ_UsYMp9tqIJquhy}gRxKaDc;DZM2Ci^PMS*koY>D6
z$*6QmNm2+ume1D!0wwH)xKMA~7NCZ8ri3i@W-pV+14Dw(2EOX0jbFPro5QUt1c94=mYb<|hRbPr5o=>)$d4>LYzp<`kqWjEr6in~h&lTex=
z%F7gQ=rd}lFLE)xcnn7tB~2mO&}UE#9Ql(ap(Og5Y9YyfM6Z#+F#kBlEi86YnPYd=ZXd04jO^Lpq08G(H6m&)3&_LqI
zCsMqBbC@=gy3V>7ca$PCAKo<_D>-xt`B^$Icnn!1=uR2uS6XFGjH51$yF*&4Z^hZ+
z$9q!9nr>$|*pq_3%|$&MmtbFL*A~ThnLx7%G0mW{#2&-uK-rsOq_CpM8H=%CGu&az
zjCL(wT6wJ6T)%FG8r9IIa$4RGF1GSsCJRul^+W$4n_`B4pNH*C*=*-{K-mkoF%twe
zIoG=4zAr*=`Laor>wy=vn*jdO5ET&!P6iX|ya)UNQ
zM9KeXHT%!&*RQ3wHa47hXI@brPAL?|ePy&|6Aj4ii@x4jI_{04s`YhNL|dd(I`8Nd
z)4&$}B=rSZE~#8N2q{8P%v{7E`!^F7r*|u%#QP!eXU#i`#Hae=zXS%PGOLsVf7uA!
zr;dFZrg|%<@S);lWQ&Pg%P!>y7>XoG9K7`_e`p0(`KmOlVTa%>E&!@I;Ru+7eI6#b
zGHY6|m}nxfj>I6~zdrVv+AMcjZgJ;OnfYn-SvFra+K4BT)T9d^B?JRo>2rzJlOYp?
z=N41oq$d`sPsp;i3y3SH5iRJ?)G8VyzVi>P0V
zOMe(*U^so0Od`qPCS%qM^@{HV}zg4tZLUuvA}yy0mwy
z7~EkK653|>yHu%_JZ5kDARq}gel?G*=d;^mnkI0q)Q8#P?CNqOC5W7q*AE*l-&3Taqp=!R}Wc_x$c*
z_u7Yg?q|gXW=*m!b*746vl#UR5mC|shn~2UpOf=cWTJj?38MLq$Dy(~KQtAkh?LLE
zNKz!why67+{->eQ;9KFeMl7jrj)?BK)oPF9wue2tJX<~Qx+lmifkR(%I~u^Tg1P-~
zrXbz|$bO$9F=j;dCASqa1p|!7%;QLQGv*)hEobN7zVKDzcDR^>21OW*>3QbAo{7)M
z%PXj}nbocTAxrk4FQHfS=S84t*to7zSGj(~q_Rj(S@TPNZAs-1zU6O(3z#eP<(_WS
zy?c|@a;fCsWM2GiN>Cs4c9H1ffQE8aR5Z1s;^k^tP}hoc1sNE-bhhl9T*NbELwnUh
zLdmu~rdb5(!7!Wcn3m1AenGozxoLt|E+qX9VMyasP3QP_^&&{=EyGe(p(7gjixS3{
zfrihPB)6jiqq{T^KefIj6vTPxE=JZ-W9GN}{9b|2LU}ZYY9J2#4}W9?UF6QRy7e_V
zHyu8hHAnE_`DZOVqI7oSW;c)#@mHgT6B4ETw;I*Tqc4Sy1k8+f%NA=T&e|7hd-{LP
z*Ij3AFl#gq_LscBTm>b{TQ!(y_3ao`$nUI_NEPDg2=1J88^+Xm)b)5U>1lBoPc_yv
zyZBsm3dTJ2#rBcS@f2BJ4Jxdgh&$bN9V2u2xG6QL8!$f_xW{ZU7JeZ+IbG57X&SJF
zZGsgz?!D4D6}UY1nCmt{8?ji!BvWw&VTN6Flc#D7A+gOWgInViiJQv^IlCLhY<5m$
z0xlVvfdv~;$Q!H77~m%5qzuUYW8V$2fJ+;RmH&cu9c^`FE@=z1Xk#(d|LMU#U;?mw
z6hD3X-C~=(OPrUvS6d{I#5qyLwcsMY6&$5E)cI_~4H<)s0BP>_aOJqeO~jq5#t-@o
z8M9cRa~?6*5irEAl3ze!NdO>6kdw`DM6ag
z%;(Qq{w^V*UinI>vD*#Z>?z9LD6?eN;tnKk+@2tUqQWTKi$^bomdp251h~Stl$qyz
z^(*7{YeH;M!RL=%(K_5|#neCPEl-HQ9T_mWY&%Nuf`+$hPGL2!pIY^^*Ea*=N`+KT`woD`C4xq`qJv%
zZd152+;-A+-v@iRXy*Bs)D@x6U%xp*H1
zGdus;UT=GzwDPc6LDmQ(PZhivtAN~qYu_47D;R+l19FJIAhAhZ@m!8RX>_ak6#bt5
zo1tVl4X^tp+L;4_I=|1K9NdAUAS#)s?5=cIDA8OSxwt&PUL91=9b?CAP6Vr}x0GLX
zAJqJ2siX{fMbed0vprRcHfG*=s_#5zMPB%fgr8d=E>{qU)420DukhZlx=IF3F}kR
zEwNpA`Ewxqsdd>bz%)j|PhfOaNdgPd<0D|`VH-RGre5H{KMn?b2iS7h1xce6vczr8iSyr;{B
zFA&7ISSV%6^f((Ru!a08o2G`{hctx~UiLC#F(G6+|NEjlY|~t+8+z`1TI#Epbv3+?WYUtX7gh%#7Og?%Jt9J
z-$*!i&@3=8p1oc7RayaK@zM9iyF&&H3XZ;3^RUy2Tma_g)vJV9=A?Dyz;)XF1&&EX
z5z5Dxw^WDypC_U5EW*##U^xIJd64l|W*I^+0Ksg_)rRNsK<=g(S#n(}2A@^6@4x6ccz;dc2LimDq
z7!_2jPIjR|HxcW&$jqae4k3CBLz>d^gHNK3)wo0SL;9Sj9SfLC?p}(Ha&9q3ov|j~
z+TeYByJxN`4+v_TWL`!V3*t+}Qp5R75w&%~?xhx&$zK(^V*_ksnNLM^B~50g%Pi~X
zLM)2X6XU`_QDsCbg}P7j3QZ57?xT%u3JPR17G{}Xsi>XbIny=FkdvD}+t#_JTRrdO
z30m_%jR`8j3z6LH*fnxoAeHBL}!XpD?W5;~@Sn_3
zQ14q|x=(@;@K-b>0aipz6#O2O!d@WcF!6->iQ&D|4L4fkTA4W9qb&Pz)s2@oO{J~i
z;CSAAc@Uwz%O=YDNTnCcMM61w`Ro*{8m$1S6qAIXL`GA|n!F_!vP@^o^r_JmwKX1G
z{71;n(Nnj09~w%v_P5u#p)0nlQ-3XWKOTf
z6;8ESBl*NSl~LBz%BJIYb2)C&%#$o^cH=jw@9ka5$NzXCo!>}&$JaA=gLcaR9#MF`
zzh@KivHo~mW|aRXqDwt-I!|0Z9jj6w?GMS}{Vu5F&Srgg(v*e7O6S|{4FWCRWo_A;
z{b5Gc^`&0@EMSxEKN#nw-HYjJBOPOc-L*nOcq#*FPae_jCq&0Uak3T!bHtyJq3WCz1c^XEN?o)G?0m&DyyaY
zwD)^f^Oz5QIj_&WW1_uPCU{5I8yzEB$=;6t#+EG0zoI|f_;!R~F3zw|A>(eBog^4?
zxv8Kb5mI`g{b9}A{Te+0lcoC8u}L7ew^^jeMhIp20WNG$(YqZC%V=4fV`SX
zB1z*SGwnkBp4eeiWj6~FT_mD7``4aWtyJp|*3O(KI;B--jm^%zaG%^5D{zP4s#fOY?ZCrNQz#<0HAVB!=ig|AgUY^)h*d;`EAZZ;!xQ
z>%5FeMrmsMWwqS|&KI$x&!g!AvlnPZcmT-zJ>IjK&=qQT7N~QR=fS+8-;3vkM|~{m
zD~sH-;`-yMghUVOX%gN$Pd10a7w3ZaW~-~}OG56q>&^<^&;`B1Yugqt<@T|=`umFn
zywdwNCpwGOqtHh^%w56#08U#j>tB#v+XeoI`%zoLh2oKi#t8d`mR?v
zN{(j(TB0oPMbnTU+h_G2ty{py9;deL=BM4ZcWp4c3QQlNM%c5ocFo9{Narx}{uUm)
znR?i)us`~xF;ZK!umuK;)=5BlH`G7tf@17J$l-RFmuC*U^~Xb6bAKDt9C|R>K(*)YnWT_7v_r(eGPlue`Yq29SB7n|cfU7mEsl
zo)6_Sm_ldwdaVl=;8NQ92a7-YwH<|+KoUu)u~xv5=QUr&_-twPB}#K(bhd}Lt`G8m
zM9R4;5YS%OQp{CovgMj4wO`-w6nB!hHac&OcfEh*9ZClAl7t0h29sxi+87;HtJ}W!
zwqNfdGYkIOd~oUN5`5elX~%$V{2`x_?`nnweMF&D%U_%MUOSxbcv=juIk#D9(r)*|
z)0QF+mmLI@6P2{|*DEilw`O_EA=Ld@C0seHd4jD^V_ROVcr{QmK-Z(r`^X*~I;)cV
zmohOHdGp5-`!k3`Ty*(%a%GO|b|&}2mXFzej*1KKFYk=Dx;uru+x=W{Q7H4?Q26SM
zF+yTvgG+VOd-vt$c<*A96N5%o`3eR##-&>^rDy_5215POUk++Gbk}Gdx+48YYKxq_
zVLK$(Qjo9OZurN1fXfJ3t?g*#w81fk_i1)CCT!nhOo-(qfis5xYSwrN+}%f;CAgvl
z&r$9L-(91LDk<6j&9@ECAJ6puNIez17;kk9Ce>kaKF*zy5qUliy(x?@;&Y-ib3j
zrKg;P7y-r_931R^KNmRs`#1k1D>eM_HDVGN>j*$XKq%FL^sVY{yA%$PxXW`!mHe9-
zj9vBnHx>HdOdL{vrKfuf1tP$zk9&0?OYCC21G;>%jTPO+Z8ByKEzXh60{h~~#nx_T<5d3E^(
z)h^IaPKONx$t=i6^sY~G$ZKOg;N{?ryIPbeeG)gNzoW~!~Y
zD^L|*Ip5}9MbqMGh2snUKAXgn2k<#6WuR(+kDN^Z5`^p>mt~N}Xp2<+ciSZY@lSEyna)~oevbL%R6=^J*u=-cJ(lti%(p>q)
z;3?E%<%Wmiw;Ur?(rvs{nsSLqi^zda)0}WRF}?dBnw#P(@y{`YZ{pb38}v&lq%V}&
zteNDHXhx*X{p;*Btz?NrPR>E3NN>~R-2ft>DJLbV@~!!@EY2TmPGT0+H~T&SfyfU7
z*BlKQIzOxLo@A%q-2#GEOcpiEDE&!Etgb)O;9D?NCz#LTD~>|e4?4?~Di!PbOzx5&
zJB2`KXfBVFF>7&eM!u5Q-E1*-LGbZz1>g#`N(WR?GR@T=m
zv%lS)QHS73bLD+@8UI=b2=PP4r6~RRpB8Mjxn`LiBIpqV~kmH7R3vV
z&F>PYE!u?1$Fq1XI%|l9%Oj~^Er$xmM(!WKqSed6HOWbs`VtL=*2JpbZ->gD?3bbu
zRe5o?4dA44aFvWCRh*oxdS0f->%FSbw|San%x10)CS_fKtqoNGk&7ZGgzaOIWSO^9
z&EO7y>)eiX?Jpg-&y*Xa0o7OlhM5&?L5!1r((p?$k4i#AiKc3VZ8XJzzyPOHnZZ!R
z+gw;n@`1q(=?e}cm6VoBpRqRh&Tw#F7_scLx(c5malwMSy1DD9rIn
zlNW(924!@jVlWCJ|N3jVv1l1*WViZTDS$}i9u$lYFBXUu7ONPq{98VOWA3t-Ld`^Ycw`KmIs5kJIih;U+k}`cBc?1}b_v-l5Fi%u8uuF5Xb9sPv
zG__fP0gDr4EbQ1qD4{8fmWv
zbf38_+I4KXCO=Y3Fdc1oXX>j*3oIDVnqUVO3WtGRw?a`-b?tJu>ql$I-Agib1r{dv
ziJ1G(V>;nuOmu;jz8h2XFO;TirMr)wNm((9n#Bq=15!%UZ3fY$;^wBC|*I
zMvcI`M$eSo1O2MO8kd_Q@OgB2`WaSsD>wbYbR@au=Cfx!)2opjdqXz3FX<|ba}Ub9
zILP_sz|m{FScR-hd350>lhK0PZg}nI|MPRr(?A+lC7OZt!cps$y0N#QY)y6>t6+eN
z`3;~qcCTMgUft+-{!%+ZOPOzqCt+nk8z8^#O9fHT#D!7Gm>B8k5u7(^GKkig{hoUX
z@b=e}%13W1-GD_j;G2WbS
zx;4Q8x-((rIkdR&H#Sl3zJ}N61QNhI^Tz!Az_qvv!XV=@-+HUtRsgH468hdkH=tt5
zOx0x6qgC_MuZxz`=63l*_>BMxe7PinCCF&6!16f2h5Y=g`C_;aOS>KxN_
z1p}n6$=C-I$6&~Sd#AYo#4fvI5tj0`1?eGJ{9wVO-;*F4ErrjSJQhZ3yzIx)17nl<
z_r)hPdBz~zZwqS=8P7uQG2TDYUUqiTRuT5Vq3Dw;SSUGPNwK@|sP^n#pk{=;bUeah{5bjknPK-k$PdpiL|NmgSargtCbZ#;3&!QuM>1|g%btf3Bs?MvuX!4tEzU{pL=HAX3_A)
zW!eFG-`;L#V()q_=@hB{uhxR4f0XG%ll#)Snv|&lNYEXCcQ^~P)znpE{kRqLHlt?$3a%|{jvq6~d?|8qMD1(^bp
z5QY5Ts{Q(JT5VuZKpowGt#J`)g|HH?gp#V*Y|0RQJ&B5Bze{&bY7e}?&bnmn>U;R2
z%aHAo5*t0d5D(3p(o+m&lZ)}UJ%qDWG^p)KjXC^z4p9+%-)i`79Z*h^GfyW0?-5