diff --git a/common-content/en/module/js1/assembly/index.md b/common-content/en/module/js1/assembly/index.md
deleted file mode 100644
index f5cea6e2c..000000000
--- a/common-content/en/module/js1/assembly/index.md
+++ /dev/null
@@ -1,57 +0,0 @@
-+++
-title = '🏗️ Assembling the parts'
-
-time = 20
-facilitation = false
-emoji= '🧩'
-hide_from_overview = true
-[objectives]
- 1='Explain how different concepts are combined to solve a goal'
-[build]
- render = 'never'
- list = 'local'
- publishResources = false
-
-+++
-
-Earlier we defined a sub-goal to find a value for the hours from the `time` input. We've found that `Number(time.slice(0,2))` is an expression that evaluates to the hours from `time`. So we can write an `if` statement using this expression:
-
-```js
-if (Number(time.slice(0, 2)) > 12) {
-}
-```
-
-If the time is `"23:00"` then the expression `Number(time.slice(0, 2)) > 12` will evaluate to `true` and the body of the `if` statement will be executed.
-
-This `if` statement is implementing the following part of the diagram from earlier:
-
-```mermaid
-
-flowchart TD
-
-A{Check: Are the hours greater than 12?}
-
-```
-
-Now we can format the string using our approach from earlier:
-we’ll need to append `"pm"` to the string expression and subtract 12 from the hours. So we get the following:
-
-```js
-if (Number(time.slice(0, 2)) > 12) {
- return `${time.slice(0, 2) - 12}:00 pm`;
-}
-```
-
-The `return` statement above implements the following steps we set out earlier:
-
-```mermaid
-
-flowchart LR
-
-D[Step 4: subtract 12 from the hours]
-D --> E[Step 5: add 'pm' to the rest of the time]
-E --> F[Step 6: return the new time]
-
-```
-
-Now we can **re-run** our assertions from earlier to check our function behaves as target.
diff --git a/common-content/en/module/js1/assertions/index.md b/common-content/en/module/js1/assertions/index.md
index 8c0bd8670..0561fc9e0 100644
--- a/common-content/en/module/js1/assertions/index.md
+++ b/common-content/en/module/js1/assertions/index.md
@@ -25,7 +25,7 @@ We now have 2 new concepts: **booleans** and **comparisons**. From these concept
> 🔑 An assertion is a _check_ that our code behaves in a particular way: this check can either succeed or fail.
-So far we've used the log function `console.log`. We can write assertions using another function: [`console.assert`](https://developer.mozilla.org/en-US/docs/Web/API/console/assert). The documentation says that `console.assert` writes an error message to the console if the assertion is false. If the assertion is true, nothing happens. As `finalCharacter === "?"` evaluates to true, no message will be written to the console.
+So far we've used the log function `console.log`. We can write assertions using another function: [`console.assert`](https://developer.mozilla.org/en-US/docs/Web/API/console/assert). The documentation says that `console.assert` writes an error message to the console if the assertion is false. If the assertion is true, nothing happens. As `10 + 32 === 42` evaluates to true, no message will be written to the console.
```js
const calculation = 10 + 32;
@@ -47,12 +47,13 @@ const result = 42;
console.assert(calculation === result);
```
-Update the final character in the `sentence` variable string to make the assertion fail. Check the output you get in the console.
+Change the value assigned to the `result` variable to make the assertion fail. Check the output you get in the console.
+
+👉🏿 [Keep Going](#predict-explain-check-2)
{{}}
{{}}
-{{}}
Let's look at an example using `formatAs12HourClock`:
```js
@@ -62,8 +63,6 @@ console.assert(formatAs12HourClock("08:00") === "08:00 am");
Predict and explain if the assertion will succeed or fail. Pay particular attention to the return value of `formatAs12HourClock`.
-{{}}
-
{{}}
{{}}
@@ -84,7 +83,7 @@ console.assert(
Let's break down these arguments to make sense of what's going on:
1. **first argument** - `formatAs12HourClock("08:00") === "08:00 am"` - the condition we're checking
-2. **second argument** - `current output: ${formatAs12HourClock("08:00")}, target output: 08:00 am` - a message string that will be logged to the console if the condition is false.
+2. **second argument** - `` `current output: ${formatAs12HourClock("08:00")}, target output: 08:00 am` `` - a message string that will be logged to the console if the condition is false.
#### 🧹 Refactor
@@ -109,13 +108,13 @@ Assertion failed: current output: undefined, target output: 08:00 am
## 🧰 Implementing the functionality
-On line 4, the function is being passed a single argument `"08:00"`. But our function ignores it - it doesn't declare any parameters. We can parameterise the function and label the input as `time`:
+On line 3, the function is being passed a single argument `"08:00"`. But our function ignores it: it doesn't declare any parameters. We can parameterise the function and label the input as `time`:
```js
function formatAs12HourClock(time) {}
```
-According to our assertion, when we call our function with an input of `"08:00"` we need to create an output of `"08:00 am"`. We can add `"am"` to the `time` to get the target output. We can update our function with a template literal, set the return value and then _re-run_ our code including our assertion to check the function is returning the correct value.
+According to our assertion, when we call our function with an input of `"08:00"` we need to create an output of `"08:00 am"`. If we add `"am"` to the `time`, we'll get the target output. We can update our function with a template literal, set the return value and then _re-run_ our code including our assertion to check the function is returning the correct value.
📓 We can and should continually check our assertions to see if our function’s current output meets our target output.
@@ -140,49 +139,21 @@ Create a javascript file on your local machine and execute the code above. Doubl
## 💼 Checking different cases
-So far we’ve only created assertions that check the function’s behaviour for times _after midnight and before midday_. In these cases, there is a pattern: take the current time and add `"am"` to the end.
+So far we’ve only created assertions that check the function’s behaviour for times _between midnight and midday_. In these cases, there is a pattern: take the current time and add `" am"` to the end.
-Now we need to assert that the function behaves correctly when the time is later than midday. Let’s create an assertion for our function when passed an input of `"23:00"`:
+But this isn't the pattern we need to follow for _all_ times. To make sure our function works for all times, we need to write more assertions.
-```js {linenos=table,linenostart=1}
-function formatAs12HourClock(time) {
- return `${time} am`;
-}
+We need to assert that the function behaves correctly when the time is later than midday.
-const currentOutput = formatAs12HourClock("08:00");
-const targetOutput = "08:00 am";
-console.assert(
- currentOutput === targetOutput,
- `current output: ${currentOutput}, target output: ${targetOutput}`
-);
+Before we think about any code, we should think about our problem. Separating _problem_ and _code_ lets us focus better. First we can focus on the data. Then we can focus on the code.
-const currentOutput = formatAs12HourClock("23:00");
-const targetOutput = "11:00 pm";
-console.assert(
- currentOutput === targetOutput,
- `current output: ${currentOutput}, target output: ${targetOutput}`
-);
-```
+First, let's think of an example time in 24 hour clock - we'll pick `23:00`.
-## 🔄 Reusing variable names
+Next, let's work out what we expect our example time to be in 12 hour clock: `11:00 pm`.
-When we run the file with Node, we get an error in the console:
+Now that we've thought about the problem, we can write the code. Let's create an assertion for our function when passed an input of `"23:00"`:
-```bash
-SyntaxError: Identifier 'currentOutput' has already been declared
-```
-
-In this case, identifier means name of a variable, so in a variable declaration like
-
-```js
-const currentOutput = formatAs12HourClock("08:23");
-```
-
-`currentOutput` is the **identifier**.
-
-When an error is thrown, it means the execution of the program stops at this point and an error report is sent to the user. However, we want to do multiple assertions.
-
-```js title="problem.js"
+```js {linenos=table,linenostart=1}
function formatAs12HourClock(time) {
return `${time} am`;
}
@@ -194,23 +165,12 @@ console.assert(
`current output: ${currentOutput}, target output: ${targetOutput}`
);
-// ❌ this assertion now fails
-const currentOutput2 = formatAs12HourClock("23:00");
-const targetOutput2 = "11:00 pm";
+const currentOutput = formatAs12HourClock("23:00");
+const targetOutput = "11:00 pm";
console.assert(
- currentOutput2 === targetOutput2,
- `current output: ${currentOutput2}, target output: ${targetOutput2}`
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
);
```
-Now the second assertion fails with the following message:
-
-```bash
-Assertion failed: current output: 23:00 am, target output: 11:00 pm
-```
-
-{{}}
-
-✏️ Write another assertion that checks `formatAs12HourClock` returns the target output when passed another _time input in the afternoon._
-
-{{}}
+Save this code to a file. Before you run it in Node, write down what you think will happen. Then run it with Node - compare what you saw with what you predicted.
diff --git a/common-content/en/module/js1/clocks/index.md b/common-content/en/module/js1/clocks/index.md
index 1bf236b46..92abb0375 100644
--- a/common-content/en/module/js1/clocks/index.md
+++ b/common-content/en/module/js1/clocks/index.md
@@ -35,9 +35,9 @@ We use the notation "HH:MM". HH is our stand-in for the hours value. MM is our s
Let's pose a problem: given any time in 24 hour clock, we want to format it as a 12 hour clock time. To achieve this goal, we're going to implement a function `formatAs12HourClock`.
-_Given_ a time in 24 hour clock
-_When_ we call `formatAs12HourClock`
-_Then_ we get back a string representing the same time in 12 hour clock
+_Given_ a time in 24 hour clock
+_When_ we call `formatAs12HourClock`
+_Then_ we get back a string representing the same time in 12 hour clock.
### 🧪 Our tests:
diff --git a/common-content/en/module/js1/comparison/index.md b/common-content/en/module/js1/comparison/index.md
index 1a0f1e7b4..15b891f8e 100644
--- a/common-content/en/module/js1/comparison/index.md
+++ b/common-content/en/module/js1/comparison/index.md
@@ -78,7 +78,7 @@ b) the 🎯 target output?
We have learned how to log values to the console. We can also **compare** two values. We check that a function produces some target output with a comparison.
-We compare the current output of `formatAs12HourClock("08:00")` with the target output of `"08:00 am"` and ask: **are these two values the same?**. We use a comparison operator to compare two expressions and check if they evaluate to the same value. We use the strict equality operator `===` to check if two values are the same.
+We compare the current output of `formatAs12HourClock("08:00")` with the target output of `"08:00 am"` and ask: **are these two values the same?** We use a comparison operator to compare two expressions and check if they evaluate to the same value. We use the strict equality operator `===` to check if two values are the same.
### Left equals Right
diff --git a/common-content/en/module/js1/identifying-missing-tests/index.md b/common-content/en/module/js1/identifying-missing-tests/index.md
new file mode 100644
index 000000000..244617d56
--- /dev/null
+++ b/common-content/en/module/js1/identifying-missing-tests/index.md
@@ -0,0 +1,68 @@
++++
+title = '🔬 Identifying missing tests'
+
+time = 30
+facilitation = false
+emoji= '🔬'
+[objectives]
+1='Define groups of input'
+2='Define edge cases'
+3='Identify groups of input for a function'
+4='Identify edge cases for a function'
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
+
++++
+
+We started off writing one test for our code - checking that it correctly handled the input `08:00`. We wrote an implementation that passed all our (1) tests!
+
+Then we realised there was a bug - it didn't handle times after midday correctly. So we wrote another test - for the input `23:00`. We saw our implementation failed that test. And we fixed it. And we had an implementation that passed all our (2) tests!
+
+> When will we be happy that our implementation works for all possible inputs? When do we have enough tests?
+
+### Groups of input
+
+One way to approach this is to think about what _groups_ of input our problem may have.
+
+We've already identified two examples of groups of input to the problem of converting 24 hour clocks to 12 hour clocks: Times before midday and times after midday.
+
+One way to find extra cases to consider (and extra tests to write) is to try to think of different groups of input.
+
+For example, some times are exactly on the hour (end in `:00`) and other times have a non-zero number of minutes.
+
+{{}}
+Set a timer for 5 minutes. Write down as many groups of input to this problem as you can. Write an example assertion for each one.
+
+If you find any bugs in the implementation, go fix them!
+{{}}
+
+### Edge cases
+
+Another way to consider this question is to think about what _edge cases_ there are in the problem.
+
+{{}}
+An edge case is an unusual value which may need special treatment.
+
+Some examples are: the minimum value, the maximum value, and the boundary between two groups of input.
+{{}}
+
+Some example edge cases for this problem are:
+`00:00`
+: The minimum time, which is `12:00 am` in 12 hour clock.
+ This is also the only hour that is _bigger_ in 12 hour clock than 24 hour clock.
+
+`24:00`
+: The maximum time.
+
+`12:00`
+: Where time changes from am to pm. The edge between morning times and afternoon times.
+
+Often these edge cases are where bugs happen.
+
+{{}}
+Set a timer for 5 minutes. Write down as many edge cases of input to this problem as you can. Write an example assertion for each one.
+
+If you find any bugs in the implementation, go fix them!
+{{}}
diff --git a/common-content/en/module/js1/interpreting-errors/index.md b/common-content/en/module/js1/interpreting-errors/index.md
new file mode 100644
index 000000000..747b18b75
--- /dev/null
+++ b/common-content/en/module/js1/interpreting-errors/index.md
@@ -0,0 +1,101 @@
++++
+title = '🔎 Interpreting errors'
+
+time = 20
+facilitation = false
+emoji= '🔎'
+[objectives]
+1='Interpret an error trace to identify which line in which file caused the error'
+2="Identify an error message from an error trace"
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
+
++++
+
+## An error is thrown
+
+When we run the file with Node, we get an error in the console:
+
+```console
+% node clock-example.js
+/Users/dwh/CYF/clock-example.js:12
+const currentOutput = formatAs12HourClock("23:00");
+ ^
+
+SyntaxError: Identifier 'currentOutput' has already been declared
+ at wrapSafe (node:internal/modules/cjs/loader:1383:18)
+ at Module._compile (node:internal/modules/cjs/loader:1412:20)
+ at Module._extensions..js (node:internal/modules/cjs/loader:1551:10)
+ at Module.load (node:internal/modules/cjs/loader:1282:32)
+ at Module._load (node:internal/modules/cjs/loader:1098:12)
+ at TracingChannel.traceSync (node:diagnostics_channel:315:14)
+ at wrapModuleLoad (node:internal/modules/cjs/loader:215:24)
+ at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:158:5)
+ at node:internal/main/run_main_module:30:49
+
+Node.js v22.4.1
+```
+
+When an error is thrown, the program stops and an error report is sent to the user.
+
+As programmers, we will see a lot of errors. It's useful for us to be able to read them.
+
+### Interpreting the output
+
+Each line of output here tells us something useful.
+
+The first line is:
+
+```
+/Users/dwh/CYF/clock-example.js:12
+```
+
+Your output was probably different. But it will have the same parts. Some text, then a colon (`:`), then a number.
+
+{{}}
+
+Work out what the parts of this line mean.
+
+Why are they different on my computer than yours?
+
+How can we use both pieces of information?
+
+{{}}
+
+Often, looking at one line of a file is enough to understand what's wrong. So the message also shows us a copy of the line that caused the problem:
+
+```
+const currentOutput = formatAs12HourClock("23:00");
+```
+
+Then the output tells us the error message:
+
+```
+SyntaxError: Identifier 'currentOutput' has already been declared
+```
+
+We may not know what this means yet, but it's something we can learn about.
+
+{{}}
+Write down three ways you could find out what this means.
+{{}}
+
+Each line starting with "at" is showing us a "Stack trace". We'll skip over this for now. In the future we'll see how it can be useful to us.
+
+Finally, we have this line:
+
+```
+Node.js v22.4.1
+```
+
+{{}}
+
+What does this line mean?
+
+Why might it be useful to know this information?
+
+Add your answer to your spaced repetition calendar. Your understanding of this will grow over time. Answer the question again in the future, and compare it to your previous answer.
+
+{{}}
diff --git a/common-content/en/module/js1/interpreting-this-error/index.md b/common-content/en/module/js1/interpreting-this-error/index.md
new file mode 100644
index 000000000..2118439f5
--- /dev/null
+++ b/common-content/en/module/js1/interpreting-this-error/index.md
@@ -0,0 +1,101 @@
++++
+title = '🧠 Interpreting this error'
+
+time = 20
+facilitation = false
+emoji= '🧠'
+[objectives]
+1='Interpret an error message'
+2='Break down an error message and look up unfamiliar parts'
+3='Rephrase an error message'
+
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
+
++++
+
+We saw this error - let's try to understand it:
+
+```
+SyntaxError: Identifier 'currentOutput' has already been declared
+```
+
+### Knowing what we changed
+
+It can be useful to remember when our code last worked, and what we changed since then.
+
+{{}}
+Source control can help here.
+
+If you commit your code every time you make something work, you can use git to easily see what changed since your last commit.
+{{}}
+
+When we just had the first 10 lines of code here, everything worked. When we added the rest, we got this error:
+
+```js {linenos=table,linenostart=1,hl_lines=["12-17"]}
+function formatAs12HourClock(time) {
+ return `${time} am`;
+}
+
+const currentOutput = formatAs12HourClock("08:00");
+const targetOutput = "08:00 am";
+console.assert(
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
+);
+
+const currentOutput = formatAs12HourClock("23:00");
+const targetOutput = "11:00 pm";
+console.assert(
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
+);
+```
+
+{{}}
+
+Run your code very often.
+
+If we changed one thing since our code last worked, we know what change is the problem. If we have written 100 lines of code since we last saw it work, we have 100 possible problems.
+
+{{}}
+
+### Interpreting the error message
+
+The error message tries to tell us useful information:
+
+```
+SyntaxError: Identifier 'currentOutput' has already been declared
+```
+
+When we get an error, we should make sure we understand all of the words in the error message. If we don't, we should look them up or ask someone.
+
+{{}}
+
+For each word in this error message, write down what it means.
+
+If you don't know a word, look it up.
+
+Make sure you _understand_ each word. Make sure you could explain the word to someone _without reading the answer to them_.
+
+{{}}
+
+
+
+
+Expand for example definitions - only expand this after you have written yours down. Compare your answers with these.
+
+
+* **SyntaxError** - If we Google "JavaScript SyntaxError", [MDN tells us](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError) this is "an error when trying to interpret syntactically invalid code". So - we wrote some code which isn't allowed.
+* **Identifier** - If we Google "JavaScript Identifier", [MDN tells us](https://developer.mozilla.org/en-US/docs/Glossary/Identifier): this is "a sequence of characters in the code that identifies a variable, function, or property". On line 12, the identifier is the variable name: `currentOutput`.
+* **currentOutput** - This is the variable name we used in our code. This is the **identifier** that the error is about.
+* **has**, **already**, and **been** are all standard English words with no special meaning.
+* **declared** - We learnt about this already in this course - a **declaration** is where we make a new name (e.g. a new variable) in JavaScript.
+
+Reading that back, we can rephrase this error message:
+
+We wrote some code which isn't allowed. We tried to declare a new variable named `currentOutput`. But we had already declared something named `currentOutput`.
+
+
diff --git a/common-content/en/module/js1/refactoring-repetition/index.md b/common-content/en/module/js1/refactoring-repetition/index.md
new file mode 100644
index 000000000..2affa2a4d
--- /dev/null
+++ b/common-content/en/module/js1/refactoring-repetition/index.md
@@ -0,0 +1,97 @@
++++
+title = '🧹 Refactoring repetition'
+
+time = 30
+facilitation = false
+emoji= '🧹'
+[objectives]
+1='Refactor code to remove duplication'
+2='Explain why duplicated code can cause problems'
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
+
++++
+
+Let's look at our code, which passes all of the tests we've written:
+
+```js {linenos=table,linenostart=1,hl_lines=["2-3"]}
+function formatAs12HourClock(time) {
+ if (Number(time.slice(0, 2)) > 12) {
+ return `${Number(time.slice(0, 2)) - 12}:00 pm`;
+ }
+ return `${time} am`;
+}
+
+const currentOutput = formatAs12HourClock("08:00");
+const targetOutput = "08:00 am";
+console.assert(
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
+);
+
+const currentOutput2 = formatAs12HourClock("23:00");
+const targetOutput2 = "11:00 pm";
+console.assert(
+ currentOutput2 === targetOutput2,
+ `current output: ${currentOutput2}, target output: ${targetOutput2}`
+);
+```
+
+Inside the `formatAs12HourClock` function we do exactly the same thing twice.
+
+{{}}
+Identify the two bits of code inside `formatAs12HourClock` that do exactly the same thing.
+{{}}
+
+There are a few reasons this isn't ideal.
+
+1. It's not clear what this value represents. You can read it and work it out, but that takes some time.
+2. Doing the same thing twice is slower than doing it once.
+3. In the future if we need to change this code's implementation, we would need to change it **twice**.
+Right now our code assumes the hours in a time are always two digits (like `05:00`). What if we wanted to support single-digit hours, like `5:00`? We would need to make the same change to both lines. It would be easy to change one line and forget the other, which would lead to a bug.
+
+### Refactor
+
+Once your code passes your test, look for ways you could make your code better. This doesn't mean changing _what_ it does - the code works. It means changing how it's written.
+
+This is called {{}}To refactor means to update our code _quality_ without changing the _implementation_. Changing _how_ it does something, not changing _what_ it does.{{}}.
+
+We can refactor our code to remove this duplication by introducing a variable:
+
+```js {linenos=table,linenostart=1,hl_lines=["2-4"]}
+function formatAs12HourClock(time) {
+ const hours = Number(time.slice(0, 2));
+ if (hours > 12) {
+ return `${hours - 12}:00 pm`;
+ }
+ return `${time} am`;
+}
+
+const currentOutput = formatAs12HourClock("08:00");
+const targetOutput = "08:00 am";
+console.assert(
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
+);
+
+const currentOutput2 = formatAs12HourClock("23:00");
+const targetOutput2 = "11:00 pm";
+console.assert(
+ currentOutput2 === targetOutput2,
+ `current output: ${currentOutput2}, target output: ${targetOutput2}`
+);
+```
+
+This code does exactly the same thing as the previous code. But it is better in a few ways:
+
+1. We can now tell more easily what this expression represents. The variable name conveys: it's the hours from the time.
+2. We only compute the hours once, not twice, which will be a little bit faster.
+3. If we need to change how we identify the hours (e.g. to support single-digit hours), we only need to update one bit of code. Both lines 3 and 4 will automatically use the same value, because they're referring to the same variable.
+
+{{}}
+Whenever you finish implementing a sub-goal, or a goal, read your code and look for ways to refactor it.
+
+This will make your code easier to continue working on.
+{{}}
diff --git a/common-content/en/module/js1/reusing-variable-names/index.md b/common-content/en/module/js1/reusing-variable-names/index.md
new file mode 100644
index 000000000..c14a93454
--- /dev/null
+++ b/common-content/en/module/js1/reusing-variable-names/index.md
@@ -0,0 +1,121 @@
++++
+title = '🔄 Reusing variable names'
+
+time = 30
+facilitation = false
+emoji= '🔄'
+[objectives]
+1='Fix code which declares the same identifier more than once'
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
+
++++
+
+We saw this error:
+
+```
+SyntaxError: Identifier 'currentOutput' has already been declared
+```
+
+Now that we understand it, let's fix it.
+
+We're not allowed to declare a new variable with the same name as an old one. Both lines 5 and 12 here try to declare a new variable named `currentOutput`:
+
+```js {linenos=table,linenostart=1,hl_lines=["5", "12"]}
+function formatAs12HourClock(time) {
+ return `${time} am`;
+}
+
+const currentOutput = formatAs12HourClock("08:00");
+const targetOutput = "08:00 am";
+console.assert(
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
+);
+
+const currentOutput = formatAs12HourClock("23:00");
+const targetOutput = "11:00 pm";
+console.assert(
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
+);
+```
+
+{{}}
+
+Make sure you understand the error message before you try to fix the code.
+
+If you don't understand what's wrong, you probably won't be able to fix it!
+
+{{}}
+
+### Fixing the error
+
+We want to do multiple assertions. And we're using variables in our assertions. But we're not allowed to use the same name twice. The simplest way we can fix this problem is by changing the name of the second variable. Remember to also change where we _use_ the variable, not just where we declare it!
+
+```js {linenos=table,linenostart=1,hl_lines=["12", "15", "16"]}
+function formatAs12HourClock(time) {
+ return `${time} am`;
+}
+
+const currentOutput = formatAs12HourClock("08:00");
+const targetOutput = "08:00 am";
+console.assert(
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
+);
+
+const currentOutput2 = formatAs12HourClock("23:00");
+const targetOutput = "11:00 pm";
+console.assert(
+ currentOutput2 === targetOutput,
+ `current output: ${currentOutput2}, target output: ${targetOutput}`
+);
+```
+
+### Trying again
+
+After making this change, let's try running our code again. We get this output:
+
+```console
+% node clock-example.js
+/Users/dwh/CYF/clock-example.js:13
+const targetOutput = "11:00 pm";
+ ^
+
+SyntaxError: Identifier 'targetOutput' has already been declared
+ at wrapSafe (node:internal/modules/cjs/loader:1383:18)
+ at Module._compile (node:internal/modules/cjs/loader:1412:20)
+ at Module._extensions..js (node:internal/modules/cjs/loader:1551:10)
+ at Module.load (node:internal/modules/cjs/loader:1282:32)
+ at Module._load (node:internal/modules/cjs/loader:1098:12)
+ at TracingChannel.traceSync (node:diagnostics_channel:315:14)
+ at wrapModuleLoad (node:internal/modules/cjs/loader:215:24)
+ at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:158:5)
+ at node:internal/main/run_main_module:30:49
+
+Node.js v22.4.1
+```
+
+Fortunately, we've seen this kind of error before. It's exactly the same as the last one, but about the `targetOutput` variable on line 13, instead of the `currentOutput` variable on line 12.
+
+{{}}
+Fix this error, and try running your code again.
+{{}}
+
+Now the second assertion fails with the following message:
+
+```console
+% node clock-example.js
+Assertion failed: current output: 23:00 am, target output: 11:00 pm
+```
+
+We expect this. Our function just adds " am" to the end of the time, which only works for times in the morning. We have proven our code isn't complete yet. Next we can fix it so that this test passes.
+
+{{}}
+
+✏️ Write another assertion that checks `formatAs12HourClock` returns the target output when passed another _time input in the afternoon._
+
+{{}}
diff --git a/common-content/en/module/js1/strategy/index.md b/common-content/en/module/js1/strategy/index.md
index ce5e9579f..288def36f 100644
--- a/common-content/en/module/js1/strategy/index.md
+++ b/common-content/en/module/js1/strategy/index.md
@@ -1,12 +1,13 @@
+++
title = '↙️ ↘️ Making a choice'
-time = 20
+time = 10
facilitation = false
emoji= '🧩'
hide_from_overview = true
[objectives]
1='Propose a strategy for solving a problem'
+ 2='Identify sub-problems within a larger problem'
[build]
render = 'never'
list = 'local'
@@ -28,28 +29,15 @@ A{Is the time before midday?} -- true --> B[Add am to time string]
A -- false --> C[???]
```
-We need to work out what to do in the case when the time input is later than midday.
+We need to make two changes to our code.
-## 🧭 Describing the strategy
+1. We need to do something different depending on whether the time is before midday. This is called running code **conditionally**.
+2. And then we need to know what we do if the time is after midday.
-Let's describe the strategy for dealing with an input that is after midday.
+We don't need to solve the whole problem at once. First let's work out how to do something different depending on the time. We can worry about what we need to do differently once we've solved this problem.
-Earlier we observed that when the time goes beyond midday then **we can subtract 12 from the hours time to get the new hours for the 12 hour clock time**.
+{{}}
+It's easier to search for the solutions to smaller parts of problems than the whole problem.
-_Before_ writing code, we can define our approach in steps using a flowchart:
-
-Starting with an input like `"23:00"`:
-
-```mermaid
-
-flowchart LR
-
-A[extract the hours, '23', from the time '23:00'] --> B[convert '23' to a number, 23]
-B --> C{check: Are the hours greater than 12?}
-C -- false --> D[add am to time string]
-C -- true --> E[subtract 12 from the hours, to get 11]
-E --> F[add 'pm' to the rest of the time, to get '11:00 pm']
-F --> G[return the new time]
-```
-
-This approach involves running some code **conditionally**. In this case, we're only going to continue doing Steps 4-6 if the condition **hours are greater than 12** is `true`.
+Programming is all about breaking down problems into smaller pieces which we can solve.
+{{}}
diff --git a/common-content/en/module/js1/strings/index.md b/common-content/en/module/js1/strings/index.md
index 06c42801c..43139d924 100644
--- a/common-content/en/module/js1/strings/index.md
+++ b/common-content/en/module/js1/strings/index.md
@@ -1,7 +1,7 @@
+++
title = '🧶 Accessing strings'
-time = 15
+time = 20
facilitation = false
emoji= '🧩'
[objectives]
@@ -53,8 +53,28 @@ time.slice(0, 2); // will access the characters below
| :-------: | :---: | :---: |
| character | `"2"` | `"3"` |
-So `time.slice(0,2)` will evaluate to `"23"` when the `time` is `"23:00"`. Finally we must convert `"23"` to the number `23`, otherwise we can't compare this value properly. We can use the `Number` function to convert the string into a number.
+So `time.slice(0,2)` will evaluate to `"23"` when the `time` is `"23:00"`.
-```js
-Number(time.slice(0, 2)); // evaluates to 23
-```
+Finally we must convert `"23"` to the number `23`, otherwise we can't compare this value properly.
+
+{{}}
+
+Think about the numbers 100 and 23. Which one is bigger?
+
+Write code which compares the strings `"100"` and `"23"` and tells you which one is bigger.
+
+Does this match your expectation? If not, what do you think is happening?
+
+{{}}
+
+JavaScript uses different ways to [compare values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness) depending on their types. If you compare two strings (which may contain numbers), it will do something different than if you compare two numbers.
+
+We can use the `Number` function to convert the string into a number.
+
+{{}}
+
+Work out how you can convert the strings "100" and "23" to numbers.
+
+Write code which compares the numbers `100` and `23` and tells you which one is bigger.
+
+{{}}
diff --git a/common-content/en/module/js1/sub-goal-2/index.md b/common-content/en/module/js1/sub-goal-2/index.md
new file mode 100644
index 000000000..b690fb071
--- /dev/null
+++ b/common-content/en/module/js1/sub-goal-2/index.md
@@ -0,0 +1,60 @@
++++
+title = '🏗️ Sub-goal #2'
+
+time = 10
+facilitation = false
+emoji= '🧩'
+hide_from_overview = true
+[objectives]
+ 1='Explain how different concepts are combined to solve a goal'
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
+
++++
+
+Now we can think about what we do when we've identified a time is after midday.
+
+Earlier, we observed what to do when the time goes beyond midday: **subtract 12 from the hours time to get the new hours for the 12 hour clock time**.
+
+_Before_ writing code, we can define our approach in steps:
+
+Starting with an input like `"23:00"`:
+
+```mermaid
+
+flowchart LR
+
+A[extract the hours, '23', from the time '23:00'] --> B[convert '23' to a number, 23]
+B --> C{check: Are the hours greater than 12?}
+C -- false --> D[add am to time string]
+ C -- true --> E[subtract 12 from the hours, to get 11]
+subgraph "Time after midday"
+ E --> F[add 'pm' to the rest of the time, to get '11:00 pm']
+ F --> G[return the new time]
+end
+```
+
+Now we can format the string using our approach from earlier:
+we’ll need to append `"pm"` to the string expression and subtract 12 from the hours. So we get the following:
+
+```js
+if (Number(time.slice(0, 2)) > 12) {
+ return `${Number(time.slice(0, 2)) - 12}:00 pm`;
+}
+```
+
+The `return` statement above implements the following steps we set out earlier:
+
+```mermaid
+
+flowchart LR
+
+D[subtract 12 from the hours]
+D --> E[add 'pm' to the rest of the time]
+E --> F[return the new time]
+
+```
+
+Now we can **re-run** our assertions from earlier to check our function behaves as target.
diff --git a/common-content/en/module/js1/sub-goal/index.md b/common-content/en/module/js1/sub-goal/index.md
index b8bafbb5f..970a26180 100644
--- a/common-content/en/module/js1/sub-goal/index.md
+++ b/common-content/en/module/js1/sub-goal/index.md
@@ -1,7 +1,7 @@
+++
title = '🧠 Forming sub-goals'
-time = 30
+time = 20
facilitation = false
emoji= '🧩'
[objectives]
diff --git a/common-content/en/module/js1/testing-a-sub-goal/index.md b/common-content/en/module/js1/testing-a-sub-goal/index.md
new file mode 100644
index 000000000..f6cab3bab
--- /dev/null
+++ b/common-content/en/module/js1/testing-a-sub-goal/index.md
@@ -0,0 +1,82 @@
++++
+title = '🔎 Testing a sub-goal'
+
+time = 15
+facilitation = false
+emoji= '🔎'
+hide_from_overview = true
+[objectives]
+ 1='Test a solution to a sub-goal before solving the whole problem'
+[build]
+ render = 'never'
+ list = 'local'
+ publishResources = false
+
++++
+
+Earlier we defined a sub-goal to find a value for the hours from the `time` input. We've found that `Number(time.slice(0,2))` is an expression that evaluates to the hours from `time`. So we can write an `if` statement using this expression:
+
+```js
+if (Number(time.slice(0, 2)) > 12) {
+}
+```
+
+If the time is `"23:00"` then the expression `Number(time.slice(0, 2)) > 12` will evaluate to `true` and the body of the `if` statement will be executed.
+
+This `if` statement is implementing the following part of the diagram from earlier:
+
+```mermaid
+
+flowchart TD
+
+A{Check: Are the hours greater than 12?}
+
+```
+
+Before we worry about how we handle times in the afternoon, we can check that we've solved this sub-goal.
+
+We can check that we are correctly identifying times in the afternoon by adding in our `if` statement (which we think is correct), with a placeholder body:
+
+```js {linenos=table,linenostart=1,hl_lines=["2-4"]}
+function formatAs12HourClock(time) {
+ if (Number(time.slice(0, 2)) > 12) {
+ return "Don't know how to handle times in the afternoon yet";
+ }
+ return `${time} am`;
+}
+
+const currentOutput = formatAs12HourClock("08:00");
+const targetOutput = "08:00 am";
+console.assert(
+ currentOutput === targetOutput,
+ `current output: ${currentOutput}, target output: ${targetOutput}`
+);
+
+const currentOutput2 = formatAs12HourClock("23:00");
+const targetOutput2 = "11:00 pm";
+console.assert(
+ currentOutput2 === targetOutput2,
+ `current output: ${currentOutput2}, target output: ${targetOutput2}`
+);
+```
+
+If we run our code, we expect the current output of the `23:00` test-case to have changed. It won't be correct - the assertion will still fail. But if it hasn't changed, we know our `if` statement is wrong.
+
+```console
+% node clock-example.js
+Assertion failed: current output: Don't know how to handle times in the afternoon yet, target output: 11:00 pm
+```
+
+Even though we _know_ the code on line 3 is incorrect, this was a useful step. It allowed us to run our code more often, and check that we're on the right track.
+
+{{}}
+Run your code as often as you can.
+
+Make small changes and run your code.
+
+Sometimes we write code we know we will delete because it lets us get feedback sooner.
+{{}}
+
+Now we can focus on just one problem: how to handle times after midday (i.e. fixing line 3). We don't need to worry about both detecting the time _and_ handling it.
+
+If the output of this assert still printed `"23:00 am"` we would have stopped here and debugged that. Again, we could focus on just one problem.
diff --git a/org-cyf-itp/content/structuring-data/sprints/2/prep/index.md b/org-cyf-itp/content/structuring-data/sprints/2/prep/index.md
index e6d9024eb..ca94ffa73 100644
--- a/org-cyf-itp/content/structuring-data/sprints/2/prep/index.md
+++ b/org-cyf-itp/content/structuring-data/sprints/2/prep/index.md
@@ -14,6 +14,15 @@ name="Comparison"
src="module/js1/assertions"
name="Assertions"
[[blocks]]
+src="module/js1/interpreting-errors"
+name="Interpreting errors"
+[[blocks]]
+src="module/js1/interpreting-this-error"
+name="Interpreting this error"
+[[blocks]]
+src="module/js1/reusing-variable-names"
+name="Reusing variable names"
+[[blocks]]
src="module/js1/strategy"
name="Strategy"
[[blocks]]
@@ -26,6 +35,15 @@ name="Sub-goal"
src="module/js1/strings"
name="Strings"
[[blocks]]
-src="module/js1/assembly"
-name="Assembly"
+src="module/js1/testing-a-sub-goal"
+name="Testing a sub-goal"
+[[blocks]]
+src="module/js1/sub-goal-2"
+name="Sub-goal #2"
+[[blocks]]
+src="module/js1/refactoring-repetition"
+name="Refactoring repetition"
+[[blocks]]
+src="module/js1/identifying-missing-tests"
+name="Identifying missing tests"
+++
diff --git a/org-cyf-itp/content/structuring-data/success/index.md b/org-cyf-itp/content/structuring-data/success/index.md
index 0796347b3..d1d2538fb 100644
--- a/org-cyf-itp/content/structuring-data/success/index.md
+++ b/org-cyf-itp/content/structuring-data/success/index.md
@@ -9,18 +9,20 @@ weight = 11
1="Complete the [Intro to Python course](https://github.com/CodeYourFuture/Module-Structuring-and-Testing-Data/issues/21)"
2="Link to your exercises for the [Coursework Exercises](https://github.com/CodeYourFuture/Module-Structuring-and-Testing-Data/issues/6) "
3="Link to your [Written Email for an Internship](https://github.com/CodeYourFuture/Module-Structuring-and-Testing-Data/issues/20)"
-
+++
### 🎯 You've achieved your learning objectives if you can:
```objectives
-- Define variables and functions.
-- Explain what a function will return when it is called.
-- Use if statements to write conditional code.
-- Identify the benefits of extracting a reusable function.
-- Explain which scopes can access variables declared in a JavaScript file.
-- Write tests for your code, using Jest.
+- Interpret and rephrase error messages
+- Break down a problem into sub-goals
+- Implement and test single sub-goals without implementing a full solution to the whole goal
+- Identify and refactor duplicated code
+- Translate requirements into unit tests
+- Interpret test feedback
+- Identify edge cases that need testing
+- Describe the intended behaviour of a program and its actual behaviour
+- Identify bugs in someone else’s code (person/machine)
```
### 💯 To complete _any_ module, you must: