Czym jest złożoność ?
-
Upload
gogcom-dev-team -
Category
Technology
-
view
412 -
download
0
Transcript of Czym jest złożoność ?
O mnie
GOG.comSenior Web Developer
Czym się zajmuję?Rozwijam i utrzymuję kod
W międzyczasie szukam złotego Graala designu aplikacji ;)
GOG.com
Historia Start w 2008 pod skrzydłami CD Projekt - zespół 10 osóbObecnie zatrudnionych jest ponad 70 osób
Obecna pozycja
#1 globalnej dystrybucji klasycznych gier na PC i Mac #2 globalnej dystrybucji gier indie na PC i Mac
Partnerzy 220+ twórców i wydawców gier
Klienci Ponad 2.7 miliona unikalnych wejść miesięcznie z całego świata
Gry Ponad 800 tytułów w kataloguPonad 39 milionów gier na kontach użytkowników
Agenda
1. Czym jest złożoność?
2. Dlaczego złożoność jest problematyczna?
3. Złożoność a design kodu
4. Złożoność poznawcza
5. Podsumowanie i wnioski
Czym jest złożoność?
CZYM JEST ZŁOŻONOŚĆ?
• Trudność w zrozumieniu, wykonaniu i zweryfikowaniu poprawności projektu.
• Im większa liczba możliwych interakcji w procesie, tym więcej rzeczy może pójść nie tak.
Dlaczego złożoność jest problematyczna?
CZŁOWIEK TO NIE MASZYNA
• Ludzki umysł nie może ogarnąć nieskończonej ilości informacji.
• Według badań, człowiek może myśleć o maksymalnie 4 rzeczach na raz.
• Zbyt dużo informacji na raz to ryzyko nieświadomej pomyłki.
Dlaczego złożoność jest problematyczna?
TOKSYCZNY WPŁYW NA PROJEKT
• Złożoność rodzi złożoność.
• Zamiast myśleć o istocie problemu i sposobie rozwiązania musimy myśleć o stanie obecnym i o tym jak zaadaptować się do nowych warunków.
Złożoność a design kodu
PODSTAWOWE METRYKI
Cyclomatic Complexity (CC)
Liczba linearnie niezależnych ścieżek, w kodzie z jednym punktem wyjścia równa jest liczbie punktów decyzyjnychNPath Complexity (NP) Liczba możliwych różnych przebiegów w kodzie
Afferent Coupling (CA) Liczba klas, które polegają na danej implementacji
Efferent Coupling (CE) Liczba klas, na których polega dana klasa
Stability (I) Wartość: CE / (CA + CE), określa ogólną stabilność,0 to całkowita stabilność, 1 to całkowita niestabilność
Złożoność a design kodu
function fizzBuzz($n)
{
$output = "";
if ($output % 3 == 0) {
$output .= "Fizz";
}
if ($output % 5 == 0) {
$output .= "Buzz";
}
return $output;
}
Złożoność a design kodu
REKOMENDOWANE LIMITY (wg PMD i phpMD)
• CC <= 10
• NPath <= 200
• Powyżej podanych metryk, kod przeważnie zaczyna robić się trudnydo zrefaktorowania i zrozumienia.
http://phpmd.org/rules/index.html#code-size-rules
Złożoność a design kodu
TESTY JEDNOSTKOWE
• Chronią przed niepożądanymi zmianami.
• Pozwalają na bardziej swobodną refaktoryzację.
Złożoność a design kodu
• Kod ma 100% code coverage, 100% path coverage.
• Jesteśmy kryci przed każdą pomyłką?
• .. niestety nie. Ale prawie.
$this->assertEquals(fizzBuzz(2) == "");
$this->assertEquals(fizzBuzz(9) == "Fizz");
$this->assertEquals(fizzBuzz(10) == "Buzz");
$this->assertEquals(fizzBuzz(30) == "FizzBuzz");
Złożoność a design kodu
ROZBIJANIE PROBLEMÓW:SEPARATION OF CONCERNS
• Nasze aplikacje rozwiązują jakiś (duży) problem, najczęściej biznesowy.
• Każdy problem można rozbić na więcej pod-problemów.
Złożoność a design kodu
OBSŁUŻENIE ŻĄDANIA HTTP KLIENTA
PRZESŁANIE OBIEKTUREQUEST DO KONTROLERAURUCHOMIENIE BUNDLI STWORZENIE OBIEKTU
REQUEST
WYBRANIE ROUTE’A NAPODSTAWIE ŚCIEŻKIŻĄDANIA HTTP
ODESŁANIE ODPOWIEDZI
WYTWORZENIE OBIEKTU TYPU RESPONSE
ODPYTANIE BAZY DANYCHO ŻĄDANE INFORMACJE
GENERACJA WIDOKUDLA UŻYTKOWNIKA
URUCHOMIENIE INNYCHŻĄDANYCH PROCESÓW
ZAPYTANIE DOBAZY DANYCH
GENERACJASZABLONÓW TWIG
ZAPYTANIEDO CACHE
OTRZYMANIE OBIEKTU TYPU RESPONSE
Złożoność a design kodu
OBSŁUŻENIE ŻĄDANIA HTTP KLIENTA
URUCHOMIENIE BUNDLI STWORZENIE OBIEKTUREQUEST
WYBRANIE ROUTE’A NAPODSTAWIE ŚCIEŻKIŻĄDANIA HTTP
PRZESŁANIE OBIEKTUREQUEST DO KONTROLERA
WYTWORZENIE OBIEKTU TYPU RESPONSE
ODPYTANIE BAZY DANYCHO ŻĄDANE INFORMACJE
GENERACJA WIDOKUDLA UŻYTKOWNIKA
URUCHOMIENIE INNYCHŻĄDANYCH PROCESÓW
ZAPYTANIE DOBAZY DANYCH
GENERACJASZABLONÓW TWIG
ZAPYTANIEDO CACHE
Złożoność a design kodu
OBSŁUŻENIE ŻĄDANIA HTTP KLIENTA
URUCHOMIENIE BUNDLI STWORZENIE OBIEKTUREQUEST
WYBRANIE ROUTE’A NAPODSTAWIE ŚCIEŻKIŻĄDANIA HTTP
PRZESŁANIE OBIEKTUREQUEST DO KONTROLERA
WYTWORZENIE OBIEKTU TYPU RESPONSE
URUCHOMIENIE INNYCHŻĄDANYCH PROCESÓW
GENERACJA WIDOKUDLA UŻYTKOWNIKA
GENERACJASZABLONÓW TWIG
ODPYTANIE BAZY DANYCHO ŻĄDANE INFORMACJE
ZAPYTANIE DOBAZY DANYCH
ZAPYTANIEDO CACHE
Złożoność a design kodu
OBSŁUŻENIE ŻĄDANIA HTTP KLIENTA
PRZESŁANIE OBIEKTUREQUEST DO KONTROLERAURUCHOMIENIE BUNDLI STWORZENIE OBIEKTU
REQUEST
WYBRANIE ROUTE’A NAPODSTAWIE ŚCIEŻKIŻĄDANIA HTTP
WYTWORZENIE OBIEKTU TYPU RESPONSE
URUCHOMIENIE INNYCHŻĄDANYCH PROCESÓW
GENERACJA WIDOKUDLA UŻYTKOWNIKA
GENERACJASZABLONÓW TWIG
ODPYTANIE BAZY DANYCHO ŻĄDANE INFORMACJE
ZAPYTANIE DOBAZY DANYCH
ZAPYTANIEDO CACHE
ODESŁANIE ODPOWIEDZI
OTRZYMANIE OBIEKTU TYPU RESPONSE
Złożoność a design kodu
DOBRE OBIEKTY TO MAŁE OBIEKTY
• Uniwersalna zasada: „preferuj gęstszą sieć mniejszych obiektów od rzadszej
sieci większych obiektów” - Nigel Thorne
• Single Responsibility Principle
• Design By Contract (Liskov Substitute Principle)
• Dependency Inversion Principle
• Interface Segregation Principle
• Tell, don’t ask
http://stackoverflow.com/questions/243274/best-practice-with-unit-testing-abstract-classes
Złożoność a design kodu
SINGLE RESPONSIBILITY PRINCIPLE
• Każdy obiekt powinien mieć jedną odpowiedzialność.
• “Odpowiedzialność to powód do modyfikacji” - Robert C. Martin
Złożoność a design kodu
class AppKernel { … }
class Controller { … }
class TwigEngine implements EngineInterface { … }
Złożoność a design kodu
DESIGN BY CONTRACT
• Wprowadzenie jasnego kontraktu umożliwia jawne przekazanie informacji.
• Te informacje to m.in to, czego dana klasa oczekuje, co i w jakim wypadku zwraca, a także wyjątki które może zwrócić i co one oznaczają.
• Brak typów wartościowych (int, string…) oraz zwracanych wartości w PHP niestety to utrudniają, ale annotacje PHPDoc (@param, @return, @throws) i dobre IDE pomagają w utrzymaniu dyscypliny.
Złożoność a design kodu
interface UserRepository {
public function findOne(UserId $userId);
}
class MysqlUserRepository {
private $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
public function findOne(UserId $userId) {
return $this->connection->query("SELECT * from users WHERE id = :uid", [$userId->value()]);
}
}
class InMemoryUserRepository { […] }
Złożoność a design kodu
DEPENDENCY INVERSION PRINCIPLE
• Nie powinno być „hierarchii klasowej”. Zamiast tego, wszystko powinno być zależne od abstrakcyjnych interfejsów.
• Abstrakcja nie powinna polegać na implementacji (to ma być złączone z poniższym).
• Implementacja powinna polegać na abstrakcji.
Złożoność a design kodu
class BlogController {
public function __construct(BlogPagesRepository $repository ) { … }
}
interface BlogPagesRepository { … }
class MysqlBlogPagesRepository implements BlogPagesRepository { … }
class MongoDbPagesRepository implements BlogPagesRepository { … }
Złożoność a design kodu
INTERFACE SEGREGATION PRINCIPLE
• Klient nie powinien zależeć od metod, którego nie potrzebuje.
• Ułatwia tworzenie implementacji do granularnych interfejsów.
Złożoność a design kodu
interface VisitorInterface {
public function getIP();
}
interface UserInterface {
public function getId();
}
class HttpUser implements VisitorInterface, UserInterface { … }
class Crawler implements VisitorInterface { … }
class CliUser implements UserInterface { … }
Złożoność a design kodu
TELL, DON’T ASK
• Mów obiektom co mają robić, nie pytaj ich o stan.
• Stawiaj warunki tam, gdzie są one zasadne dla danego problemu.
Złożoność a design kodu
// BasketController.php
if($customer->getCountOfItemsInBasket() < 3) {
$customer->addToBasket($item);
}
ŹLE (IMPLEMENTACJA KLASY CUSTOMER WYCIEKA DO KONTROLERA):
Złożoność a design kodu
//BasketController.php
$customer->addToBasket($item);
//Customer.php
public function addToBasket($item) {
if($this->getCountOfItemsInBasket() < 3) {
[…]
}
}
DOBRZE:
Złożoność a design kodu
KORZYŚCI ZE STOSOWANIA
• Odizolowanie problemów od siebie = Większa elastyczność
• Mniejsze problemy = Mniejsza złożoność
Złożoność a design kodu
SCOPE
• Każdy kod posiada jakiś scope, w którym ma zadeklarowane swoje wartości.
• Wszystkie dane w scopie powinny być mu jawnie przekazane poprzez parametry.
Złożoność a design kodu
PROBLEMY ZE SCOPE’EM
• Global variable: global $var;
• Mutability: setFoo($foo) - Dla obiektów które nie przenoszą danych
• Zależność od implementacji
Złożoność a design kodu
POMOCNE NARZĘDZIA
phpMD Na podstawie reguł alarmuje Nas, gdy dana klasa/metoda może okazać się problematyczna w utrzymaniu
PHP Code Sniffer Sprawdza zgodność z standardami PSR
PHP Code Analyzer Wykonuje analizę statyczną kodu, inferencję typów , wykrywa proste błędy
Solidne IDE Wspomaga pisanie i formatowanie kodu, minimalizuje ryzyko wystąpienia pomyłki mechanicznej ( syntax error, zły typ, zła klasa, zła metoda.. etc. )
Złożoność poznawcza kodu
ZŁOŻONOŚĆ KOGNITYWNA
• Jawność tego, co dzieje się w kodzie dla osoby czytającej
• Często pomijana (ze względu na swoją „nietechniczność”), ale jest nie mniej ważna od złożoności samego kodu
Złożoność poznawcza kodu
ODBIÓR JEST WSZYSTKIM
• Czytelność kodu (Coding Style)
• Język wykorzystywany w aplikacji
• Domain Driven Design, Ubiquitous Language - metodologia, która minimalizuje narzut w odbiorze
Podsumowanie i wnioski
WNIOSKI
• Zdanie sobie sprawę z tego, co dokładnie sprawia, że kod ciężej utrzymać to pół sukcesu.
• Pisanie łatwego kodu jest trudne - przepisanie trudnego kodu może byćjeszcze trudniejsze.
• Sprawdzone rozwiązania z zakresu projektowania aplikacji pomagają w ograniczeniu złożoności aplikacji do koniecznego minimum.
• Czytelność i nazewnictwo są tak samo ważne co sam kod.
Podsumowanie i wnioski
CO ZYSKUJE DEVELOPER I PRODUCT OWNER?
• Czas
• Elastyczność w adaptacji do nowych wymogów biznesowych
• Elastyczność w tworzeniu technicznych implementacji
• Podatność na zmiany, odporność na uszkodzenia produktu