Commit 755f5125 authored by Alexander Hirsch's avatar Alexander Hirsch
Browse files

Add implementation and testing

parent 548d71bd
This diff is collapsed.
......@@ -126,10 +126,347 @@ If things get to complicated, adding another layer may help.
- Details become less obvious
- The devil is in the detail
- Think in layers
- How far am I from the lowest level
- How far am I from the lowest level?
> You aren't gonna need it
## Cross Layer Interaction
![](images/cross_layer_interaction.svg)
# Implementation
## Types
- Types are documentation
- Use meaningful types (e.g. `bool`)
- Use structs / class to group data that belongs together (e.g. `User`)
## Functions
```c
double square(double n);
bool is_prime(int n);
int sum(const int *data, int size);
double clamp(double value, double lower, double upper);
double xfb(int a, int b, double pre); // 🤔
```
---
- Signatures are documentation
- `const` pointers signal input, non-`const` pointers signal output
- If signature gets too complex
- Use a struct for parameters / return value
- Split function, would be too complicated anyway
---
- Which global state does the function touch?
- Observe the call-graph
- Which parts of the program calls this function?
- Which functions are called by this function?
- Which layer of abstraction are we on?
---
- Number of local variables should not exceed 7
- How long is the function?
- How complicated is the control-flow?
## Variables
- Again, use the correct type
- Meaningful name, don't abbreviate (e.g. `wnd` vs. `window`)
- Conventional abbreviations are ok (e.g. `num_users`)
- `const` by default
- Always initialise
- Limit their scope
- Manually
- Utilise variable declaration inside `for` (and `if` since C++17)
---
```c
int main(void)
{
int number1, number2, number3,
difference1, difference2, difference3,
larger_numbers, smallest_difference,
secret_number, winner;
// …
}
```
Bad
---
```c
int main(void)
{
srand(time(NULL));
int secret = rand() % 100;
while (true) {
int guess1 = get_guess();
int guess2 = get_guess();
int guess3 = get_guess();
// …
}
}
```
Good
---
```c++
const auto direction = physx::PxVec3(inputDir.x, 0.f, inputDir.y)
const auto strength = 2000.0 * timeDelta;
entity->addTorque(strength * direction, physx::PxForceMode::eIMPULSE);
// …
```
Bad
---
```c++
{
const auto direction = physx::PxVec3(inputDir.x, 0.f, inputDir.y)
const auto strength = 2000.0 * timeDelta;
entity->addTorque(strength * direction, physx::PxForceMode::eIMPULSE);
}
// …
```
Good
## Control-Flow
- Linearize as much as possible
- Limit nesting depth
- Avoid complex `break` / `continue` constructs
- Avoid conditionals / loops inside `switch`
- Use empty lines to separate blocks that belong together
Use additional functions (or macros) if things get too complex.
---
```c
void foo(void)
{
if (first()) {
if (second()) {
if (third()) {
// …
}
}
}
}
```
Bad
---
```c
void foo(void)
{
if (!first())
return;
if (!second())
return;
if (!third())
return;
// …
}
```
Good
## Comments
- Comments should tell **why** something is happening
- Code should tell **what** is happening
- Do not introduce comments where none are necessary
- Consider overview comments at the beginning of files
- Keep them free of implementation details
Avoid comments that need to be kept in sync with other parts of the code.
---
```c++
double Engine::updateTimestamp()
{
const auto now = Clock::now();
auto delta = now - m_timestampe;
m_timestampe = now;
// cap delta to 100 milliseconds
delta = std::min<Clock::duration>(delta, 50ms);
// …
}
```
Bad
---
```c++
double Engine::updateTimestamp()
{
const auto now = Clock::now();
auto delta = now - m_timestampe;
m_timestampe = now;
// Large time deltas can cause issues with physics simulations. Capping it
// here affects the whole simulation (not just physics) equally.
delta = std::min<Clock::duration>(delta, 50ms);
// …
}
```
Good
## Classes
- Put together what belongs together (data and functions)
- Adhere to separation of concerns
- Cleary communicate invariants
- Interfaces much bigger than your regular functions
- Make sure this trade-off is worth it!
- Limit the number of public methods (and variables)
- Critically think about the lifetime (and ownership) of instances
- Try to minimize mutability of held data
- Auto-generate getters / equality / hash / … **at compile-time**
---
```haskell
data Person = Person { firstName :: String
, lastName :: String
, age :: Int
}
deriving (Eq, Ord, Show, Read)
main = print $ Person "John" "Doe" 28
```
```
Person {firstName = "John", lastName = "Doe", age = 28}
```
# Testing
## V-Model
![Src: geeksforgeeks.org](images/v_model.png)
## How to write useful tests?
- Start with unit testing
- Focus on black-box testing
- Focus on testing complex logic
- Test error cases (negative tests)
- Observe test coverage
- Add integration tests
Consider test driven development (TDD).
---
- Use a testing framework
- Integrate it into the build system
- Make it easy to write and run tests!
- See Go for instance
---
```
make # builds the project
make test # runs all unit tests
scripts/run_integration tests
```
---
![Test Runner (Src: microsoft.com)](images/test_runner.png))
## Continuous Integration
- Let services (Jenkins, GitLab CI) build and test your code
- Reject merge-requests which break tests
- View this as a form of quality assurance
---
![Jobs](images/jenkins-1.png)
---
![Configurations](images/jenkins-2.png)
---
![Build History](images/jenkins-3.png)
---
![Pipelines](images/gitlab_ci.png)
---
![Pull Requests](images/github_ci.png)
# Profiling
## About Profiling
- Not that important right now
- Always measure!
- Are the values you measure meaningful?!
- Related multiple measurements over time
- Can be applied to multiple layers
- Micro-benchmarks (similar to unit tests)
- Overall benchmark
- Profile **release** builds!
---
![Benchmarks](images/benchmarks.png)
---
![Profiling](images/profiling.svg)
---
- Correctly present plots
- Labelled axes
- Grid lines
- Print data points (no need to connect them)
- Put some reference there
- Use a suitable scale
- Consider logarithmic axes
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment