Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ MARKDOWNS := $(shell find . -mindepth 2 -name '*.md' \
-not -path './node_modules/*' -not -path './$(OUTDIR)/*' | sed 's|^\./||' | sort)
PDFS := $(patsubst %.md,$(OUTDIR)/%.pdf,$(MARKDOWNS))
MDFLAGS := -f markdown -t beamer -s -H include.tex -V aspectratio:169 -V urlcolor:red
HTMLFLAGS := -f markdown -t html5 -s --template index.template.html --lua-filter index.lua
HTMLFLAGS := -f markdown -t html5 -s --template index.template.html --lua-filter index.lua \
--metadata title="Clean Code Slides"

.PHONY: all check clean format format-check lint

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

## Overview

Here you can find slides for Clean Code conversations or classes.
This repository contains slide decks for Clean Code conversations and classes.

## Development

Expand Down Expand Up @@ -85,7 +85,7 @@ here are the only place the curriculum is edited.
| 1 | Discussion | [Advanced TDD](advanced-tdd/01-advanced-tdd.md#warmup) |
| 2 | Coding Dojo | Roman Numerals Kata ([Python][roman-numerals-python], [C++][roman-numerals-cpp]) |
| 3 | Discussion | [Clean Tests](advanced-tdd/03-clean-tests.md#warmup) |
| 4 | Coding Dojo | Mars Rover Kata ([Python][mars-rover-python], [C++][mars-rover-python]) |
| 4 | Coding Dojo | Mars Rover Kata ([Python][mars-rover-python], [C++][mars-rover-cpp]) |
| 5 | Coding Mob | Mars Rover Kata ([Python][mars-rover-python], [C++][mars-rover-cpp]) |
| 6 | Discussion | Test Design / Test Process |
| 7 | Coding Dojo | Hyper-optimized Telemetry Kata ([Python][hyper-optimized-telemetry-python], [C++][hyper-optimized-telemetry-cpp]) |
Expand Down
2 changes: 1 addition & 1 deletion index.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

<title>Clean Code Slides</title>
<title>$pagetitle$</title>
<!-- Bootstrap -->
<link
rel="stylesheet"
Expand Down
2 changes: 1 addition & 1 deletion legacy-code/02-kata-identifying.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ private:

public:
static OrderProcessor* getInstance() {
if (instance == null) {
if (instance == nullptr) {
instance = new OrderProcessor();
}
return instance;
Expand Down
31 changes: 14 additions & 17 deletions legacy-code/03-safety-net.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ TEST_CASE("InvoiceCalculator preserves existing behavior") {
double result = calc.calculateTotal(items);

// Document the exact current behavior
REQUIRE(result == Approx(1850.95));
REQUIRE(result == Approx(2132.10));
// Note: This might not be correct behavior,
// but it's what the system currently does
}
Expand All @@ -76,6 +76,9 @@ TEST_CASE("InvoiceCalculator preserves existing behavior") {
## Python Example: Characterization Testing Technique

```python
import pytest


# Original Legacy Code
class TaxCalculator:
def calculate_tax(self, income, state):
Expand All @@ -98,26 +101,20 @@ class TaxCalculator:
def test_capture_current_tax_behavior():
calc = TaxCalculator()

# Test cases to capture current behavior
# Exact outputs captured from the current implementation
test_cases = [
(30000, "NY"),
(60000, "NY"),
(120000, "NY"),
(50000, "CA"),
(80000, "CA"),
(45000, "TX")
(30000, "NY", 1200),
(60000, "NY", 3600),
(120000, "NY", 10800),
(50000, "CA", 1500),
(80000, "CA", 5600),
(45000, "TX", 450),
]

# Store current behavior
results = {
case: calc.calculate_tax(*case)
for case in test_cases
}

# Verify behavior remains unchanged
for case in test_cases:
assert calc.calculate_tax(*case) == results[case], \
f"Behavior changed for {case}"
for income, state, expected in test_cases:
result = calc.calculate_tax(income, state)
assert result == pytest.approx(expected), f"Behavior changed for {(income, state)}"
```

# Key Techniques
Expand Down
21 changes: 12 additions & 9 deletions legacy-code/05-safe-changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,18 +147,21 @@ class Engine:
### Improved Code Example

```python
class LoggingEngine(Engine):
class LoggingEngine:
def __init__(self, engine):
self._engine = engine

def calculate_torque(self, rpm, throttle):
print(f"[LOG] Calculating torque: rpm={rpm}, throttle={throttle}")
torque = super().calculate_torque(rpm, throttle)
torque = self._engine.calculate_torque(rpm, throttle)
print(f"[LOG] Torque result: {torque}")
return torque
```

# Usage

```python
engine = LoggingEngine()
engine = LoggingEngine(Engine())
engine.calculate_torque(3000, 70)
```

Expand Down Expand Up @@ -200,12 +203,12 @@ car.drive()

# Comparison & Benefits

| Technique | Location <br/>of Change | Scope | Purpose | Risk | Code Impact |
| ------------- | ----------------------- | ---------------- | ------------------------------ | ---- | ------------------------- |
| Sprout Method | Same class | One method | Isolate new logic | Low | Add method,<br/> call it |
| Sprout Class | New class | Functionality | Extract cohesive<br/>behavior | Low | New class, <br/>inject it |
| Wrap Method | Same class | One method | Insert logic around<br/>method | Low | Rename + wrap<br/>method |
| Wrap Class | Subclass | Multiple methods | Modify/extend<br/>behavior | Med | New subclass<br/>created |
| Technique | Location <br/>of Change | Scope | Purpose | Risk | Code Impact |
| ------------- | ----------------------- | ---------------- | ------------------------------------ | ---- | ------------------------- |
| Sprout Method | Same class | One method | Isolate new logic | Low | Add method,<br/> call it |
| Sprout Class | New class | Functionality | Extract cohesive<br/>behavior | Low | New class, <br/>inject it |
| Wrap Method | Same class | One method | Insert logic around<br/>method | Low | Rename + wrap<br/>method |
| Wrap Class | Wrapper | Multiple methods | Add behavior around<br/>legacy class | Med | New wrapper<br/>created |

# Summary

Expand Down
6 changes: 3 additions & 3 deletions legacy-code/06-kata-sprouting-wrapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ class UserManager:
# Tasks

1. **Sprouting (20 min)**
- Add a new authentication method that uses a user database or config file
- Do not modify the original method
- Add new authentication logic in a separate method that uses a user database or config file
- Make only the minimal change to the original method needed to call the new method

2. **Wrapping (20 min)**
- Create a wrapper that logs authentication attempts
- Ensure the wrapper can be tested independently

3. **Testing (30 min)**
- Write tests for both the new and legacy authentication methods
- Write tests for both the new method and the original authentication entry point
- Validate that wrapping does not change legacy behavior

4. **Review (20 min)**
Expand Down