- Transition to Processing
- Primitive Operations
- Algorithms
- Variables
- Debugging in Processing
- Conditions
- Loops
- Functions
- Scope
- Compound Data
- Reference Semantics
- Refactoring
- Transition to Java
- Debugging in Java
- Unit Testing
- Classes - Writing your own Types
- Classes - Functions inside objects
- Recursion
- Searching
- Lists
- ArrayLists vs Recursive Data

- Logic and Proofs
- Relations
- Mathematical Functions
- Matrices
- Binary Numbers
- Trigonomtry
- Finite State Machines
- Turing Machines
- Counting - Inclusion/Exclusion
- Graph Algorithms

- Algorithm Efficiency
- Algorithm Correctness
- Trees
- Heaps, Stack, and Queues
- Maps and Hashtables
- Graphs and Graph Algorithms
- Advanced Trees and Computability

- Command line control
- Transition to C
- Pointers
- Memory Allocation
- IO
- Number representations
- Assembly Programming
- Structs and Unions
- How memory works
- Virtual Memory

- Version Control with Git
- Inheritance and Overloading
- Generics
- Exceptions
- Lambda Expressions
- Design Patterns
- Concepts of Concurrency
- Concurrency: Object Locks
- Modern Concurrency

- System Models
- Naming and Distributed File Systems
- Synchronisation and Concurrency
- Fault Tolerance and Security
- Clusters and Grids
- Virtualisation
- Data Centers
- Mobile Computing

- Transition to Scala
- Functional Programming
- Syntax Analysis
- Name Analysis
- Type Analysis
- Transformation and Compilation
- Control Abstraction
- Implementing Data Abstraction
- Language Runtimes

- Transition to Coq
- Proof by Induction, Structured Data
- Polymorphism and Higher-Order Functions
- More Basic Tactics
- Logical Reasoning in Proof Assistants
- Inductive Propositions
- Maps
- An Imperative Programming Language
- Program Equivalence
- Hoare Logic
- Small-Step Operational Semantics
- Simply-typed Lambda Calculus

- Be able to identify why one program snippet is preferrable over another.
- Be able to convert programs from a poorer version to a better version.

We refactor code to *takeaway duplicate or similar code*, *to make our program easier to understand*, and *to improve code maintenance*.

You want meaningful variable names. If you find you have a variable that is not self-describing, give it a better name.

```
int d = 20;
ellipse(width/2, height/2, d, d);
```

```
int diameter = 20;
ellipse(width/2, height/2, diameter, diameter);
```

Any value that you are using *in multiple places* but *for the same underlying concept* is called a magic number and should be replaced by a variable

```
ellipse(width/2, height/2, 20, 20);
```

```
int circleSize = 20;
ellipse(width/2, height/2, circleSize, circleSize);
```

`if`

```
if(x < 7)
y = 4;
if(x > 23)
y = 4;
```

```
if(x < 7 || x > 23)
y = 4;
```

`if`

condition```
if(x < 7)
y = 4;
if(x < 7)
z = 9;
```

```
if(x < 7) {
y = 4;
z = 9;
}
```

`if`

statements can sometimes be combined.It is often possible to replace nested `if`

statements with a single `if`

statement that has a more complex condition. You should take this option *as long as the condition does not become too complex itself*.

```
if(x < 7){
if (y < 7){
y = 4;
}
}
```

```
if(x < 7 && y < 7) {
y = 4;
}
```

```
ellipse(30, 30, 10, 10);
ellipse(60, 60, 10, 10);
ellipse(90, 90, 10, 10);
ellipse(120, 120, 10, 10);
ellipse(150, 150, 10, 10);
```

```
for(int i = 30; i <= 150; i += 30){
ellipse(i, i, 10, 10);
}
```

Introduce an array to store the values you need and loop over the array.

