ZTO Wprowadzenie do TDD, SOLID - Jak pisać dobry kod

Slides:



Advertisements
Podobne prezentacje
C++ wykład 4 ( ) Przeciążanie operatorów.
Advertisements

Klasy abstrakcyjne i interfejsy
1 Dzisiejszy wykład Wzorce funkcji Wzorce klas. 2 Wzorce Często pojawia się konieczność pisania podobnych funkcji lub klas operujących na argumentach.
Wzorce.
Projekt Do kariery na skrzydłach – studiuj Aviation Management Projekt współfinansowany ze ś rodków Europejskiego Funduszu Społecznego. Biuro projektu:
Bezpieczeństwo wyjątków w C++: OpenGL
Logiki (nie)klasyczne
Licznik template<class Count_Type> class Count { public:
Serwery Aplikacji ASP .NET Web Objects Arkadiusz Popa.
Refaktoryzacja czyli odświeżanie kodu
Obiektowe metody projektowania systemów
Pakiety i ATD 1 Definicja. Pakietem albo jednostką programową nazywamy grupę logicznie powiązanych elementów, które mogą być typami, podtypami, obiektami.
Języki programowania obiektowego
-Witam nazywam się Weronika Zgorzelska oraz Oliwia Kołakowska. -Witam serdecznie 1.Od kiedy pan gra w FC Barcelonie… -W FC Barcelonie gram od 13 roku.
Zestawienie wyników badań Researches summary. 1. Czy Twoi rodzice uprawiają jakieś sporty lub w inny aktywny sposób spędzają wolny czas poświęcając im.
Podstawy C# Grupa .NET PO.
Komponentowe i rozproszone Jak pisać dobry kod. ZŁY KOD WYGLĄDA TAK...
Komponentowe i rozproszone
Projektowanie obiektowe
JAVA c.d.. Instrukcji wyboru SWITCH używamy, jeśli chcemy w zależności od wartości pewnego wyrażenia wykonać jeden z kilku fragmentów kodu. Jest to w.
Dziedziczenie Maciek Mięczakowski
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Projektowanie obiektowe
Tworzenie Aplikacji Internetowych
Programowanie obiektowe 2013/2014
Dobry kod OO Jeżeli zapytamy statystycznego programistę z czym kojarzy mu się dobry kod OO to najprawdopodobniej będzie mówił o wzorcach projektowych.
How to make an application on Step by Step Instructions
Diagram klas Kluczowymi elementami są: klasy (class)
Wydział Elektroniki Kierunek: AiR Zaawansowane metody programowania Wykład 5.
Rights of the child. Kliknij, aby edytować format tekstu konspektu Drugi poziom konspektu  Trzeci poziom konspektu Czwarty poziom konspektu  Piąty poziom.
OOP, Desing Patterns … and more Michał Dubel
Wstęp do Fizyki Środowiska - Podstawy mechaniki płynów Problems 1 Lecture 1 1)In a vertical capillary filled with water air bubbles are rising Sketch the.
CROSSWORD: SLANG. Konkurs polega na rozwiązaniu krzyżówki. CROSSWORD: SLANG Wypełnione karty odpowiedzi prosimy składać w bibliotece CJK, lub przesyłać.
Haskell. Dopasowanie do wzorca Jest to operacja, gdzie pewnie wyrażenie sprawdza się ze wzorcem, w którym może znajdować się jedno lub więcej "wolnych.
Les meilleures photos de L'année 2005 D'après NBC A life for two, full of tenderness, obtains happiness as they get closer to heaven. Życie we dwoje,
Komponentowe i rozproszone Komponenty i zależności.
Obiektowe metody projektowania systemów Adapter. Wstęp: „Dostosowanie interfejsu klasy do interfejsu, którego oczekuje użytkownik. Adapter umożliwia współprace.
Obiektowe metody projektowania systemów Abstract Factory design pattern (aka. Kit)
Zakres Wzorce projektowe - kreacyjne -Factory Method -Abstract Factory.
Paweł Starzyk Obiektowe metody projektowania systemów
DEFINITION OF COMPOSITE PROGRAMMABLE GRAPH (CP-GRAPH)
Komponentowe i rozproszone Interludium czyli krótki wykład o rozpraszaniu.
Paulina Kowalczyk Dominika Struzik I LO Tadeusz Kosciuszko in Wielun POLAND.
Programowanie Zaawansowane
You are about to see a few sentences in Polish. Try to translate them into English, but keep in mind they are: The First Conditonal The Second Conditional.
Assessment of influence of short-lasting whole-body vibration on joint position sense and body balance – a randomised masked study Rehabilitation Department,
Partnerstwo dla Przyszłości 1 Lekcja 28 Dziedziczenie i rodzaje dziedziczenia.
Od Feynmana do Google’a Rafał Demkowicz-Dobrzański,, Wydział Fizyki UW.
Refaktoryzacja „Any fool can write a code that computer understands. Good programers write code that human can understand” – Martin Fowler.
ZTO Wprowadzenie do TDD, SOLID - Jak pisać dobry kod Krzysztof Manuszewski.
Www,mojesilnedrzewo.pl. W dniach 15 marca – 30 kwietnia 2010.r.wytwórnia wody mineralnej Żywiec Zdrój SA wspólnie z Fundacją Nasza Ziemia i Regionalną.
Inżynieria oprogramowania OOP i zasady SOLID WWW: Jacek Matulewski Instytut Fizyki, UMK.
Opracowanie: Katarzyna Gagan, Anna Krawczuk
Programowanie Obiektowe – Wykład 6
Programowanie Obiektowe – Wykład 9
(według:
Przetestuj Usability Mateusz Kaczmarek
Trudny czy łatwy labirynt?
Programowanie Obiektowe – Wykład 2
A prototype of distributed modelling environment
Managed Service Identity dla zasobów w Microsoft Azure
Running Dictation Activity to Engage Students in Reading, Writing, Listening, and Speaking.
EMPOWEREMENT IN ICT SKILLS. I CREATED MY WEBSITE TO USE IT FOR TEACHING.
Zaawansowane techniki obiektowe
System rzymski Roman system
zl
1) What is Linux 2) Founder and mascot of linux 3) Why Torvalds created linux ? 4) System advantages and disadvantages 5) Linux distributions 6) Basic.
Refaktoryzacja czyli odświeżanie kodu
Zapis prezentacji:

