# PHAS0100 - Week 6
:::info
## :tada: Welcome to the 6th live class!
### Today we will:
- Discuss Quality of Code
- Recap Object-oriented programming (OOP) principles
- Play with VS Code and a debugger to find :bug:s
:::
### Groups
We will assign you into groups of 3-5 people in the lab for this lesson and we will use the breakout rooms functionality of Zoom for online participants.
You will populate this collaborative document with the relevant findings based upon discussions in your groups.
### Timetable for Today
- **Part I**
-- 2:00-2:20 Recap of code quality and quiz
-- 2:20-2:30 Discussion in breakout
-- 2:30-2:40 Recap of OOP principles
-- 2:40-3:00 Design challenge in breakout
-- 10m BREAK
- **Part II**
-- 3:10-3:20 Code readability and another quick quiz
-- 3:20-3:40 Discussion of 4 elements of simple design & Kat's recommendations
-- 10m BREAK
- **Part III**
-- 3:50-4:05 Demonstration of g++ warnings, gdb, and valgrind
-- 4:05-4:50 Bug-finding challenge in breakout
-- 4:50-5:00 Wrapup
# Part I
## I. A) Code Quality
Recall Steve McConnell's list of qualities:
- External qualities
- Correctness
- Accuracy
- Reliability
- Robustness
- Efficiency
- Adaptability
- Usability
- Internal qualities
- Maintainability
- Flexibility
- Portability
- Reusability
- Readability
- Testability
- Understandability
### Quiz
What's the *most* important qualities for these examples:
- World of Warcraft:
- A scientific simulation:
- Whatsapp messenger:
- A banking app:
- The Eigen library:
<https://www.menti.com>
### Breakout Discussion
Each group gets an example from the quiz.
- Do you agree with the class's top qualities for your example? Why?
- Does choosing the *most* important quality even make sense?
### Itemised summary of each group's discussion
#### Group 1. World of Warcraft
- ***External***
- In person: Prioritise accuracy
- In person: in effect, all are important
- In person: correctness less so important
- ***Internal***
- **Maintainability:** massively online, so server-side stability is important to maintain
- **Reusability:** big game of many entities sharing characteristics -> large class hierarchy
- **Readability:** always important to keep code well-structured and formatted
- **Testability:** implementation of high-level emergent features require thorough testing
- **Understandability:** for bugs to be fixed and tweaks to be made quickly, the source code should be decently navigable
#### Group 2. A Scietific simulation
- ...
- Accuracy: giving accurate result
- Testablility: Need to check whether it can give a correct answer
- Robustness: handle different situations
- Usability (less important): easy to set up
- Adaptability: build different models
-
#### Group 3. Whatsapp messenger
- on menti : cross-platform, speed & usability
- is there something most important? No, many factors should be included for making a messenging app useful and appropriate for use.
- Top 3 internal qualities:
- **portability** (cross-platform) : android, IOS, ...
- **maintainability/scalability** : quick correction of bugs & ability to deal with increased flow.
- **testability** : you don't want to roll out something that could have adverse effects on the user base.
- Top 3 external qualities:
- **security** : no point in having a private messenging app otherwise.
- **usability** : it's the whole point of communication applications, i.e. facilitating it.
- **reliability** : messages need to arrive (to the right person), app needs to be available 24/7.
#### Group 4. A banking app
- Top Qualities: Security, Robustness, Cross-platform, Usability, Maintainability
- Security: Protecting users' money, bank account privacy
- Robustness: Handle different situations
- Cross-platform: Should be used via both website and mobile application, can be operated with different devices
- Usability: Users can easily get the bank sevices online
- Maintainability: Find and fix bugs in time to avoid being attacked or ensure a stability to make it easy for users to operate.
-
#### Group 5. The Eigen Library
- Reliability: Algorithms are carefully selected for reliability. Reliability trade-offs are clearly documented and extremely safe decompositions are available.
- Readability: The API is extremely clean and expressive while feeling natural to C++ programmers, thanks to expression templates.Implementing an algorithm on top of Eigen feels like just copying pseudocode.
- Adaptability: as we run our test suite against many compilers to guarantee reliability and work around any compiler bugs. Eigen up to version 3.4 is standard C++ 03 and maintains reasonable compilation times. Versions following 3.4 will be C++14.
-
## I. B) OOP Principles Recap
Remember the 4 principles of object-oriented programming:
- Encapsulation (hiding state)
- Abstraction (hiding implementation)
- Inheritance (similar classes share parent class)
- Polymorphism (similar classes can be treated like parent class)
### Class Exercise 1a: Exploration of encapsulation & abstraction
Design part of a small sims-like game, where the character can interact with a coffee machine. We just want to model the character, the coffee machine and how they *might* interact (use your imagination!). What I'm looking for is a list of classes, a descriptions of their data members, the public interface, and the way in which the classes interact via this public interface. Feel free to use a simple description of the classes, methods, data members and a description of how they might interact. Consider the first two principles of OOP: encapsulation (hiding **state**) and abstraction (hiding **implementation** behind a **public interface**). Don't worry about inheritance and polymorphism for now.
Some questions to consider:
- What are the classes?
- How might they interact?
- What might their public interfaces look like?
- What private data members will the character and coffee machine require?
- What private functions could they have?
- Have you made sure the data in each class is appropriately encapsulated?
- Have you made sure the implementation of certain operations is hidden?
### Itemised summary of each group's discussion
#### Group 1.
```
class Drink {
public:
private:
};
class DrinkMachine {
public:
virtual Drink get_drink();
private:
virtual bool has_supplies();
virtual Drink make_drink();
};
class CoffeeMachine : DrinkMachine {
public:
Drink get_drink() {...}
private:
bool has_supplies();
Drink make_drink();
};
class TeaMachine : DrinkMachine {
public:
Drink get_drink() {...}
private:
bool has_supplies();
Drink make_drink();
};
class Character {
public:
private:
};
```
- In person:
- Present main menu (coffee options)
- Input: coffee,
- Present sub-options: size, number of shots, sugar, milk type
- Input: sub-options as an Order data member
- Take payment:
- Make drink: Passes Order class to Coffee Machine class (private) to operate the machine with given configuration of the order
- Classes; order, coffee machine, character
- Order is an object within a coffee machine as a data member,
#### Group 2.
- class Machine
-public:
virtue run() =0
- class CoffeeMachine : public Machine
- public:
- chooseCoffee():
- pay():
- run():
- private:
- displayOption():
- charge():
- makeCoffee():
- dropCoffee():
- class Drink
-public:
-getName()
-getPrice()
-getImage()
-private:
-name
-price
-image
#### Group 3.
- Class Person
- private:
- Cup unique pointer
- string Favourite Drink
- public:
- ChooseDrink(machine,option)
- Class DrinksMachine
- private:
- dictionary of liquids:(available amount)
- public:
- readOption()
- DispenseLiquid(Cup)
- Struct Cup
- string content
- bool full
#### Group 4.
- Class Character
- private
- name
- money
- public
- buy_drink()
- Class Drink_Machine{
- public
- choose_drink()
- show_price()
- produce()
- sell()
- private
- menu
- drink_storage
- cup_storage
- Class Drink{
- private
- price
- name
- size
- ice
- sugar
- public
- get_price()
- ...
}
#### Group 5.
- Character
- private:
Drink something
- public:
Choose Favourite Drink
- Coffee Machine:
- public:
Making coffee
- private:
Making coffee that is favourite
- Tea Machine:
- public:
### Class Exercise 1b: Exploration of inheritance & polymorphism
Now let's explore inheritance and polymorphism. What if we don't just want a coffee-machine but also a tea-machine? Rewrite your design from part **1a** to include a tea-machine which behaves like the coffee-machine but makes tea. The important thing when designing classes with inheritance is understanding what functionality to put in the **superclass** and what should be in each type of **subclass**.
Some more things to consider:
- What parts of the public interface are shared between the two machines?
- What parts of the private implementation are shared?
### Itemised summary of each group's discussion
#### Group 1.
- In person:
- Drink base class; coffee and tea derived from base class (i.e. size, cost)
- Machine class has methods to create both coffee and tea (Takes in order which is constructed from tea/coffee)
#### Group 2.
- ...
#### Group 3.
- Class TeaMachine : DrinksMachine
- private:
- vector tea types
- Class CoffeeMachine : DrinksMachine
- private:
- bool MakeIrish
#### Group 4.
- Class Coffee_Machine: Drink_Machine
- Public:
- sell_coffee()
- get_storage()
- private:
- produce_coffee()
- get_storage_drink()
- get_storage_cup()
-
- Class Tea :public Drink
}
#### Group 5.
- Class Machine
- private
- public
- collect cash
- making something to drink
- Class Tea Machine : public Machine
- private
- public
- making tea
### Class Exercise 1c: Exploration of composition
Now let's design a drinks vendor, a machine that could make tea, coffee, maybe even juice! It doesn't make sense for this machine to inherit from any class you've designed previously. It *does* make sense for this machine to be *composed* of some of the previous classes. Design a machine that can make *both* tea and coffee using the classes from the previous part without inheriting from either of them.
Even more things to consider:
- How can you link the public interface of the vendor to the internal tea or coffee machines?
- Are the tea and coffee machines private or public data members?
- What are the potential advantages to composition over inheritance (especially if we add more drinks)?
### Itemised summary of each group's discussion
#### Group 1.
- ...
#### Group 2.
```
class DrinkMachine {};
class CoffeeMachine: DrinkMachine {};
class TeaMachine: DrinkMachine {};
class SuperMachine {
private:
std::vector<DrinkMachine> machines;
public:
bool hasCoffee();
bool hasJuice();
void dispense();
}
```
#### Group 3.
- FancyMachine:
- public:
- CoffeMachine;
- TeaMachine;
- GetDrink();
#### Group 4.
- ...
#### Group 5.
-
# Part II
## II. A) Code Readability
Let’s assume I have in test.cpp:
int GCD(int a,int b) {int r;
while(b){r=a%b; a=b;b=r;}return a;}
Then, running [clang-format] test.cpp produces:
int GCD(int a, int b) {
int r;
while (b) {
r = a % b;
a = b;
b = r;
}
return a;
}
[clang-format]:https://clang.llvm.org/docs/ClangFormat.html
### Another Quiz
How does code smell? With its nose!
<https://www.menti.com>
## II. B) Quality Software Design Discussion
### Four elements of simple design discussion
As part of this week's lecture, you should have read [J. B. Rainsberger's *The Four Elements of Simple Design*][four-elements] and considered the following questions:
- Do you agree with his 4 elements? What about the 2 elements he ends up with? Why?
- J codes in an iterative way, renaming functions to `foo` before he knows what they *really* do. How could this impact collaboration if J is writing functions called `foo`?
- What is the value in this kind of iterative programming?
- What are the potential downsides?
- How would you use J's iterative programming style to improve Kat's code?
### Class Exercise 2
In your breakout groups, discuss your answers.
[four-elements]: https://blog.jbrains.ca/permalink/the-four-elements-of-simple-design
### Itemised summary of each group's discussion
#### Group 1.
- 4 rules is excessive, the 2. and 3. rules make sense.
- Removing 1. makes sense, but not for the reason that it is second nature; it's not about design, but rather about making sure your code can handle jsut about anything.
- foo is bad idea, have at least some name to say what it does, and try to probe code about what is its function
- Maintaining "clarity" is somewhat vague - no project should be purposefully made unclear.
- The prioritisation of testing differs from project to project, e.g. larger continuous integration schemes will have testing as important at all times, while small script-style programs will require much less active long-term testing.
#### Group 2.
- Agree
- Collaborator cannot understand foo()
- Simplify and clarify the code
- forget to change foo() may be bad
-
#### Group 3.
- Agree. Not with removing the tests -> at some point will make mistake
- Other people won't understand what he's doing
- It allows you to update your names as your learn more about functionality rather than having to spend a long time trying to understand what something does. It's **flexible**
- That you may forget to change a name? That you may confuse someone else?
-
#### Group 4.
- Agree, the 2 elements improve the code quality.
- Others can't understand it
- He can update the name
#### Group 5.
- Agree
- foo() only makes sense to himself. This reduces readability for collaboration.
- he's a little arrogant on the testing bit
# Part III
## III. A) Demonstration
I'll walk through the process of finding and fixing a few bugs in some "badly implemented array" code, which you can get from:
```bash
git clone https://github.com/OrodRazeghi/PHAS0100Week06Pt03.git
```
or directly from [moodle](https://moodle.ucl.ac.uk/pluginfile.php/3916102/mod_resource/content/3/badlyImplementedArray.cpp). I recommend you download the code and follow along. You may need to install valgrind:
`sudo apt install valgrind`
To build, you can use:
```bash
g++ -g -Wall badlyImplementedArray.cpp
```
This will output the executable `a.out` in the current directory.
### Debugging tool cheatsheet
#### Warnings and symbols
Enabling compiler warnings:
`-Wall`
Enabling symbols:
`-g`
**Note**: Adding symbols has possible performance implications.
#### GDB cheatsheet for debugging from the command line
Staring gdb:
`gdb ./a.out`
| Command | Long version | Short version |
| ----------------------------------------- | ----------------- | ------------- |
| run program | `run` | `r` |
| print call stack | `where` | `whe` |
| switch frame | `frame <n>` | `f <n>` |
| list nearby code | `list` | `l` |
| print variable value | `print <varname>` | `p <varname>` |
| set breakpoint | `break <n>` | `b <n>` |
| print current breakpoints | `info break` | `i b` |
| delete breakpoint | `delete <n>` | `d <n>` |
| set watchpoint | `watch <varname>` | `w <varname>` |
| continue until break/watch/error | `continue` | `c` |
| run next line (step into functions) | `step` | `s` |
| run next line (don't step into functions) | `next` | `n` |
**Note**: Setting breakpoints and watchpoints is dependent on which frame/file you're currently viewing.
**Note**: gdb doesn't care about privacy of variables
#### Valgrind
Starting valgrind:
`valgrind ./a.out`
Track initialisation (or lack of):
`--track-origins=yes`
Analyse leaks:
`--leak-check=full`
## III. B) Bug-finding Challenge
There are six more (known) bugs for you to find. You might be able to find some by looking at the code intently but try using the tools first. Some show up in the compiler warnings. Some are memory leaks and invalid read/writes that you can find with valgrind. Some might require you to use gdb to set breakpoints and watchpoints.
### Class Exercise 3
Fix the bugs when you find them but think about how the code could be rewritten or redesigned *defensively* to avoid these bugs in the future.
### Recap
I'll show you my rewrite of the "badly implemented array" code using some defensive strategies and good practices.
# Homework Exercise
The assignment 1 deadline is nearly upon us so your homework is just to take what you've learned from this lesson to improve the quality of your assignment code. Some suggestions:
- Choose a few qualities you think are most important to your code
- Read your code critically; is it the highest quality you can write?
- Make sure your state and implementation are hidden behind a thoughtful public interface
- Ensure your code is as readable to others as it is to you (perhaps ask a coursemate to read it?)
- Did you KISS?
- Use `const` and smart pointers liberally
- Enable compiler warnings and fix every single one
- Run your program with valgrind and fix any errors it reports (if you don't get any, nice work!)
# Questions
Here you can post any question you have while we are going through this document. A summary of the questions and the answers will be posted in moodle after each session. Please, use a new bullet point for each question and sub-bullet points for their answers.
For example writing like this:
```
- Example question
- [name=student_a] Example answer
- [name=TA_1] Example answer
```
produces the following result:
- Example question
- [name=student_a] Example answer
- [name=TA_1] Example answer
Write new questions below :point_down:
- []
###### tags: `phas0100` `teaching` `class`