Object Calisthenics (ZOSIA, Przesieka 2017 PL)
-
Upload
grzegorz-byrka -
Category
Software
-
view
183 -
download
4
Transcript of Object Calisthenics (ZOSIA, Przesieka 2017 PL)
We design and developcomplex business applications
Object Calisthenics
czyli jak uczynić nasz kod czytleniejszym
Grzegorz Byrka
ZOSIA 2017
Dlaczego warto pisać kod dobrej jakości? (poza tym, że nam za to płacą)
3
● Poprawa czytelności i zrozumiałości
• Ułatwione wdrażanie nowych osób do zespołu• Łatwiejsze zarządzanie i modyfikowanie istniejących funkcjonalności
Dlaczego warto pisać kod dobrej jakości?
4
● Poprawa czytelności i zrozumiałości
• Ułatwione wdrażanie nowych osób do zespołu• Łatwiejsze zarządzanie i modyfikowanie istniejących funkcjonalności
● Zmniejszona potrzeba tworzenia dokumentacji technicznej
• Z wyłączeniem dokumentowania administracji systemem
Dlaczego warto pisać kod dobrej jakości?
5
● Poprawa czytelności i zrozumiałości
• Ułatwione wdrażanie nowych osób do zespołu• Łatwiejsze zarządzanie i modyfikowanie istniejących funkcjonalności
● Zmniejszona potrzeba tworzenia dokumentacji technicznej
• Z wyłączeniem dokumentowania administracji systemem
● Łatwiejsze testowanie
Dlaczego warto pisać kod dobrej jakości?
6
● Poprawa czytelności i zrozumiałości
• Ułatwione wdrażanie nowych osób do zespołu• Łatwiejsze zarządzanie i modyfikowanie istniejących funkcjonalności
● Zmniejszona potrzeba tworzenia dokumentacji technicznej
• Z wyłączeniem dokumentowania administracji systemem
● Łatwiejsze testowanie
● Poprawiona reużywalność poszczególnych metod
Dlaczego warto pisać kod dobrej jakości?
7
DISCLAIMER
8
Przedstawione zasady mają charakter zaleceń,należy dostosować je do natury własnego projektu
Zasady Object Calisthenics
9
1. Tylko jeden poziom wcięcia na metodę
Zasady Object Calisthenics
10
class Board { String board() { StringBuffer buf = new StringBuffer(); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { buf.append(data[i][j]); buf.append("\n"); } } return buf.toString(); }}
11
class Board { String board() { // 0 StringBuffer buf = new StringBuffer(); for (int i = 0; i < 10; i++) { // 1 for (int j = 0; j < 10; j++) { // 2 buf.append(data[i][j]); buf.append("\n"); } } return buf.toString(); }}
12
class Board { String board() { StringBuffer buf = new StringBuffer(); collectRows(buf); return buf.toString(); }
void collectRows(StringBuffer buf) { for (int i = 0; i < 10; i++) { collectRow(buf, i); } }
void collectRow(StringBuffer buf, int row) { for (int i = 0; i < 10; i++) { Buf.append(data[row][i]); buf.append("\n"); } }}
13
● Dokładniejsze nazewnictwo metod
● Krótsze metody
● Re-używalne metody
Zalety:
14
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
Zasady Object Calisthenics
15
if (…) { …} elseif (…) { …} elseif (…) { …} elseif (…) { …} elseif (…) { …} elseif (…) { …} elseif (…) { …} elseif (…) { …} else { …}
16
17
public void login(String username, String password) { if (userRepository.isValid(username, password)) { redirect("homepage"); } else { addFlash("error", "Bad credentials"); redirect("login"); }}
18
public void login(String username, String password) { if (userRepository.isValid(username, password)) { return redirect("homepage"); }
addFlash("error", "Bad credentials"); return redirect("login");}
19
public void login(String username, String password) { String redirectRoute = "homepage";
if (!userRepository.isValid(username, password)) { addFlash("error", "Bad credentials"); redirectRoute = "login"; }
redirect(redirectRoute);}
20
● Mniej upakowany kod
● Mniejsza złożoność logiczna
● Czytelność
● Unikamy duplikowania kodu
Zalety:
21
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
Zasady Object Calisthenics
22
Class Date { public boolean check(int year, int month, int day){ ... }}
// 9th of October or 10th of SeptemberDate.check(2017, 10, 9);
23
Class Date { public boolean check(Year year, Month month, Day day){ ... }}
Date.check(new Year(2017), new Month(10), new Day(9));
24
● Zabezpieczenie przed niewykryciem błędnego użycia metody
● Type hinting
Zalety:
25
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
Zasady Object Calisthenics
26
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
– Każda kolekcja musi być opakowana w swoją klasę, która będzie odpowiedzialna za wszystkie operacje
związane z tą kolekcją (filtrowanie, mapowanie, łączenie kolekcji, … )
Zasady Object Calisthenics
27
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
– Każda kolekcja musi być opakowana w swoją klasę, która będzie odpowiedzialna za wszystkie operacje
związane z tą kolekcją (filtrowanie, mapowanie, łączenie kolekcji, … )
– Żadna klasa z kolekcją nie może zawierać innych zmiennych
Zasady Object Calisthenics
28
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię (lub –> w PHP)
Zasady Object Calisthenics
29
class Piece { public String representation;}
class Location { public Piece current;}
class Board { public String boardRepresentation() { StringBuilder buf = new StringBuilder();
for (Location loc : squares()) { buf.append(loc.current.representation.substring(0, 1)); }
return buf.toString(); }}
30
class Piece { private String representation;
public String character() { return representation.substring(0, 1); }
public void addTo(StringBuilder buf) { buf.append(character()); }}
31
class Piece { private String representation;
public String character() { return representation.substring(0, 1); }
public void addTo(StringBuilder buf) { buf.append(character()); }}
class Location { private Piece current;
public void addTo(StringBuilder buf) { current.addTo(buf); }}
32
class Piece { private String representation;
public String character() { return representation.substring(0, 1); }
public void addTo(StringBuilder buf) { buf.append(character()); }}
class Location { private Piece current;
public void addTo(StringBuilder buf) { current.addTo(buf); }}
33
class Piece { private String representation;
public String character() { return representation.substring(0, 1); }
public void addTo(StringBuilder buf) { buf.append(character()); }}
class Location { private Piece current;
public void addTo(StringBuilder buf) { current.addTo(buf); }}
34
class Board { public String boardRepresentation() { StringBuilder buf = new StringBuilder();
for (Location location : squares()) { location.addTo(buf); }
return buf.toString(); }}
● Przestrzeganie zasad prywatności
● Zgodność z Prawem Demeter (regułą ograniczonej interakcji: „Rozmawiaj tylko z bliskimi przyjaciółmi”)
Zalety:
35
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
Zasady Object Calisthenics
36
if (sx >= sy) { if (sx > strSysMatImgW) { ny = strSysMatImgW * sy / sx; nx = strSysMatImgW; } if (ny > strSysMatImgH) { nx = strSysMatImgH * sx / sy; ny = strSysMatImgH; }} else { if (sy > strSysMatImgW) { nx = strSysMatImgH * sx / sy; ny = strSysMatImgH; } if (nx > strSysMatImgH) { ny = strSysMatImgW * sy / sx; nx = strSysMatImgW; }} 37
if (sx >= sy) { if (sx > strSysMatImgW) { ny = strSysMatImgW * sy / sx; nx = strSysMatImgW; } if (ny > strSysMatImgH) { nx = strSysMatImgH * sx / sy; ny = strSysMatImgH; }} else { if (sy > strSysMatImgW) { nx = strSysMatImgH * sx / sy; ny = strSysMatImgH; } if (nx > strSysMatImgH) { ny = strSysMatImgW * sy / sx; nx = strSysMatImgW; }} 38
if (sx >= sy) { if (sx > strSysMatImgW) { ny = strSysMatImgW * sy / sx; nx = strSysMatImgW; } if (ny > strSysMatImgH) { nx = strSysMatImgH * sx / sy; ny = strSysMatImgH; }} else { if (sy > strSysMatImgH) { nx = strSysMatImgH * sx / sy; ny = strSysMatImgH; } if (nx > strSysMatImgW) { ny = strSysMatImgW * sy / sx; nx = strSysMatImgW; }} 39
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
Zasady Object Calisthenics
40
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
– Nazwy powinny być na tyle precyzyjne, by jednoznacznie dało się tylko po niej stwierdzić, za co
odpowiada klasa, metoda, bądź zmienna
Zasady Object Calisthenics
41
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
– Nazwy powinny być na tyle precyzyjne, by jednoznacznie dało się tylko po niej stwierdzić, za co
odpowiada klasa, metoda, bądź zmienna
– Gdy nie umiesz wymyślić adekwatnej nazwy klasy, zastanów się, czy ta klasa ma sens w ogóle
Zasady Object Calisthenics
42
● Czytelność i ułatwione zarządzanie kodem
● Okazja do wykrycia problemów z architekturą systemu
● Wykorzystanie wsparcia IDE do podpowiadania (i wyszukiwania) nazw
Zalety:
43
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
Zasady Object Calisthenics
44
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
– Maksymalnie 50 linii na metodę w klasie
Zasady Object Calisthenics
45
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
– Maksymalnie 50 linii na metodę w klasie
– Maksymalnie 10 metod w klasie
Zasady Object Calisthenics
46
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
– Maksymalnie 50 linii na metodę w klasie
– Maksymalnie 10 metod w klasie
– Maksymalnie 15 klas w pakiecie
Zasady Object Calisthenics
47
48
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
8. Ogranicz ilość pól w klasie (Eng. Instance Variables) do 2 kilku
Zasady Object Calisthenics
49
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
8. Ogranicz ilość pól w klasie (Eng. Instance Variables) do 2 kilku
Zasady Object Calisthenics
50
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
8. Ogranicz ilość pól w klasie (Eng. Instance Variables) do 2 kilku
Zasady Object Calisthenics
51
● Mniej zależności
● Opakowanie typów prostych
● Większa spójność
● Łatwiejsze mockowanie na potrzeby testów jednostkowych
Zalety:
52
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
8. Ogranicz ilość pól w klasie (Eng. Instance Variables) do 2 kilku
9. Mów, nie pytaj (Unikaj GET’erów oraz SET’erów)
Zasady Object Calisthenics
53
// Gameprivate int score;
public void setScore(int score) { this.score = score;}
public int getScore() { return score;}
// Usagegame.setScore(game.getScore() + ENEMY_DESTROYED_SCORE);
54
// Gameprivate int score;
public void addScore(int delta) { this.score += delta;}
// Usagegame.addScore(ENEMY_DESTROYED_SCORE);
55
// Gameprivate int score;
public void addScore(int delta) { this.score += delta;}
public int getScore() { return score;}
// Usagegame.addScore(ENEMY_DESTROYED_SCORE);
56
● Logika klasy wewnątrz klasy – nie jest rozproszona po całym projekcie
Zalety:
57
1. Tylko jeden poziom wcięcia na metodę
2. Unikaj używania ELSE
3. Opakowuj typy proste
4. Kolekcje jako osobne klasy
5. Jedna kropka na linię
6. Nie skracaj nazw
7. Klasy i metody muszą być małe
8. Ogranicz ilość pól w klasie (Eng. Instance Variables) do 2 kilku
9. Mów, nie pytaj
Zasady Object Calisthenics
58
Pytania ...
59
● Rafael Dohms, Your code sucks, let's fix it (PHP Benelux, Antwerpia 2013)
● Guilherme Blanco, Object Calisthenics Applied to PHP (GTA Meetup, Toronto 2012)
● Paweł Lewtak, Object calisthenics (PHPCon, Rawa Mazowiecka 2016)
● http://williamdurand.fr/2013/06/03/object-calisthenics/
● https://www.cs.helsinki.fi/u/luontola/tdd-2009/ext/ObjectCalisthenics.pdf
● http://williamdurand.fr/2012/01/24/designing-a-software-by-naming-things/
● http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/general-formulation.html
● http://wiki.c2.com/?LawOfDemeter
Bibliografia:
60
Dziękuję
61