ZTO Wprowadzenie do TDD, SOLID - Jak pisać dobry kod Krzysztof Manuszewski

Trudno jest testować zły kod ...

zły kod wygląda TAK ...

... jest „sztywny” i „delikatny” Nowe błedy pojawiają się w obszarach, które zdają sie być niezwiazane ze zmienianą funkcjonalnoscią Pozornie drobne zmiany indukują poważne zmiany w wielu miejscach kodu i/lub skutkuja trudnymi do przewidzenia błędami Trudno przewidzieć wpływ nawet drobnych zmian Trudno przewidzieć czas oraz koszty rozwoju projektu/poprawek Zespół prorgramistów traci wiarygodność Menedżerowie niechętnie godza się na zmiany

... i trudny do „reużycia” Potrzebne elementy zależą od niepotrzebnych Ryzyko ekstrakcji potrzebnego kodu jest duże a koszt wiekszy niż napisanie opotrzebnej funkcjonalności od podstaw

Bezpośrednie źródła problemów Praca z cudzym kodem Pośpiech Zmiany, ciagłe zmiany Niedostateczna/niejasna specyfikacja ... a może przyczyną jest nienajlepsza architektura kodu

Prosty przykład kopiowanie znaków z klawiatury na drukarkę public class Copier { public static void Copy() { int c; while((c=Keyboard.Read()) != -1) Printer.Write(c); } Simple design is good because is simple and cheap, but it does not necessarily mean is also cheap to maintain Good design should take into account possible change (be careful to not overdesign the software), but it can also be simple. The clue is to catch the moment when you start see the smells, then the change of architecture is the absolute must.

... drobna zmiana ... Z klawiatury lub z czytnika taśmy public class Copier { public static bool rdFlag = false; public static void Copy() { int c; while((c= (rdFlag ? PaperTape.Read() : Keyboard.Read()) != -1) Printer.Write(c); } Changes in program coppier done without change in architecture.

..i następna ... Na drukarke lub ekran public class Copier { public static bool rdFlag = false; public static bool ptFlag = false; public static void Copy() { int c; while((c= (rdFlag ? PaperTape.Read() : Keyboard.Read()) != -1) if (ptFlag) Screen.Write(c); else Printer.Write(c); } More changes equal more problems

...i już nie jest prosty... Więcej źródeł i ujść danych Obsługa błędów I/O errors Przekodowywanie znaków Logowanie przekodowanych znaków do pliku Zmiana formatu tekstu w oparciu o kontekst (np justowanie tekstu After some number of change lines of original code is less then patches.

Wymagania się zmieniają ... Zawsze lub przynajmniej czasami zwłaszcza w kontekście iteracyjnej realizacji projektu Changes are always so it is worth to take them into account in design phase or at least in the moment when the change occurs.

... być gotowym na zmiany public class KeyboardReader : { public int Read() { return Keyboard.Read(); } } public class PrinterWriter : { public Write(int c) { return Printer.Write(c); } public class Copier { public static KeyboardReader reader = new KeyboardReader(); public static PrinterWriter writer = new PrinterWriter(); public static void Copy() { int c; while((c=(reader.Read())) != -1) writer.Write(c); This is a simple example of the design, which is change friendly

... to podzielić odpowiedzialność Wyraźna separcja kodu: twórcy klas Printer i Writer nie muszą znać ani rozumieć logiki kopiowania ale: Zmiany w sposobie obsługi drukarki/klawiatury: wymuszają zmiany w klasie kopier (typy atrybutów) wymuszają rekompilację klasy „Copier” Implementujący klasę Copier musi znać i umieć tworzyć obiekty klas Printer, KeyboardReader Klasa Screen musi dziedziczyć po Printer (choć nie ma nic wspólnego z drukarką) However changes in modules responsible for IO influence the copier module

Lepszykod wygląda TAK ...

public interface IReader { public int Read() ; } public class KeyboardReader : IReader{ public int Read() { return Keyboard.Read(); } public class Copier { public static IReader reader = new KeyboardReader(); public static IWriter writer = new PrinterWriter(); public static void Copy() { int c; while((c=(reader.Read())) != -1) writer.Write(c); Example of the code with interfaces.

public class Copier { IReader reader; IWriter writer; public Copier (IReader newReader, IWriter writer) { reader = newReader; writer = newWriter; } public static void Copy() { ... Example of the code with interfaces.

Dobra separacja kodu Klasa Copier nie zależy od Printer ani od Reader Klasy Printer ani Reader nie zależą od Copier Wszystkie klasy (usługobiorcy i usługodawcy zależą od interfejsu) Zmiany interfejs-u sa jedynym powodem do zmian w większych obszarach kodu Interfejs stanowi specyfikację kontraktu pomiędzy 2 stronami – klientem i dostarczycielem pewnej funkcjonalności The problem here may be solved by the use of inteface Additionally interface is more legible then class even if we are looking in the public methods

S.O.L.I.D. - ny kod SRP: The Single Responsibility Principle OCP: The Open/Close Principle LSP: The Liskov Substitution Principle ISP: The Interface Segregation Principle DIP: The Dependency Inversion Principle

(SRP) Single-Responsibility Principle Klasa powinna mieć pojedynczy powód do zmian. Klasa Printer jest odpowiedzialna za pisanie na drukarkę Klasa Copier jest odpowiedzialna za proces kopiowania Single responsibility rule

SRP - przykład problemów public interface Modem { public void Dial(string pno); public void Hangup(); public void Send(char c); public char Recv(); } 2 odpowiedzialności razem – zarządzanie połaczeniem i transmisja danych Jeżeli klienci korzystają z nich oddzielnie (prawdopodobne) zmiany w sygnaturze Dial wywołają konieczność rekompilacji klientów, którzy korzystają jedynie z Send/Recv Single responsibility rule

SRP - przykład problemów Nie zmusza do realizacji obu funkcjonalności przez jedną klasę – chociaz dalej jest to mozliwe Single responsibility rule

SRP - przykład problemów Zmiany dowolnego z 3 aspektów oznaczają zmiany w klasie Employee Łatwo wprowadzić błąd do pobocznej funkcjonalności . Testować trzeba cała klasę. Pożądane jest ograniczenie funkcjonalności w obrębie zmienianej klasy

SRP - Możliwe rozwiązanie Single responsibility rule

Moment! Obiekty powinny hermetyzować swoją zawartość Czy obiekty powinny mieć wiedzę: Jak zapisać samego siebie? Jak raportować swój stan? To nie jest tak istotne! Filozofia, która kryje się za OO nie jest w tym wypadku tak istotna Podstawowym celem jest ograniczenie propagacji zmian w systemie System ma być łatwy w utrzymaniu i modularny! Single responsibility rule

(OCP) Open/Close Principle Jednostki programowe (klasy, moduły, funkcje, itd.) powinny być otwarte na rozszerzenia a zamknięte na zmiany Robert C. Martin Do kopiarki mogą być łatwo dodawane nowe typy czytników/pisarzy bez zmian (no prawie bez) w klasie Copier Ale „bez zmian” oznacza też, że klasa Copier nie powinna sama tworzyć obiektów, z których korzysta -> rozwiązywanie zależności

OCP - Otwartość na rozszerzanie Zapewniają np. wzorce projektowe: It is a particular software design pattern, whereby algorithms can be selected on-the-fly at runtime. So behaviors of a class should not be inherited, instead they should be encapsulated using interfaces. This allows better decoupling between the behavior and the class that uses the behavior. The behavior can be changed without breaking the classes that use it, and the classes can switch between behaviors by changing the specific implementation used without requiring any significant code changes. Behaviors can also be changed at run-time as well as at design-time. A template method defines the program skeleton of an algorithm. The algorithm itself is made abstract, and the subclasses override the abstract methods to provide concrete behavior. First a class is created that provides the basic steps of an algorithm design. These steps are implemented using abstract methods. Later on, subclasses change the abstract methods to implement real actions. Thus the general algorithm is saved in one place but the concrete steps may be changed by the subclasses. strategia metoda szablonowa Które rozwiązanie wybrać ?

Które rozwiazanie wybrać? Dziedziczenie wprowadza silniejsze zwiazki miedzy klasami: Agregacja daje możliwość zmiany zachowania w czasie wykonania Agregacje dają możliwość niezależnego określania zachowania w różnych obszaarch (niezaleznych strategii) Dziedziczenie interfejsu jest naturalne Dziedziczenie implementacji niekoniecznie Jeśli nie ma dodatkowych wskazówek agregacja może być lepszym rozwiazaniem! It is a particular software design pattern, whereby algorithms can be selected on-the-fly at runtime. So behaviors of a class should not be inherited, instead they should be encapsulated using interfaces. This allows better decoupling between the behavior and the class that uses the behavior. The behavior can be changed without breaking the classes that use it, and the classes can switch between behaviors by changing the specific implementation used without requiring any significant code changes. Behaviors can also be changed at run-time as well as at design-time. A template method defines the program skeleton of an algorithm. The algorithm itself is made abstract, and the subclasses override the abstract methods to provide concrete behavior. First a class is created that provides the basic steps of an algorithm design. These steps are implemented using abstract methods. Later on, subclasses change the abstract methods to implement real actions. Thus the general algorithm is saved in one place but the concrete steps may be changed by the subclasses.

OCP – co ze zmianami? Nie można zapobiec wszystkim zmianom Kluczowe jest rozpoznanie co może się zmieniać często lub co bedzie trudno zmienić Dodanie nowej funkcjonalności powinno być łatwe

(LSP) Liskov Substitution Principle Podklasy muszą być logicznie zgodne z typami bazowymi. TapeReader : KeyboardReader ??? Dziedziczenie oznacza „jest szczególnym przypadkiem” We need to be careful how we are designing the class hierarchy

LSP – Szkolny przykład (1) public class Rectangle { private Point topLeft; private double width; private double height; public double Width get { return width; } set { width = value; } } public double Height get { return height; } set { height = value; } 30

LSP – Szkolny przykład (2) Unit Testing LSP – Szkolny przykład (2) public class Rectangle { private Point topLeft; private double width; private double height; public virtual double Width get { return width; } set { width = value; } } public virtual double Height get { return height; } set { height = value; } public class Square : Rectangle { public override double Width set base.Width = value; base.Height = value; } public override double Height 31

LSP – Szkolny przykład (3) Unit Testing LSP – Szkolny przykład (3) void foo (Rectangle r) { r.SetWidth(32); // calls Rectangle.SetWidth } Co bedzie gdy przekażemy obiekt typu Square? A poniżej ? void goo (Rectangle r) { r.Width = 5; r.Height = 4; if(r.Area() != 20) throw new Exception("Bad area!"); } Square nie zachowuje się jak szczególny przypadek prostokąta! 32

(ISP) Interface Seggregation Principle Klasa nie powinna zależeć od tego, czego nie używa. Interfejs IReader powinien być oddzielny od IWriter. „Tłuste” klasy wprowadzają zwykle silne związki ze swoimi klientami Zmiana wymuszona przez jednego z klientów dotyka pozostałych Interface pollution Too wide interfaces are easy to do but harder to use

ISP - uwagi Należy unikać obszernych interfejsów Interfejs (kontrakt) powinien być spójny Interfejs (kontrakt) nie powinien być zbyt szeroki wszystkie implementujące go klasy będą musiały dostarczyć kompletu metod (np. WCF: 3-5-9) Lepsze są wąskie, zorientowane na role interfejsy Jeżeli nie można uniknąć „tłustych” klas - te powinny być prezentowane klientom za pośrednictwem zbioru wąskich, zorientowanych na role interfejsów Oddzielni klienci mogą oznaczać oddzielne interfejsy Interfejsy moga dziedziczyc po sobie – można dostarczyć pojedynczą referencją do obiektu implementującego wiele interfejsów. Interface pollution Too wide interfaces are easy to do but harder to use

(DIP) Dependency-Inversion Principle Wysokopoziomowe moduły nie powinny zależeć od nispopoziomowych (ani odwrotnie). Jedne i drugie powinny zależeć od abstrakcji (kontraktów). Abstrakcje (kontrakty) nie powinny zależeć od szczegółów implementacyjnych. Implementacja powinna zależeć od abstrakcji (kontraktu). Hollywood principle: „Don‘t call us – we will call you” Copier i KeyboardReader zależą od interfejsu IReader, ale nie zależą od siebie Interfejs jest bardziej przejrzysty niż klasa Also known as Inversion of control. Informally, it is expressed by the Hollywood Principle - "Don't call us, we'll call you". When excercised it needs to be applied wise, as always. Nothing is for free. The price paid for that additional flexibility is increased complexity, but in many cases this makes sense (the same case for coppier example).

Unit Testing DIP - Przykład 36

DIP - podsumowanie Podstawa dobrego OOD Interfejsy należą do klientów Unit Testing DIP - podsumowanie Podstawa dobrego OOD Interfejsy należą do klientów Implementacja zmienia się często, interfejsy rzadko „Podejrzane” sytuacje: Zmienna odwołuje się do nieabstrakcyjnej klasy Klasa dziedziczy po nieabstrakcyjnej klasie Metoda nadpisuje konkretną implementację z klasy bazowej 37

Zalecana lektura Robert C.C. Martin „Agile Principles, Patterns and Practices in C#” [przykłady są na tej podstawie] Robert C.C. Martin „Czysty kod" Warto zobaczyc screencast Martina z NDC 2009 „Robert C. Martin - Clean Design, SOLID Principles I and II.wmv” Interface pollution Too wide interfaces are easy to do but harder to use