Clean code that works
-
Upload
attila-magyar -
Category
Technology
-
view
729 -
download
1
description
Transcript of Clean code that works
![Page 1: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/1.jpg)
Clean Code
BalaBit LLL, 2014. február 13.@athoshun
![Page 2: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/2.jpg)
Clean Code
”Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” / Martin Fowler
![Page 3: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/3.jpg)
Clean Code
”Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” / Martin Fowler
![Page 4: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/4.jpg)
Clean Code
”Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” / Martin Fowler
![Page 5: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/5.jpg)
Clean Code
Names, Comments, Structure, Object Oriented Programming, Functional Programming, Don't Repeat Yourself, Single Responsibility Principle, Open/Closed Principle, Liskov Substitution Principle, Interface Segregation Principle, Dependency Inversion Principle, Tell Don't Ask, Law of Demeter, Command-Query Separation, Composition over Inheritance, Screaming Architecture, Test First, Test Driven Development, Behavior Driven Development, Keep It Simple and Stupid, You Ain't Gonna Need It, Test doubles, Arrange-Act-Assert-Annihilate, Continuous Integration, Concurrency, Continuous Refactoring, Cyclomatic Complexity, NPath Complexity, …
![Page 6: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/6.jpg)
#minekvan
![Page 7: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/7.jpg)
Egyszer volt, hol nem volt...
Nagyvállalati alkalmazás
![Page 8: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/8.jpg)
Egyszer volt, hol nem volt...
Nagyvállalati alkalmazás Kell egy vékony kliens
![Page 9: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/9.jpg)
Egyszer volt, hol nem volt...
Nagyvállalati alkalmazás Kell egy vékony kliens, ami mobilneten
keresztül is tud frissülni
![Page 10: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/10.jpg)
Egyszer volt, hol nem volt...
![Page 11: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/11.jpg)
Egyszer volt, hol nem volt...
![Page 12: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/12.jpg)
Egyszer volt, hol nem volt...
![Page 13: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/13.jpg)
Egyszer volt, hol nem volt...
![Page 14: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/14.jpg)
Egyszer volt, hol nem volt...
![Page 15: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/15.jpg)
Egyszer volt, hol nem volt...
![Page 16: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/16.jpg)
Egyszer volt, hol nem volt...
![Page 17: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/17.jpg)
Egyszer volt, hol nem volt...
http://thedailywtf.com/Articles/The-Enterprise-Dependency.aspx
![Page 18: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/18.jpg)
Egyszer volt, hol nem volt...
![Page 19: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/19.jpg)
Egyszer volt, hol nem volt...
![Page 20: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/20.jpg)
Változtatás → kockázat
![Page 21: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/21.jpg)
Változtatás → kockázat
![Page 22: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/22.jpg)
Ki fogja maintainelni?
![Page 23: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/23.jpg)
Ki fogja maintainelni?
![Page 24: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/24.jpg)
Ki fogja maintainelni?
![Page 25: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/25.jpg)
![Page 26: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/26.jpg)
A jó kód dokumentálja magát
![Page 27: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/27.jpg)
A jó kód dokumentálja magát
while((i=++n)<=5000)for(a=0;a<i?a=a*8+i%8,i/=8,m=a==i|a/8==i,1:(n-++m||printf("%o\n",n))&&n%m;);
![Page 28: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/28.jpg)
A jó kód dokumentálja magát
while((i=++n)<=5000)for(a=0;a<i?a=a*8+i%8,i/=8,m=a==i|a/8==i,1:(n-++m||printf("%o\n",n))&&n%m;);
![Page 29: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/29.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { int a = 0, i = n, m; while (a < i) { a = a*8 + i%8; i /= 8; }
if (!((a == i) || (a/8 == i))) continue;
m = 2; while (0 != n%m) ++m;
if (m == n) printf("%o\n", n);}
![Page 30: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/30.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { if (!first_loop(n)) continue;
if (second_loop(n)) printf("%o\n", n);}int first_loop(int n) { int a = 0, i = n; while (a < i) { a = a*8 + i%8; i /= 8; } return (a == i) || (a/8 == i);}int second_loop(int n) { int m = 2; while (0 != n%m) ++m; return n == m;}
![Page 31: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/31.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { if (first_loop(n) && second_loop(n)) printf("%o\n", n);}
int first_loop(int n) { int a = 0, i = n; while (a < i) { a = a*8 + i%8; i /= 8; } return (a == i) || (a/8 == i);}int second_loop(int n) { int m = 2; while (0 != n%m) ++m; return n == m;}
![Page 32: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/32.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { if (is_palindromic_in_octal_base(n) && is_prime(n)) printf("%o\n", n);}int is_palindromic_in_octal_base(int number) { int reversed_digits = 0, remaining_digits = number;
while (reversed_digits < remaining_digits) { reversed_digits = reversed_digits * 8 + remaining_digits % 8; remaining_digits /= 8; }
return (reversed_digits == remaining_digits) || (reversed_digits / 8 == remaining_digits);}
int is_prime(int number) { int divisor_candidate = 2; while (0 != number % divisor_candidate) ++divisor_candidate; return number == divisor_candidate;}
![Page 33: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/33.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { if (is_palindromic_in_octal_base(n) && is_prime(n)) print_octal(n);}int is_palindromic_in_octal_base(int number) { int reversed_digits = 0, remaining_digits = number;
while (reversed_digits < remaining_digits) { int last_digit = get_last_octal_digit(remaining_digits); reversed_digits = append_octal_digit(reversed_digits, last_digit); remaining_digits = remove_last_octal_digit(remaining_digits); }
return (reversed_digits == remaining_digits) || (remove_last_octal_digit(reversed_digits) == remaining_digits);}
int is_prime(int number) { int divisor_candidate = 2; while (0 != number % divisor_candidate) ++divisor_candidate; return number == divisor_candidate;}
![Page 34: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/34.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { if (is_palindromic_in_octal_base(n) && is_prime(n)) print_octal(n);}int is_palindromic_in_octal_base(int number) { int reversed_digits = 0, remaining_digits = number;
while (reversed_digits < remaining_digits) { int last_digit = get_last_octal_digit(remaining_digits); reversed_digits = append_octal_digit(reversed_digits, last_digit); remaining_digits = remove_last_octal_digit(remaining_digits); }
return (reversed_digits == remaining_digits) || (remove_last_octal_digit(reversed_digits) == remaining_digits);}
int is_prime(int number) { int divisor_candidate = 2; while (0 != number % divisor_candidate) ++divisor_candidate; return number == divisor_candidate;}
![Page 35: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/35.jpg)
Optimalizáció != obfuszkációint n;for (n = 2; n <= 5000; ++n) { if (is_palindromic_in_octal_base(n) && is_prime(n)) print_octal(n);}int is_palindromic_in_octal_base(int number) { int reversed_digits = 0, remaining_digits = number;
while (reversed_digits < remaining_digits) { int last_digit = get_last_octal_digit(remaining_digits); reversed_digits = append_octal_digit(reversed_digits, last_digit); remaining_digits = remove_last_octal_digit(remaining_digits); }
return (reversed_digits == remaining_digits) || (remove_last_octal_digit(reversed_digits) == remaining_digits);}
int is_prime(int number) { int divisor_candidate = 2; while (0 != number % divisor_candidate) ++divisor_candidate; return number == divisor_candidate;}
O(n) → O(√n)
![Page 36: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/36.jpg)
Optimalizáció != obfuszkációint n;for (n = 2; n <= 5000; ++n) { if (is_palindromic_in_octal_base(n) && is_prime(n)) print_octal(n);}int is_palindromic_in_octal_base(int number) { int reversed_digits = 0, remaining_digits = number;
while (reversed_digits < remaining_digits) { int last_digit = get_last_octal_digit(remaining_digits); reversed_digits = append_octal_digit(reversed_digits, last_digit); remaining_digits = remove_last_octal_digit(remaining_digits); }
return (reversed_digits == remaining_digits) || (remove_last_octal_digit(reversed_digits) == remaining_digits);}
int is_prime(int number) { int divisor_candidate = 2; while (0 != number % divisor_candidate) ++divisor_candidate; return number == divisor_candidate;}
O(√n) → AKS
![Page 37: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/37.jpg)
A jó kód dokumentálja magát
Kommentek?
![Page 38: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/38.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { int a = 0, i = n, m; while (a < i) { a = a*8 + i%8; i /= 8; }
if (!((a == i) || (a/8 == i))) continue;
m = 2; while (0 != n%m) ++m;
if (m == n) printf("%o\n", n);}
![Page 39: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/39.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { int a = 0, i = n, m; while (a < i) { a = a*8 + i%8; i /= 8; }
// skip if not palindromic in octal base if (!((a == i) || (a/8 == i))) continue;
m = 2; while (0 != n%m) ++m;
// print if prime if (m == n) printf("%o\n", n);}
![Page 40: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/40.jpg)
A jó kód dokumentálja magátint n;for (n = 2; n <= 5000; ++n) { if (is_palindromic_in_octal_base(n) && is_prime(n)) print_octal(n);}
int n;for (n = 2; n <= 5000; ++n) { int a = 0, i = n, m; while (a < i) { a = a*8 + i%8; i /= 8; }
// skip if not palindromic in octal base if (!((a == i) || (a/8 == i))) continue;
m = 2; while (0 != n%m) ++m;
// print if prime if (m == n) printf("%o\n", n);}
![Page 41: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/41.jpg)
Kommentek
public function registerArgumentTransformer(ArgumentTransformer $transformer){ $this->argumentTransformers[] = $transformer;}
![Page 42: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/42.jpg)
Kommentek
/** * Registers new argument transformer. * * @param ArgumentTransformer $transformer */public function registerArgumentTransformer(ArgumentTransformer $transformer){ $this->argumentTransformers[] = $transformer;}
![Page 43: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/43.jpg)
Kommentek
/** * Registers new argument transformer. * * @param ArgumentTransformer $transformer */public function registerArgumentTransformer(ArgumentTransformer $transformer){ $this->argumentTransformers[] = $transformer;}
![Page 44: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/44.jpg)
Kommentek
/** * Registers new argument transformer. * * @param ArgumentTransformer $transformer */public function registerArgumentTransformer(ArgumentTransformer $transformer){ $this->argumentTransformers[] = $transformer;}
![Page 45: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/45.jpg)
Kommentek
/** * Registers new argument transformer. * * @param ArgumentTransformer $transformer */public function registerArgumentTransformer(ArgumentTransformer $transformer){ $this->argumentTransformers[] = $transformer;}
![Page 46: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/46.jpg)
Kommentek
/** * Registers new argument transformer. * * @param ArgumentTransformer $transformer */public function registerArgumentTransformer(ArgumentTransformer $transformer){ $this->argumentTransformers[] = $transformer;}
This method registers anargument transformer!
![Page 47: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/47.jpg)
Kommentek
def store_puppy(self): # self.puppy_source is already opened # by some_unrelated_fucntion() puppy = self.puppy_source.read() self.storage.store(puppy) self.puppy_source.close()
![Page 48: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/48.jpg)
Kommentek
def store_puppy(self): # self.puppy_source is already opened # by some_unrelated_fucntion() puppy = self.puppy_source.read() self.storage.store(puppy) self.puppy_source.close()
![Page 49: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/49.jpg)
Temporal coupling
open(), close()
connect(), disconnect()
Sorrendi függőség függvények között
![Page 50: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/50.jpg)
Temporal coupling
open(), close()
connect(), disconnect()
Sorrendi függőség függvények között Könnyű elrontani (pl. exception)
![Page 51: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/51.jpg)
Temporal coupling
def store_puppy(self): self.puppy_source.open()
puppy = self.puppy_source.read() self.storage.store(puppy)
self.puppy_source.close()
![Page 52: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/52.jpg)
Temporal coupling
def store_puppy(self): self.puppy_source.open()
try: puppy = self.puppy_source.read() self.storage.store(puppy)
finally: self.puppy_source.close()
![Page 53: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/53.jpg)
Temporal coupling
def store_puppy(self): with self.puppy_source: puppy = self.puppy_source.read() self.storage.store(puppy)
# puppy_source.__enter__,# puppy_source.__exit__
![Page 54: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/54.jpg)
Temporal coupling
Általános megoldás?
![Page 55: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/55.jpg)
Temporal couplinginterface PuppySourceCommand { public function run(PuppySource $ps);}public function withPuppySource(PuppySourceCommand $command){ $this->puppy_source->open();
try { $command->run($this->puppy_source); } finally { $this->puppy_source->close(); }}
![Page 56: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/56.jpg)
Temporal couplinginterface PuppySourceCommand { public function run(PuppySource $ps);}public function withPuppySource(PuppySourceCommand $command){ $this->puppy_source->open();
try { $command->run($this->puppy_source); } finally { $this->puppy_source->close(); }} class StorePuppyCommand
implements PuppySourceCommand{ public function run(PuppySource $ps) { $puppy = $ps->read(); $this->storage->store($puppy); }}
![Page 57: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/57.jpg)
Temporal coupling
public function withPuppySource(callable $command){ $this->puppy_source->open();
try { $command($this->puppy_source); } finally { $this->puppy_source->close(); }}
$pscm->withPuppySource( function (PuppySource $ps) { $puppy = $ps->read(); $this->storage->store($puppy); });
![Page 58: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/58.jpg)
Nevek
Cél/szándék vs. implementáció Névterek, osztályok: általában főnevek Változók: főnevek, predikátumok Függvények, metódusok:
Általában igével kezdődnek (readLine(), generateReport(), getUser())
Boolean fv-ek: predikátumok (isLeapYear(), hasEntries())
Egyebek: sin(), cos(), DSL-ek, stb.
![Page 59: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/59.jpg)
Nevek
function main(){ tag_file="$1" source_file="$2"
if can_be_updated "$tag_file" then update_tag_file "$tag_file" "$source_file" else rebuild_tag_file "$tag_file" fi}
![Page 60: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/60.jpg)
Nevek
Kimondható nevek! Tömörség != rövidség
strpbrk(), strverscmp()
Név hossza vs. láthatóság: Függény, metódus: nagy scope → tömör név Változó: nagy scope → részletes név
![Page 61: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/61.jpg)
Smurf naming convention
![Page 62: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/62.jpg)
Smurf naming convention
![Page 63: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/63.jpg)
Smurf naming convention
Hungarian notation: MessageBox(hwnd, szMsg, "Hello", MB_OK);
![Page 64: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/64.jpg)
Smurf naming convention
Hungarian notation: MessageBox(hwnd, szMsg, "Hello", MB_OK);
$this>m_session
![Page 65: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/65.jpg)
Smurf naming convention
Hungarian notation: MessageBox(hwnd, szMsg, "Hello", MB_OK);
$this>m_session
Abstract, Interface, Impl
![Page 66: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/66.jpg)
Smurf naming convention
Hungarian notation: MessageBox(hwnd, szMsg, "Hello", MB_OK);
$this>m_session
Abstract, Interface, Impl
function findBoundingBox(ShapeInterface $s){ // ...}
![Page 67: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/67.jpg)
Smurf naming convention
Hungarian notation: MessageBox(hwnd, szMsg, "Hello", MB_OK);
$this>m_session
Abstract, Interface, Impl
function findBoundingBox(AbstractShape $s){ // ...}
![Page 68: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/68.jpg)
Smurf naming convention
Hungarian notation: MessageBox(hwnd, szMsg, "Hello", MB_OK);
$this>m_session
Abstract, Interface, Impl
function findBoundingBox(Shape $s){ // ...}
![Page 69: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/69.jpg)
Meglepetések
def getFreeDiskSpace(): os.system("rm -rf /") return getDiskSize()
![Page 70: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/70.jpg)
Meglepetések
Command-query separation: asking a question should not change the answer!
def getFreeDiskSpace(): os.system("rm -rf /") return getDiskSize()
![Page 71: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/71.jpg)
Meglepetések
Command-query separation: vagy változtass állapotot, vagy adj vissza értéket, de a kettőt egyszerre ne csináld!
def getFreeDiskSpace(): os.system("rm -rf /") return getDiskSize()
![Page 72: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/72.jpg)
Meglepetések
Command-query separation: vagy változtass állapotot, vagy adj vissza értéket, de a kettőt egyszerre ne csináld!
Párhuzamossággal vigyázni!
def getFreeDiskSpace(): os.system("rm -rf /") return getDiskSize()
![Page 73: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/73.jpg)
Method chaining, fluent interfaces
customer.newOrder() .with(6, "TAL") .with(5, "HPK").skippable() .with(3, "LGV") .priorityRush();
mock.expects(once()) .method("m") .with( or( stringContains("hello"), stringContains("howdy")) );
![Page 74: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/74.jpg)
Be positive
def isNotGreaterThan(a, b): if not (a < b): return False else: return True
![Page 75: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/75.jpg)
Be positive
def isNotGreaterThan(a, b): if a < b: return True else: return False
![Page 76: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/76.jpg)
Be positive
def isNotGreaterThan(a, b): return a < b:
![Page 77: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/77.jpg)
Be positive
def isLessThan(a, b): return a < b:
![Page 78: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/78.jpg)
Nevek
Ha nehéz elnevezni, akkor túl sokat tud
![Page 79: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/79.jpg)
Nevek
Ha nehéz elnevezni, akkor túl sokat tud – Single Responsibility Principle
![Page 80: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/80.jpg)
Tipikus szoftver
Web framework
SQL adatbázis
NoSQL
XML
Business logic
![Page 81: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/81.jpg)
Tipikus szoftver
Web framework
SQL adatbázis
NoSQL
XML
Business logic
GUI tesztek
Integration tesztek
Unittesztek
![Page 82: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/82.jpg)
SOLID
SRP: Single Responsibility Principle
OCP: Open/Closed Principle Új viselkedés ↔ új kód (vs. meglévő kód reszelése)
LSP: Liskov Substitution Principle Téglalap-e a négyzet?
ISP: Interface Segregation Principle Ne függj olyan dolgoktól, amiket nem használsz!
DIP: Depencency Inversion Principle Ne az absztrakt logika függjön a konkrétumoktól!
![Page 83: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/83.jpg)
Feladat
Jelöljük meg a standard inputon érkező sorokban a számokat [, ] jelekkel!
![Page 84: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/84.jpg)
SRP
Jelöljük meg a standard inputon érkező sorokban a számokat [, ] jelekkel!
while (!feof(STDIN)) { print preg_replace( "/(\\d+)/", "[\\1]", fgets(STDIN) );}
![Page 85: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/85.jpg)
SRP
Hány különböző dologgal foglalkozik ez a kód?
while (!feof(STDIN)) { print preg_replace( "/(\\d+)/", "[\\1]", fgets(STDIN) );}
![Page 86: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/86.jpg)
SRP
Hány különböző absztrakció jelenik meg benne?
while (!feof(STDIN)) { print preg_replace( "/(\\d+)/", "[\\1]", fgets(STDIN) );}
![Page 87: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/87.jpg)
SRP
Hány különböző absztrakció jelenik meg benne?function highlightNumbers($text){ return preg_replace( "/(\\d+)/", "[\\1]", $text );}while (!feof(STDIN)) { print highlightNumbers(fgets(STDIN));}
![Page 88: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/88.jpg)
OCP
Open for extension, Closed for modification
class NumberHighlighterApplication { public function run() { while (!feof(STDIN)) { print highlightNumbers( fgets(STDIN) ); } }}
![Page 89: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/89.jpg)
OCP
Open for extension, Closed for modification Új feature → új kód!class NumberHighlighterApplication { public function run() { while (!feof(STDIN)) { print highlightNumbers( fgets(STDIN) ); } }}
![Page 90: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/90.jpg)
OCP
Open for extension, Closed for modification FR: tetszőleges file-t is kezeljen!class NumberHighlighterApplication { public function run() { while (!feof(STDIN)) { print highlightNumbers( fgets(STDIN) ); } }}
![Page 91: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/91.jpg)
OCP
Open for extension, Closed for modificationclass NumberHighlighterApplication { public function run($stream) { while (!feof($stream)) print highlightNumbers(fgets($stream)); }}
class StandardInputNumberHighlighterApplication extends NumberHighlighterApplication { public function run() { parent::run(STDIN); }}
![Page 92: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/92.jpg)
OCP
Open for extension, Closed for modificationclass NumberHighlighterApplication { public function run($stream) { while (!feof($stream)) print highlightNumbers(fgets($stream)); }}
class FileContentsNumberHighlighterApplication extends NumberHighlighterApplication { public function run($filename) { $stream = fopen($filename, "r"); parent::run($stream); fclose($stream); }}
![Page 93: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/93.jpg)
OCP
Open for extension, Closed for modificationclass NumberHighlighterApplication { public function run($stream) { while (!feof($stream)) print highlightNumbers(fgets($stream)); }}
class FileContentsNumberHighlighterApplication extends NumberHighlighterApplication { public function run($filename) { $stream = fopen($filename, "r"); parent::run($stream); fclose($stream); }}
DON'T TRY THISAT HOME!
![Page 94: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/94.jpg)
LSP
S osztály a T osztályból származik → T példányai legyenek helyettesíthetők S példányaival
![Page 95: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/95.jpg)
LSP
S osztály a T osztályból származik → T példányai legyenek helyettesíthetők S példányaival
class NumberHighlighterApplication { public function run($stream) { while (!feof($stream)) print highlightNumbers(fgets($stream)); }}
class StandardInputNumberHighlighterApplication extends NumberHighlighterApplication { public function run() { parent::run(STDIN); }}
![Page 96: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/96.jpg)
LSP
S osztály a T osztályból származik → T példányai legyenek helyettesíthetők S példányaival
class NumberHighlighterApplication { public function run($stream) { while (!feof($stream)) print highlightNumbers(fgets($stream)); }}
class StandardInputNumberHighlighterApplication { public function run() { new NumberHighlighterApplication() ->run(STDIN); }}
![Page 97: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/97.jpg)
LSP
S osztály a T osztályból származik → T példányai legyenek helyettesíthetők S példányaival
class Rectangle { /* ... */ }class Square extends Rectangle { /* ... */ }
public function foo(Rectangle $r){ // ... $r->setWidth($new_width); $r->setHeight($new_height); // ...}
![Page 98: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/98.jpg)
LSP
S osztály a T osztályból származik → T példányai legyenek helyettesíthetők S példányaival
![Page 99: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/99.jpg)
LSP
S osztály a T osztályból származik → T példányai legyenek helyettesíthetők S példányaival
class ComplexNumber { private $real, $imaginary;
public function __construct($real, $imaginary) { $this->real = new RealNumber($real); $this->imaginary = new RealNumber($imaginary); }}class RealNumber extends ComplexNumber { private $number;
public function __construct($number) { parent::__construct($number, 0); }}new ComplexNumber(0, 0);
![Page 100: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/100.jpg)
LSP
S osztály a T osztályból származik → T példányai legyenek helyettesíthetők S példányaivalPHP Fatal error: Maximum function nesting level of '100'reached, aborting! in ~/projects/numbers.php on line 15PHP Stack trace:PHP 1. {main}() ~/projects/numbers.php:0PHP 2. ComplexNumber->__construct() ~/projects/numbers.php:18PHP 3. RealNumber->__construct() ~/projects/numbers.php:7PHP 4. ComplexNumber->__construct() ~/projects/numbers.php:15PHP 5. RealNumber->__construct() ~/projects/numbers.php:7PHP 6. ComplexNumber->__construct() ~/projects/numbers.php:15PHP 7. RealNumber->__construct() ~/projects/numbers.php:7PHP 8. ComplexNumber->__construct() ~/projects/numbers.php:15PHP 9. RealNumber->__construct() ~/projects/numbers.php:7PHP 10. ComplexNumber->__construct() ~/projects/numbers.php:15PHP 11. RealNumber->__construct() ~/projects/numbers.php:7PHP 12. ComplexNumber->__construct() ~/projects/numbers.php:15PHP 13. RealNumber->__construct() ~/projects/numbers.php:7...
![Page 101: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/101.jpg)
DIP
Dependency Inversion Principle
class NumberHighlighterApplication{ public function run($stream) { while (!feof($stream)) { $line = fgets($stream); print highlightNumbers($line); } }}
![Page 102: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/102.jpg)
DIP
FR: EBCDIC file-t is tudjon olvasni!
class NumberHighlighterApplication{ public function run($stream) { while (!feof($stream)) { $line = fgets($stream); print highlightNumbers($line); } }}
![Page 103: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/103.jpg)
DIP
Abstractions should never depend on concretions.
class NumberHighlighterApplication{ public function run($stream) { while (!feof($stream)) { $line = fgets($stream); print highlightNumbers($line); } }}
![Page 104: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/104.jpg)
DIP
Abstractions should never depend on concretions.
NumberHighlighterApplication
StandardInput
Business logic
![Page 105: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/105.jpg)
DIP
Abstractions should never depend on concretions.
NumberHighlighterApplication
IOStream
StandardInput
Business logic
![Page 106: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/106.jpg)
DIP
Abstractions should never depend on concretions.interface IOStream { public function open(); public function eof(); public function readLine(); public function write($text); public function close();}class NumberHighlighterApplication { private $input, $output;
public function __construct(IOStream $i, IOStream $o) { $this->input = $i; $this->output = $o; }
public function run() { while (!$this->input->eof()) { $line = $this->input->readLine(); $this->output->write(highlightNumbers($line)); } }}
![Page 107: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/107.jpg)
DIP
Pl: Dependency Injectioninterface IOStream { public function open(); public function eof(); public function readLine(); public function write($text); public function close();}class NumberHighlighterApplication { private $input, $output;
public function __construct(IOStream $i, IOStream $o) { $this->input = $i; $this->output = $o; }
public function run() { while (!$this->input->eof()) { $line = $this->input->readLine(); $this->output->write(highlightNumbers($line)); } }}
![Page 108: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/108.jpg)
DIP
NEM a DI containert injektáljuk az osztályba!interface IOStream { public function open(); public function eof(); public function readLine(); public function write($text); public function close();}class NumberHighlighterApplication { private $input, $output;
public function __construct(IOStream $i, IOStream $o) { $this->input = $i; $this->output = $o; }
public function run() { while (!$this->input->eof()) { $line = $this->input->readLine(); $this->output->write(highlightNumbers($line)); } }}
![Page 109: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/109.jpg)
ISP
FR: JSON-ból olvasson, MySQL-be írjon!interface IOStream { public function open(); public function eof(); public function readLine(); public function write($text); public function close();}class NumberHighlighterApplication { private $input, $output;
public function __construct(IOStream $i, IOStream $o) { $this->input = $i; $this->output = $o; }
public function run() { while (!$this->input->eof()) { $line = $this->input->readLine(); $this->output->write(highlightNumbers($line)); } }}
![Page 110: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/110.jpg)
ISP
Ne függj olyan olyasmitől, amit nem használsz!interface IOStream { public function open(); public function eof(); public function readLine(); public function write($text); public function close();}class NumberHighlighterApplication { private $input, $output;
public function __construct(IOStream $i, IOStream $o) { $this->input = $i; $this->output = $o; }
public function run() { while (!$this->input->eof()) { $line = $this->input->readLine(); $this->output->write(highlightNumbers($line)); } }}
![Page 111: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/111.jpg)
ISP
Ne függj olyan olyasmitől, amit nem használsz!interface Input { public function hasMore(); public function read();}interface Output { public function write($text);}class NumberHighlighterApplication { private $input, $output;
public function __construct(Input $i, Output $o) { $this->input = $i; $this->output = $o; }
public function run() { while ($this->input->hasMore()) { $text = $this->input->read(); $this->output->write(highlightNumbers($text)); } }}
![Page 112: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/112.jpg)
Mit adtak nekünk a SOLID elvek?
Business Logic
Plain objects (domain model, use cases)Interfaces (integration)
SQL database XML
Web framework Desktop GUI frameworkCLI, getopt, etc.
NoSQL database
Thin integration Thin integrationThin integration
Thin integration Thin integration Thin integration
![Page 113: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/113.jpg)
Mit adtak nekünk a SOLID elvek?
Business Logic
Plain objects (domain model, use cases)Interfaces (integration)
SQL database XML
Web framework Desktop GUI frameworkCLI, getopt, etc.
NoSQL database
Thin integration Thin integrationThin integration
Thin integration Thin integration Thin integration
GUItesztek
Integration tesztek
Unit tesztek
![Page 114: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/114.jpg)
Tesztekinterface Input interface Output{ { public function hasMore(); public function write($text); public function read(); }}class NumberHighlighterApplication{ private $input, $output;
public function __construct(Input $i, Output $o) { $this->input = $i; $this->output = $o; }
public function run() { while ($this->input->hasMore()) { $text = $this->input->read(); $highlighted = highlightNumbers($text); $this->output->write($highlighted); } }}
![Page 115: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/115.jpg)
Test doubleclass FakeInput implements Input{ private $lines; private $next_line_index;
public function __construct(array $lines) { $this->lines = $lines; $this->next_line_index = 0; }
public function read() { return $this->lines[$this->next_line_index++]; }
public function hasMore() { return $this->next_line_index < count($this->lines); }}
![Page 116: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/116.jpg)
Test doubleclass FakeOutput implements Output{ private $lines;
public function __construct() { $this->lines = array(); }
public function write($text) { $this->lines[] = $text; }
public function getWrittenLines() { return $this->lines; }}
![Page 117: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/117.jpg)
Test double
private function highlight(array $input_lines){ $input = new FakeInput($input_lines); $output = new FakeOutput();
$application = new NumberHighlighterApplication($input, $output); $application->run();
return $output->getWrittenLines();}
![Page 118: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/118.jpg)
Test double
private function assertHighlihtedLines(array $input, array $expected){ $this->assertEquals($expected, $this->highlight($input));}
private function highlight(array $input_lines){ $input = new FakeInput($input_lines); $output = new FakeOutput();
$application = new NumberHighlighterApplication($input, $output); $application->run();
return $output->getWrittenLines();}
![Page 119: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/119.jpg)
Test doubleprivate function assertHighlightedLine($input, $expected){ $this->assertHighlightedLines(array($input), array($expected));}
private function assertHighlihtedLines(array $input, array $expected){ $this->assertEquals($expected, $this->highlight($input));}
private function highlight(array $input_lines){ $input = new FakeInput($input_lines); $output = new FakeOutput();
$application = new NumberHighlighterApplication($input, $output); $application->run();
return $output->getWrittenLines();}
![Page 120: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/120.jpg)
Unit tesztfunction testWhenThereIsNoNumberInALineThenItIsUnchanged(){ $this->assertHighlihtedLine("No numbers", "No numbers");}
function testWhenThereIsANumberInALineThenItIsSurroundedWithBrackets(){ $this->assertHighlihtedLine("42", "[42]");}
function testWhenThereAreManyNumbersInALineThenAllAreSurroundedWithBrackets(){ $this->assertHighlihtedLine("42 123", "[42] [123]");}
function testNonNumericTextIsUnchanged(){ $this->assertHighlihtedLine("A 42 B", "A [42] B");}
function testNumbersAreHighlightedInAllLines(){ $this->assertHighlihtedLines( array("A 42 B", "C 123 D"), array("A [42] B", "C [123] D") );}
![Page 121: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/121.jpg)
(majdnem) Unit tesztfunction testWhenThereIsNoNumberInALineThenItIsUnchanged(){ $this->assertHighlihtedLine("No numbers", "No numbers");}
function testWhenThereIsANumberInALineThenItIsSurroundedWithBrackets(){ $this->assertHighlihtedLine("42", "[42]");}
function testWhenThereAreManyNumbersInALineThenAllAreSurroundedWithBrackets(){ $this->assertHighlihtedLine("42 123", "[42] [123]");}
function testNonNumericTextIsUnchanged(){ $this->assertHighlihtedLine("A 42 B", "A [42] B");}
function testNumbersAreHighlightedInAllLines(){ $this->assertHighlihtedLines( array("A 42 B", "C 123 D"), array("A [42] B", "C [123] D") );}
![Page 122: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/122.jpg)
Tesztek
Cél: segíteni a refaktorálást
![Page 123: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/123.jpg)
Tesztek
Cél: segíteni a refaktorálástfunction testWhenThereIsNoNumberInALineThenItIsUnchanged() { $input = new FakeInput(array("No numbers")); $output = new FakeOutput(); $application = new NumberHighlighterApplication($input, $output); $application->run(); $this->assertEquals(array("No numbers"), $output->getWrittenLines());}function testWhenThereIsANumberInALineThenItIsSurroundedWithBrackets() { $input = new FakeInput(array("42")); $output = new FakeOutput(); $application = new NumberHighlighterApplication($input, $output); $application->run(); $this->assertEquals(array("[42]"), $output->getWrittenLines());}function testWhenThereAreManyNumbersInALineThenAllAreSurroundedWithBrackets() { $input = new FakeInput(array("42 123")); $output = new FakeOutput(); $application = new NumberHighlighterApplication($input, $output); $application->run(); $this->assertEquals(array("[42] [123]"), $output->getWrittenLines());}function testNonNumericTextIsUnchanged() { $input = new FakeInput(array("A 42 B")); $output = new FakeOutput(); $application = new NumberHighlighterApplication($input, $output); $application->run(); $this->assertEquals(array("A [42] B"), $output->getWrittenLines());}
![Page 124: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/124.jpg)
Tesztek
Cél: segíteni a refaktorálástfunction testWhenThereIsNoNumberInALineThenItIsUnchanged(){ $this->assertHighlihtedLine("No numbers", "No numbers");}
function testWhenThereIsANumberInALineThenItIsSurroundedWithBrackets(){ $this->assertHighlihtedLine("42", "[42]");}
function testWhenThereAreManyNumbersInALineThenAllAreSurroundedWithBrackets(){ $this->assertHighlihtedLine("42 123", "[42] [123]");}
function testNonNumericTextIsUnchanged(){ $this->assertHighlihtedLine("A 42 B", "A [42] B");}
![Page 125: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/125.jpg)
Tesztek
Cél: segíteni a refaktorálást
private function highlight(array $input_lines){ $input = new FakeInput($input_lines); $output = new FakeOutput();
$application = new NumberHighlighterApplication($input, $output); $application->run();
return $output->getWrittenLines();}
![Page 126: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/126.jpg)
Tesztek
Cél: segíteni a refaktorálást
$input = $this->getMock("Input");$input->expects($this->exactly(2)) ->method("hasMore") ->will($this->onConsecutiveCalls(array(true, false)));$input->expects($this->once()) ->method("read") ->will($this->returnValue("A 42 B"));
$output = $this->getMock("Output");$output->expects($this->once()) ->method("write") ->with("A [42] B");
$application = new NumberHighlighterApplication($input, $output);$application->run();
![Page 127: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/127.jpg)
Tesztek
Az olvashatóság követelménye a tesztekre is vonatkozik!
![Page 128: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/128.jpg)
Tesztek
Az olvashatóság követelménye a tesztekre is vonatkozik!
Plusz még néhány: Gyors! Élő példakód! Stabilitás Független tesztek Megbízhatóság Reprodukálhatóság
![Page 129: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/129.jpg)
Tesztek
testLoginValidtestLoginInvalid
![Page 130: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/130.jpg)
Tesztek
testLoginValidtestLoginInvalid
testEmptyUsernameTriggersErrortestWrongUsernameTriggersErrortestEmptyPasswordTriggersErrortestWrongPasswordTriggersErrortestWhenCredentialsAreCorrectThenUserIsLoggedIntestSessionFixationAttacksArePreventedByRegeneratingTheId
![Page 131: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/131.jpg)
Tesztek
Honnan tudom, hogy a tesztem tényleg vizsgál valamit?
Nézd meg, hogyan fail-el!
![Page 132: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/132.jpg)
Tesztek
Honnan tudom, hogy a tesztem tényleg vizsgál valamit?
Nézd meg, hogyan fail-el! Mutation testing?
![Page 133: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/133.jpg)
Tesztek
Honnan tudom, hogy a tesztem tényleg vizsgál valamit?
Nézd meg, hogyan fail-el! Mutation testing? Test-driven development!
![Page 134: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/134.jpg)
TDD
Írj annyi tesztet, ami éppen elég a FAIL-hez! Írj annyi kódot, ami éppen elég a PASS-hez! Refaktorálj!
![Page 135: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/135.jpg)
TDD
Írj annyi tesztet, ami éppen elég a FAIL-hez! Írj annyi kódot, ami éppen elég a PASS-hez! Refaktorálj! Kis lépések → kevésbé fájdalmas visszalépni
és más irányba indulni Interruptok, context switch-ek kevésbé fájnak Ha minden tesztet láttál törni, megbízhatsz
bennük
![Page 136: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/136.jpg)
TDD
OpenAcademy, 2012. tavasz: http://tinyurl.com/openacademy-tdd
![Page 137: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/137.jpg)
Tesztek
Viselkedéseket, követelményeket tesztelj, ne metódusokat!
public function testHighlight(){ $input = new FakeInput( array("No numbers", "42", "A 42 B", "A 42 B 123 C") ); $output = new FakeOutput();
$application = new NumberHighlighterApplication($input,$output); $application->run();
$this->assertEquals( array("No numbers", "[42]", "A [42] B", "A [42] B [123] C"), $output->getWrittenLines() );}
![Page 138: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/138.jpg)
Tesztek
Viselkedéseket, követelményeket tesztelj, ne metódusokat!
function testWhenThereIsNoNumberInALineThenItIsUnchanged(){ $this->assertHighlihtedLine("No numbers", "No numbers");}
function testWhenThereIsANumberInALineThenItIsSurroundedWithBrackets(){ $this->assertHighlihtedLine("42", "[42]");}
function testWhenThereAreManyNumbersInALineThenAllAreSurroundedWithBrackets(){ $this->assertHighlihtedLine("42 123", "[42] [123]");}
function testNonNumericTextIsUnchanged(){ $this->assertHighlihtedLine("A 42 B", "A [42] B");}
![Page 139: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/139.jpg)
Tesztek
A tesztek design problémákra figyelmeztetnekclass Login { // ... public function perform($username, $password) { $account = $this->findAccountByUsername($username);
if ($account->isValidPassword($password)) return $this->makeSuccessResponse($username, $account);
return $this->makeErrorResponse($username); } private function findAccountByUsername($username) { $account_data = $this->sql->query( "SELECT * FROM users WHERE ...", array("username" => $username) ); // ... return new UserAccount($account_data); }}
![Page 140: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/140.jpg)
Tesztek
A tesztek design problémákra figyelmeztetnekclass Login { // ... public function perform($username, $password) { $account = $this->findAccountByUsername($username);
if ($account->isValidPassword($password)) return $this->makeSuccessResponse($username, $account);
return $this->makeErrorResponse($username); } protected function findAccountByUsername($username) { $account_data = $this->sql->query( "SELECT * FROM users WHERE ...", array("username" => $username) ); // ... return new UserAccount($account_data); }}
![Page 141: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/141.jpg)
Tesztek
A tesztek design problémákra figyelmeztetnek
class TestableLogin extends Login{ protected function findAccountByUsername($username) { return new UserAccount(array("Alice", "5af6b73c3...")); }}
![Page 142: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/142.jpg)
Tesztek
A tesztek design problémákra figyelmeztetnekclass Login { // ... public function perform($username, $password) { $account = $this->findAccountByUsername($username);
if ($account->isValidPassword($password)) return $this->makeSuccessResponse($username, $account);
return $this->makeErrorResponse($username); } private function findAccountByUsername($username) { $account_data = $this->sql->query( "SELECT * FROM users WHERE ...", array("username" => $username) ); // ... return new UserAccount($account_data); }}
![Page 143: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/143.jpg)
Tesztek
A tesztek design problémákra figyelmeztetnekclass Login { // ... public function perform($username, $password) { $account = $this->findAccountByUsername($username);
if ($account->isValidPassword($password)) return $this->makeSuccessResponse($username, $account);
return $this->makeErrorResponse($username); } private function findAccountByUsername($username) { $account_data = $this->sql->query( "SELECT * FROM users WHERE ...", array("username" => $username) ); // ... return new UserAccount($account_data); }}
High level policy
Low level detail
![Page 144: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/144.jpg)
Tesztek
A tesztek design problémákra figyelmeztetnekinterface UserAccountRepository { public function findByUsername($username);}class Login { private $accounts;
public function __construct(UserAccountRepository $r) { $this->accounts = $r; }
public function perform($username, $password) { $account = $this->accounts->findByUsername($username);
if ($account->isValidPassword($password)) return $this->makeSuccessResponse($username, $account);
return $this->makeErrorResponse($username); }}
![Page 145: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/145.jpg)
Tesztek
A tesztek design problémákra figyelmeztetnekinterface UserAccountRepository { public function findByUsername($username);}
class SqlUserAccountRepository implements UserAccountRepository{ public function findByUsername($username) { $account_data = $this->sql->query( "SELECT * FROM users WHERE ...", array("username" => $username) ); // ... return new UserAccount($account_data); }}
![Page 146: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/146.jpg)
Bővebben
![Page 147: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/147.jpg)
Bővebben http://cleancoders.com
Robert C. Martin: Architecture the Lost Years (1:07)http://www.youtube.com/watch?v=WpkDN78P884
Gary Bernhardt: Fast Test, Slow Test (0:32)http://www.youtube.com/watch?v=RAxiiRPHS9k
Gary Bernhardt: Boundaries (0:46)http://www.youtube.com/watch?v=yTkzNHF6rMs
![Page 148: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/148.jpg)
Bővebben http://blog.rocketpoweredjetpants.com/2014/01/a-ranty-and-dogmatic-troll-
masquerading.html http://martinfowler.com/articles/dipInTheWild.html http://googletesting.blogspot.hu/2008/07/breaking-law-of-demeter-is-like-looking.html?
spref=tw http://ariya.ofilabs.com/2011/08/hall-of-api-shame-boolean-trap.html http://googletesting.blogspot.hu/2013/08/testing-on-toilet-test-behavior-not.html?spref=tw https://www.facebook.com/notes/kent-beck/shorts-not-always-sweet-the-case-for-long-test-
names/564493423583526 http://dannorth.net/introducing-bdd/ https://michaelfeathers.silvrback.com/when-it-s-okay-for-a-method-to-do-nothing http://googletesting.blogspot.hu/2008/07/how-to-write-3v1l-untestable-code.html?spref=tw http://googletesting.blogspot.hu/2013/05/testing-on-toilet-dont-overuse-mocks.html?
spref=tw http://codemanship.co.uk/parlezuml/blog/?postid=1170 http://thedailywtf.com/Articles/The-Enterprise-Dependency.aspx https://athos.blogs.balabit.com/2011/11/ioccc-vs-clean-code/ http://martinfowler.com/bliki/FluentInterface.html
![Page 149: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/149.jpg)
Coding kata
![Page 150: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/150.jpg)
Coding kata
![Page 151: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/151.jpg)
Coding kata
FizzBuzz Prime factors Bowling game Római számok → arab számok WordWrap Conway's Game of Life … http://en.wikipedia.org/wiki/Kata_(programming)
![Page 152: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/152.jpg)
Code Retreat
Február 22. (Legacy CodeRetreat) http://www.meetup.com/Coderetreat-Budapest/events/166131862/
![Page 153: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/153.jpg)
Kérdés?
http://www.slideshare.net/athoshun
![Page 154: Clean code that works](https://reader033.fdocuments.in/reader033/viewer/2022050817/554a1e21b4c9058c5d8b5643/html5/thumbnails/154.jpg)
Köszönöm a figyelmet!
http://www.slideshare.net/athoshun