```
ellipse(30, 30, 10, 10);
ellipse(50, 50, 10, 10);
ellipse(110, 110, 10, 10);
ellipse(120, 120, 10, 10);
ellipse(160,160, 10, 10);
```

```
int[] z = {30, 50, 110, 120, 160};
for(int i = 0; i < z.length; i++){
ellipse(z[i], z[i], 10, 10);
}
```

Sometimes, in using a loop to position multiple things on the screen, we end up using a calculation based on the loop variable. It is often possible to adjust the way that loop variable progresses instead. You end up with more meaningful coe because the loop variable is taking exactly the values you need - it is a little-bit of documentation *and* the code is simpler.

```
for(int i = 0; i < 10; i++){
ellipse(width/2, height/2, i*10, i*10);
}
```

```
for(int i = 0; i < 100; i = i + 10){
ellipse(width/2, height/2, i, i);
}
```

Note that the following examples show cases where new functions could be created but in practical cases, we would be more likely to create a new function if:

- it has a reasonable size or complexity
- it will be used (or is likely to be used) in multiple places in the code

You might have similar code in two (or more) place in your program. For example

1
2
3

stroke(0);
fill(255, 0, 0);
ellipse(255, 200, 40, 40);

in one place and

1
2
3

stroke(0);
fill(255, 0, 0);
ellipse(300, 250, 40, 40);

in another.

You should create a function to do that job

1
2
3
4
5

void drawRedEllipse(int x, int y){
stroke(0);
fill(255, 0, 0);
ellipse(x, y, 40, 40);
}

and replace the other places with calls to this function.

Imagine you have, in one place in the code:

1
2
3

stroke(0)
fill(255, 0, 0);
ellipse(150, 200, 40, 40);

and at another place in the code:

1
2
3

stroke(0)
fill(255, 0, 0);
rect(300, 250, 40, 40);

The structure is the same, the numbers are the same, the intent is very similar, it would be great to have one place to put this code.

To achieve this, you should introduce a parameter that can be used to indicate which version of the major variation should be used. Create a new function and constants for the new parameter:

1
2
3
4
5
6
7
8
9
10
11
12

int SHAPE_ELLIPSE = 1;
int SHAPE_RECT = 2;
void drawRedShape(int x, int y, int shape) {
stroke(0);
fill(255, 0, 0);
if(shape == SHAPE_ELLIPSE){
ellipse(x, y, 40, 40);
} else {
rect(x, y, 40, 40);
}
}

and in the first place, replace with:

1

drawRedShape(150, 200, SHAPE_ELLIPSE);

and in the second place, replace with:

1

drawRedShape(300, 250, SHAPE_RECT);

The following function picks the (first) array element that is closest to the average

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

int closestToAverage(int[] a){
int sum = 0;
for(int i = 0; i < a.length; i++){
sum += a[i];
}
float avg = (float)sum / a.length;
println(avg);
int closest = a[0];
float smallestGap = abs(a[0] - avg);
for(int i = 1; i < a.length; i++){
float currentGap = abs(a[i] - avg);
if(currentGap < smallestGap){
smallestGap = currentGap;
closest = a[i];
}
}
return closest;
}

The function is really doing two separate tasks:

- calculating the average
- scanning the array to find the (first) element that is closest the average

We could create two functions to do these two tasks. The first function can calculate the average and the second function can be slightly generalised so that it will scan an array and find the (first) element that is closest to a particular value.

We now have two functions that are more likely to be used elsewhere in our programs than the original.

`if`

returns `true`

and `false`

If you end up with `return true`

or `return false`

in the body of an if, then the condition probably contains all the information you need.

```
if(x){
return true;
} else {
return false;
}
```

```
return x;
```

You might have mutliple code paths in a function and you end up with mutliple `return`

statements. Make sure you donâ€™t have any redundant ones.

```
if(x){
return 1;
} else {
return 2;
}
return 3;
```

```
if(x){
return 1;
} else {
return 2;
}
```