SlideShare a Scribd company logo
1 of 205
Jak programować aby
nie zwariować?
Jakub Marchwicki
04.04.2013
Na początek
Co to za gość?
Co ja tu robię?
Co ja tu robię?
Co ja tu robię?
Co ja tu robię?ból
Co ja tu robię?ból
liczba slajdów
Co ja tu robię?ból
liczba slajdów
OK
Ryzyko
utraty
zdrowia
35 slajdów
Co ja tu robię?ból
liczba slajdów
OK
Ryzyko
utraty
zdrowia
205 slajdów
I po co to wszystko?
Bo software to nasze hobby
I po co to wszystko?
Bo software to nasze hobby
fach
I po co to wszystko?
Bo software to nasze hobby
fach
zawód
I po co to wszystko?
Bo software to nasze hobby
fach
zawód
przyjemność
I po co to wszystko?
bo płacą nam za pisanie
dokumentacji
pisanie kodu to przyjemność
Punkt wyjścia
Punkt wyjścia
Kiedy software jest dobry?
Oprogramowanie musi działać
Musi być na czas
Musi być rozbudowywalne
Modyfikowalne
Musi mieć odpowiednią jakość
Punkt wyjścia
Kiedy software jest dobry?
Oprogramowanie musi działać
Musi być na czas
Musi być rozbudowywalne
Modyfikowalne
Musi mieć odpowiednią jakość
To zależy???
Punkt wyjścia
Więc czym jest jakość
Dla kogoś Dla siebie
Dla kogo pracuje?
Więc czym jest jakość
Dla kogoś Dla siebie
Dla kogo pracuje?
„Jakość (jak piękno) jest sądem
wartościującym, wyrażonym przez
użytkownika. Jeśli nie ma takiego
użytkownika – nie ma takiego sądu”
Platon
Więc czym jest jakość
Więc czym jest jakość
Dla kogoś Dla siebie
Dla kogo pracuje?
„Jakość to sposób myślenia,
który powoduje, że stosuje się i
bez przerwy poszukuje
najlepszych rozwiązań”
William Edwards Deming
Więc czym jest jakość
Plan-Do-Study-Act
If design is a hypothesis
how can you prove it?
Czy mój software jest dobrej jakości?
Czy mój software jest dobrej jakości?
Oprogramowanie musi działać
Musi być na czas
Musi być rozbudowywalne
Modyfikowalne
Musi mieć odpowiednią jakość
Jak programować aby nie zwariować?
Użyjmy frameworka
Konkretyzacja pewnej idei
Wprowadzenie uporządkowanego
sposoby pracy
Ujęcie złożonych czynności w zestaw
powtarzalnych kroków
Framework to pewna obietnica
No więc mamy to zadanie
I ten ciekawy framework
…
Wyobraźmy sobie nowy projekt…
…w którym framework nie zadziałał
Szukamy doświadczenia, pytamy
Samodzielnie poszukujemy drogi
Stosujemy framework na siłę
Porzucamy framework i robimy po staremu
I jeżeli ma szczęście do pierwszy dwóch
A po latach
• Kod jest podstawowym medium
komunikacji w projekcie
• Zły kod to jak solenie herbaty koledze
z zespołu albo plucie do kanapki – a
przecież nie jesteśmy złośliwi
Wartości
• Jako zespół jesteśmy jednością
– Jak ja pójdę na skróty, to kolega
będzie się męczył
– I jako całość i tak będziemy
nieefektywni
Wartości
• Programy są częściej czytane niż
pisane
• Więcej czasu poświęcamy na
modyfikację istniejącego kodu niż na
tworzenie nowego
Implementation Patterns
• Komunikacja – kod źródłowy powinno
się czytać jak książkę
• Prostota – wprowadzaj złożoność
tylko wtedy, kiedy jest to konieczne
• Elastyczność – elastyczność to
dodatkowa złożoność, więc
wprowadzaj ją tylko tam gdzie to
konieczne
Implementation patterns
• Lokalne konsekwencje – zmiana w
jednym miejscu nie powoduje zmian w
innych
• Minimalne powtórzenia – DRY
Implementation patterns
• Dane i logika razem – ponieważ dane
i logika z reguły zmieniają się w tym
samym czasie
• Symetria – utrzymuj podobny poziom
abstrakcji w obrębie metody / klasy
Implementation patterns
„Czysty kod jest prosty i bezpośredni.
Czysty kod czyta się jak dobrze
napisaną prozę. Czysty kod nigdy nie
zaciemnia zamiarów projektanta; jest
pełen trafnych abstrakcji i prostych
ścieżek sterowania.”
Grady Booch – to jeden z tych panów od UMLa
Czysty kod
Czysty kod
• Po prostu głęboko wierzymy że dobry
kod nam pomoże
• Choć nie wiemy jak, intuicyjnie
staramy się go stosować
• Z pokorą przyjmujemy karcący wzrok
mnicha
Nie wiemy że nie wiemy
• Uczymy się… bez wnikania w kontekst
 Nazywaj zmienne w taki a taki sposób
 Stosuj komentarze w takich a nie innych
przypadkach
 Dziel funkcje na części zgodnie z takimi
a takimi zasadami
• Z czasem zobaczymy że z czystym
kodem lepiej się pracuje… tak po
ludzku
Nasz mózg lepiej reaguje na czysty kod
• Utrzymujemy koncentrację
• Nie gubimy wątków, swobodniej
podążamy tokiem myślenia
• Cognitive load – możemy pomieścić
poszczególne kawałki kodu w głowie
więc potrafimy się miedzy nimi
swobodnie przemieszczać
• Nazwy
• Funkcje
• Komentarz
• Formowanie kodu
• Obiekty i struktury danych
• Obsługa błędów
Poziom I
• Nazwy
• Funkcje
• Komentarz
• Formatowanie kodu
• Obiekty i struktury danych
• Obsługa błędów
Poziom I
• Nazwy zmiennych, metod, klas
powinny być wystarczająco opisowe
aby zrozumieć jaką wartość
przetrzymuje zmienna i jaką czynność
wykonuje metoda.
Zmienne
• Nazwy nie powinny wymagać
dodawania komentarza
• Nazwy zmiennych nie mogą
wprowadzać w błąd!
• Nazwy metod nie mogą ukrywać
funkcjonalności!
Nazewnictwo
int d1; //dni od rozpoczęcia
int d2; //dni do zakończenia
int d3; //dni wolnych
int daysSinceStart;
int daysTillEnd;
int daysOf;
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>();
for (int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
} public List<int[]> getDates() {
List<int[]> dateList = new ArrayList<int[]>();
for (int[] week : theWeeksArray)
if (week[0] == BEGIN_DATE)
dateList.add(x);
return dateList;
}
for (int i=0; i<10; i++){
k += ((l[i]*1.5) / 3 );
}
float milleageRate;
const int NUMER_OF_EMPLOYEE = 3;
float sum = 0;
for ( int i=0; i<numberOfTrips; i++ ){
float totalCompensation = tripLength[i] * milleageRate;
float deduction = totalCompensation / NUMER_OF_EMPLOYEE;
sum += deduction;
}
• Korzystaj z nazw, które można
wymówić
Ułatwiają zapamiętywanie
Umożliwiają swobodną dyskusję o kodzie
Nazwewnictwo
public class CsmrDt {
public void crtshpcrt() {/*...*/};
public void remcrt() {/*...*/};
private final int ssntm = 10;
/*...*/
}
public class CustomerDataset {
public void createShoppingCart() {/*...*/};
public void removeCart() {/*...*/};
private final int sessionTimeout = 10;
/*...*/
}
• Używaj rzeczowników lub wyrażeń
rzeczownikowych do nazywania klas
np.: Customer, Account, Page
• Nie nazywaj klas za pomocą
czasowników
• Używaj nazw konkretnych a nie
“wszystkoznaczących”
ManagerFactoryProcessor
Klasy
• Używaj czasowników lub wyrażeń
czasownikowych do nazywania metod np.:
addUser, deleteCustomer, update
• Twórz nazwy metod tak, aby wyrażały to co
robią
Metody
• Nazwy powinny sugerować co zwracają
• Nazwy muszą mówić o całym zakresie
funkcjonalności
Metody
String findLastNameOfCustomerWithId(long customerId){...}
Map<Long, Customer> customers;
Customer getCustomer(Long id){
Customer customer = customers.get(id);
if(customer == null){
customer = createNewCustomer(id);
}
return customer;
}
• Bądź konsekwentny i używaj tych samych
słów do określania podobnych czynności,
np.: add, get, DeviceManager,
ProtocolController
Metody
• Nazwy
• Funkcje
• Komentarz
• Formatowanie kodu
• Obiekty i struktury danych
• Obsługa błędów
Poziom I
• Zasada pierwsza:
funkcje powinny być małe
• Zasada druga:
funkcje powinny być jeszcze mniejsze
Funkcje
Functions should do one thing.
Should do it well
Should do it only!
Funkcje
Funkcje
• Korzystaj z nazw dokładnie opisujących
przeznaczenie funkcji
• Nie obawiaj się konstruowania długich nazw
• Stosuj spójne nazwy - wykorzystuj te same frazy,
rzeczowniki czy czasowniki dla funkcji
wykonujących analogiczne operacje
• addCustomer, putItemToBasket
• UserSettings, AdminConfiguration
• Nie ukrywaj funkcjonalności za złymi nazwami
funkcji
Funkcje
• Pisz funkcje zawierające jak najmniejszą liczbę
argumentów
• Funkcją idealną jest funkcja bezargumentowa
• Dopuszczalne są funkcje
jedno- i dwuargumentowe
• Unikaj funkcji już z trzema argumentami
• Funkcje posiadające więcej niż trzy argumenty
stosuj tylko w uzasadnionych sytuacjach
writeField(outputStream, name);
outputStream.writeField(name);
createSquare(width, height);
calculateRectangularPrismVolume(double height,
double width, double depth);
calculateRectangularPrismVolume(Area rectangle,
double depth);
Funkcje
• Stosuj wyjątki zamiast zwracania
kodów błędów
• Korzystanie z kodów błędów tworzy
głęboko zagnieżdżone struktury
• Wyjątki pozwalają na oddzielenie
przetwarzania błędów od prawidłowej
ścieżki wykonywania kodu
if (changeDate(date) == OK) {
if (dateFilled(date) == OK) {
if (dateFromFuture(date) == OK) {
System.out.println("Data została zmieniona.");
} else {
System.out.println("Data niepoprawna.");
}
} else {
System.out.println("Brak podanej daty.");
}
} else {
System.out.println("Błąd podczas zmiany daty.");
return ERROR;
}
try {
changeDate(date);
dateFilled(date);
dateFromFuture(date);
}
catch (Exception e) {
System.out.println(e.getMessage());
}
Funkcje
DRY – Don’t repeat yourself
• Duplikacja zmniejsza czytelność
• Zwiększa koszty utrzymania, refactoringu i
poprawiania błędów
• Prowadzi do rozbieżności funkcjonalnej
modułów wykonujących to samo
• Zmniejsza reusability kodu
Funkcje
Jeden poziom abstrakcji na funkcje
• Nie realizuj w funkcji zadań które operują
na innych poziomach abstrakcji
• Pomieszane poziomy abstrakcji
zmniejszają czytelność kodu, utrudniają
zrozumienie logiki i prowadzą do
zwiększenia duplikacji kodu
• Nazwy
• Funkcje
• Komentarz
• Formatowanie kodu
• Obiekty i struktury danych
• Obsługa błędów
Poziom I
Komentarze
DON’T
Komentarze
„Nie komentuj złego kodu – popraw go”
Brian W. Kernighan i P.J. Plaugher
Komentarze
Są złe bo
• Często się powtarzają
• Są mylące
• Nadmiarowe
• Klamry zamykające
• Zakomentowany kod
• Informacje nielokalne
• Nie są utrzymywane
Komentarze
• Konieczność dodania komentarza
oznacza zazwyczaj kod do
poprawienia
• Napraw i uporządkuj zły kod a nie
komentuj
//Sprawdzenie czy klient ma możliwość korzystania ze zniżki
if (customer.isStudent() ||
(customer.age < 18) || (customer.age > 65))
if (customer.isEligibleForDiscount())
Komentarze
Bywają dobre, np:
• Komentarze prawne
• Komentarze informacyjne
• Wyjaśnienia
• Ostrzeżenia
• Komentarze TODO
// Dopasowany format kk:mm:ss EEE, MMM dd, yyyy
Pattern timeMacher = Pattern.compile("d*:d*:d*  w*, w* d*, d*")
Komentarze
• Nieprawdą jest, że wszystkie funkcje
powinny posiadać Javadoc, a każda
zmienna komentarz
• Ten typ komentarzy powoduje
zaciemnianie kodu i dezorganizację
public abstract class ContainerBase implements
Container, Lifecycle, Pipeline,
MBeanRegistration, Serializable {
/**
* The processor delay for this component.
*/
protected int backgroundProcessorDelay = -1;
/**
* The lifecycle event support for this component.
*/
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
/**
* The container event listeners for this Container.
*/
protected ArrayList listeners = new ArrayList();
/**
* The Loader implementation with which this Container is associated.
*/
protected Loader loader = null;
/**
* The Logger implementation with which this Container is associated.
*/
protected Log logger = null;
/**
* Associated logger name.
*/
protected String logName = null;
/**
* The Manager implementation with which this Container is associated.
*/
protected Manager manager = null;
„If you decide to write a comment, then
spend the time necessary to make sure it is
the best comment you can write”
Robert C. Martin
Komentarze
• Nazwy
• Funkcje
• Komentarz
• Formatowanie kodu
• Obiekty i struktury danych
• Obsługa błędów
Poziom I
Formatowanie
• Konwencje formatowania w zespole.
Ustal i się ich trzymaj
Formatowanie
• Odpowiednie formatowanie kodu
ułatwia czytanie klasy.
• Redukuje czas potrzebny na szukanie
składowych, konstruktorów itp.
• Nie musimy przeglądać całej klasy aby
sprawdzić czy ma konstruktor bo
wiemy dokładnie gdzie go szukać
• Nazwy
• Funkcje
• Komentarz
• Formatowanie kodu
• Obiekty i struktury danych
• Obsługa błędów
Poziom I
• Ukrywaj szczegóły techniczne i stosuj
terminy abstrakcyjne
Abstrakcja danych
public static interface Vehicle {
double getFuelTankCapacityInGallons();
double getGallonsOfGasoline();
}
public static interface Vehicle {
double getPercentFuelRemaining();
}
• Prawo Demeter – zasada minimalnej
wiedzy
• Moduł powinien nie wiedzieć nic o
wnętrzu obiektów, którymi manipuluje
Prawo Demeter
• Prawo Demeter głosi, że metoda f
klasy C powinna wywoływać tylko
metody z:
• Klasy C,
• Obiektu utworzonego przez f,
• Obiektu przekazanego jako argument f,
• Obiektu umieszczonego w zmiennej
instancyjnej klasy C.
Prawo Demeter
• Możesz bawić się ze sobą
• Możesz bawić się własnymi
zabawkami (ale nie możesz ich
rozbierać)
• Możesz bawić się zabawkami które
dostałeś
• Możesz bawić się zabawkami które
zrobiłeś samodzielnie
Prawo Demeter
final String outputDir = context.getOptions().getScratchDir().getAbsolutePath();
Options options = context.getOptions();
File scratchDir = options.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();
// before refactoring
class Customer {
String getMailingAddressLine1();
String getMailingAddressLine2();
String getShippingAddressLine1();
String getShippingAddressLine2();
}
class Employee {
String getHomeAddressLine1();
String getHomeAddressLine2();
}
public void method() {
customer.getMailingAddressLine1();
employee.getHomeAddressLine1();
}
// before refactoring
class Customer {
String getMailingAddressLine1();
String getMailingAddressLine2();
String getShippingAddressLine1();
String getShippingAddressLine2();
}
class Employee {
String getHomeAddressLine1();
String getHomeAddressLine2();
}
public void method() {
customer.getMailingAddressLine1();
employee.getHomeAddressLine1();
}
// after refactoring, before Demetering
class Address {
String getLine1();
String getLine2();
}
Class Customer {
Address getMailingAddress();
Address getShippingAddress();
}
class Employee {
Address getHomeAddress();
}
public void method() {
customer.getMailingAddress().getLine1();
employee.getHomeAddress().getLine1();
}
// before refactoring
class Customer {
String getMailingAddressLine1();
String getMailingAddressLine2();
String getShippingAddressLine1();
String getShippingAddressLine2();
}
class Employee {
String getHomeAddressLine1();
String getHomeAddressLine2();
}
public void method() {
customer.getMailingAddressLine1();
employee.getHomeAddressLine1();
}
// after refactoring, before Demetering
class Address {
String getLine1();
String getLine2();
}
Class Customer {
Address getMailingAddress();
Address getShippingAddress();
}
class Employee {
Address getHomeAddress();
}
public void method() {
customer.getMailingAddress().getLine1();
employee.getHomeAddress().getLine1();
}
//after Demeterizing
class Address { // same as above
String getLine1();
String getLine2();
}
class Customer {
Address getMailingAddress();
Address getShippingAddress();
String getMailingAddressLine1();
String getMailingAddressLine2();
String getShippingAddressLine1();
String getShippingAddressLine2();
}
class Employee {
Address getHomeAddress();
String getHomeAddressLine1();
String getHomeAddressLine2();
}
public void method() {
customer.getMailingAddressLine1();
employee.getHomeAddressLine1();
}
• Ukrywaj szczegóły wnętrza obiektów
• Nie łam hermetyzacji bez powodu,
łatwiejsze pisanie testów nie jest
powodem
Prawo Demeter
BufferedOutputStream bos =
context.createScratchFileStream(classFileName);
• Za idealną formę struktur danych
przyjmuje się obiekty transferu danych
(DTO)
• Są przydatne do komunikowania się z
bazą danych, analizowania
komunikatów z gniazd sieciowych itp.
Data Transfer Objects
• DTO są to mogą być klasy
pozbawione funkcji, ale ze zmiennymi
publicznymi
• Częściej spotykaną formą jest postać
typu beans
• Posiada ona zmienne prywatne, do
których dostęp uzyskuje się za
pomocą getterów i setterów
Data Transfer Objects
public class Client {
private String name;
private String lastName;
private long clientId;
public Client(long clientId, String name, String lastName) {
this.clientId = clientId;
this.name = name;
this.lastName = lastName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setlastName(String lastName) {
this.lastName = lastName;
}
public long getClientId() {
return clientId;
}
}
Budowanie oprogramowania z
wykorzystaniem struktur danych
wpływa w przyszłości na:
Budowanie oprogramowania z
wykorzystaniem obiektów wpływa na:
łatwość i elastyczność dodawania
nowych funkcji – dodanie nowej
funkcji nie wymaga zmiany żadnej ze
struktur
łatwość i elastyczność w dodawaniu
nowych obiektów – nie wymaga
zmiany żadnych funkcji ani innych
obiektów
trudność dodawania nowych struktur
– musimy zmienić wszystkie funkcje
trudność dodawania nowych funkcji –
musimy zmienić wszystkie obiekty
Obiekty vs struktury danych
• Nazwy
• Funkcje
• Komentarz
• Formatowanie kodu
• Obiekty i struktury danych
• Obsługa błędów
Poziom I
• Mówiliśmy o kodach błędu i wyjątkach
• O blokach try-catch-finally
• Grupuj wyjątki ze względu na kontekst i
zachowuj symetrię w kodzie
• Osłaniaj wyjątki:
• przechwytuj i przekształcaj zgłaszane wyjątki
• uniezależniaj się od wyjatków wprowadzonych przez
API, używaj wyjątków specyficznych dla własnej
aplikacji
Klasy wyjątków
ACMEPort port = new ACMEPort(12);
try {
port.open();
} catch (DeviceReponseException e) {
reportPortError(e);
logger.log("Wyjątek odpowiedzi urządzenia", e);
} catch (ATM1212UnlockedException e) {
reportPortError(e);
logger.log("Wyjątek odblokowania", e);
} catch (GMXError e) {
reportPortError(e);
logger.log("Wyjątek odpowiedzi urządzenia");
} finally {
/*...*/
}
ACMEPort port = new ACMEPort(12);
try {
port.open();
} catch (DeviceReponseException e) {
reportPortError(e);
logger.log("Wyjątek odpowiedzi urządzenia", e);
} catch (ATM1212UnlockedException e) {
reportPortError(e);
logger.log("Wyjątek odblokowania", e);
} catch (GMXError e) {
reportPortError(e);
logger.log("Wyjątek odpowiedzi urządzenia");
} finally {
/*...*/
}
LocalPort port = new LocalPort(12);
try {
port.open();
} catch (PortDeviceFailure e) {
reportError(e);
logger.log(e.getMessage(), e);
} finally {
/*...*/
}
public class LocalPort {
private ACMEPort innerPort;
public LocalPort(int portNumber) {
innerPort = new ACMEPort(portNumber);
}
public void open() {
try {
innerPort.open();
} catch (DeviceResponseException e) {
throw new PortDeviceFailure(e);
} catch (ATM1212UnlockedException e) {
throw new PortDeviceFailure(e);
} catch (GMXError e) {
throw new PortDeviceFailure(e);
}
}
/*...*/
}
Zwracanie null
DON’T
• Wykorzystuj zgłaszanie wyjątków lub
zwracanie obiektu specjalnego
przypadku
Zwracanie null
List<Item> items = getItems();
if (items != null) {
for (Item i : items) {
totalCost += i.getCost();
}
}
List<Item> items = getItems();
for(Item i : items) {
totalCost += i.getCost();
}
public interface Animal {
public void makeSound();
}
public class Dog implements Animal {
public void makeSound() {
System.out.println("woof!");
}
}
public class NullAnimal implements Animal {
public void makeSound() {
}
}
• Przekazywanie null jest gorsze od
jego zwracania
Przekazywanie null
public class MetricsCalculator {
public double rectanglePerimeterCalculate(
double x, double y) {
return 2 * (y + x);
}
/* ... */
}
• Defensive programming
Przekazywanie null
public class MetricsCalculator {
public double rectanglePerimeterCalculate(
double x, double y) {
if (x == null || y == null) {
throw InvalidArgumentException("Niewłaściwy
argument.");
}
return 2 * (y + x);
}
} public class MetricsCalculator {
public double rectanglePerimeterCalculate(
double x, double y) {
assert x != null : "x nie może być null";
assert y != null : "y nie może być null";
return 2 * (y + x);
}
}
Miara czystego kodu
Czysty projekt
• SOLID
• Zasady programowania obiektowego
• Zasady projektowania obiektowego
Poziom II
SOLIDny programista
• The Single Responsibility Principle – klasa
powinna mieć tylko jeden powód do zmiany
• The Open Closed Principle – klasę można
łatwo rozszerzać, nie modyfikując jej
• The Liskov Substitution Principle – klasy
pochodne muszą być przeźroczystymi
zamiennikami klasy nadrzędnej
• The Interface Segregation Principle – dla
różnych klientów twórz osobne interfejsy
• The Dependency Inversion Principle –
bądź zależny od abstrakcji a nie od
konkretnych implementacji
SOLIDny programista
• Należy znać hierarchię dziedziczenia, aby
zrozumieć metodę
• Kod metody polimorficznej jest rozrzucony
po kilku klasach
• Nie zawsze jest oczywisty stan obiektu, z
którego dziedziczymy
• Dodatkowe elementy (pola, metody) są
mocno związane (coupling) z klasą
nadrzędną
Kompozycja i dziedziczenie
• Niezależność klas zawieranych
• Można je używać w wielu kontekstach
• Niskie związanie (coupling)
• Łatwiej testować
Kompozycja i dziedziczenie
To znaczy jaki?
Kod obiektowy
• Odpowiedzialność – tylko jedna
 obiekty maja własną osobowość,
unikaj schizofrenicznych obiektów
• Enkapsulacja – to co się zmienia
enkaspuluj
• Preferencja kompozycji ponad
dziedziczenie
• Dokładanie ponad modyfikacje
– Gdy dodajemy nową funkcjonalność raczej dokładamy
nowe byty niż modyfikujemy istniejące.
• Lokalne zmiany
– Zmiana ma konsekwencje lokalne, a nie globalne.
Zasięg rażenia zmian jest jak najmniejszy.
• Nieinwazyjność zmian
– Dodanie nowych rzeczy (odpowiedzialności,
funkcjonalności, zachowań) do istniejących bytów jest
przezroczyste ich dla klientów.
public class Sql {
public Sql(String table, Column[] columns)
public String create()
public String insert(Object[] fields)
public String selectAll()
public String fieldByKey(
String keyColumn, String keyValue)
private String ColumnList(Column[] columns)
private String valuesList(
Object[] fields, final Column[] columns)
}
abstract public class Sql {
public Sql(String table, Column[] columns)
abstract public String generate();
}
public class CreateSql extends Sql {
public CreateSql(String table, Column[] columns)
@Override public String generate()
}
public class SelectSql extends Sql {
public SelectSql(String table, Column[] columns)
@Override public String generate()
}
public class InsertSql extends Sql {
public InsertSql(String table, Column[] columns)
@Override public String generate()
private String valuesList(Object[] fields, final Column[] columns)
}
public class FindKeyBySql extends Sql {
public FindKeyBySql(String table, Column[] columns, String keyColumn, String keyValue)
@Override public String generate()
}
public class ColumnList {
public ColumnList(Column[] columns)
public String generate()
}
Odpowiedzialność. Enkapsulacja. Kompozycja
• To co leży u podstaw możemy
stosować na każdym poziomie
• Projektując klasy
• Projektując moduły, komponenty
• Projektując systemy
• Każdy wzorzec opisujemy w trzech
kontekstach:
 Odpowiedzialność
 Enkapsulacja / hermetyzacja
 Kompozycja
Wzorce projektowe
• Rozdziela i przesłania implementację
zachowań, czynności.
• Hermetyzujemy zmienny sposób
tworzenia obiektów
• Nowe funkcjonalności uzyskujemy
poprzez dodawanie komend, poprzez
kompozycję.
Wzorce projektowe: komenda
Wzorce projektowe: komenda
• Każdy element systemu:
 Ma swoją odpowiedzialność
 Hermetyzuje pewne zachowania
 Składa się z kilku współpracujących
elementów
Moduły
• Boundary: zewnętrzny interfejs,
kontrakt, fasada
• Control: logika biznesowa,
implementacja
• Entity: persystencja
Boundary. Control. Entity
Entity. Control. Boundary
• Każdy framework opisujemy w trzech
zdaniach:
 Odpowiedzialność
 Enkapsulacja
 Preferowanie kompozycji
Frameworki
• Pozwala na obiektowy dostęp do bazy
danych
• Enkapsulujemy typ bazy, sposób
dostępu do danych
• Preferencja kompozycji (?)
ORM
• Nie ważne czy na poziomie klasy,
modułu, frameworka – stosujemy te
same bazowe pojęcia
• Dedukujemy, indukujemy –
posługujemy się doświadczeniem
• Rozumiemy że nie ma uniwersalnych
rozwiązań – ważny jest kontekst.
• Spring czy EJB
Nie ma idealnych rozwiązań
• Spring czy EJB
• JSF czy JSP
Nie ma idealnych rozwiązań
• Spring czy EJB
• JSF czy JSP czy Velocity
Nie ma idealnych rozwiązań
• Spring czy EJB
• JSF czy JSP czy Velocity
• JPA czy iBatis
Nie ma idealnych rozwiązań
• Spring czy EJB
• JSF czy JSP czy Velocity
• JPA czy iBatis czy JDBC
Nie ma idealnych rozwiązań
• Spring czy EJB
• JSF czy JSP czy Velocity
• JPA czy iBatis czy JDBC
• MVC czy MVP
Nie ma idealnych rozwiązań
• Spring czy EJB
• JSF czy JSP czy Velocity
• JPA czy iBatis czy JDBC
• MVC czy MVP
• Java czy .NET
Nie ma idealnych rozwiązań
• Spring czy EJB
• JSF czy JSP czy Velocity
• JPA czy iBatis czy JDBC
• MVC czy MVP
• Java czy .NET czy Python
Nie ma idealnych rozwiązań
• Spring czy EJB
• JSF czy JSP czy Velocity
• JPA czy iBatis czy JDBC
• MVC czy MVP
• Java czy .NET czy Python czy PHP
Nie ma idealnych rozwiązań
Po co to wszystko?
Build better systems
Complexity and confusion
Complexity and confusion
Bo nasz mózg pracuje zupełnie inaczej
Affordance
Affordance
a quality of an object, which
allows an individual to perform
an action. For example, a knob
affords twisting, and perhaps
pushing, while a cord affords
pulling
public class Sql {
public Sql(String table, Column[] columns)
public String create()
public String insert(Object[] fields)
public String selectAll()
public String fieldByKey(
String keyColumn, String keyValue)
private String ColumnList(Column[] columns)
private String valuesList(
Object[] fields, final Column[] columns)
}
abstract public class Sql {
public Sql(String table, Column[] columns)
abstract public String generate();
}
public class CreateSql extends Sql {
public CreateSql(String table, Column[] columns)
@Override public String generate()
}
public class SelectSql extends Sql {
public SelectSql(String table, Column[] columns)
@Override public String generate()
}
public class InsertSql extends Sql {
public InsertSql(String table, Column[] columns)
@Override public String generate()
private String valuesList(Object[] fields, final Column[] columns)
}
public class FindKeyBySql extends Sql {
public FindKeyBySql(String table, Column[] columns, String keyColumn, String keyValue)
@Override public String generate()
}
public class ColumnList {
public ColumnList(Column[] columns)
public String generate()
}
George Miller
Multi store memory model
Mihaly Csikszentmigalyi
ME-HI CHICKS-SENT-ME-HI
Po co to wszystko?
Budujemy nawyki
Nie po to aby było ładnie
Nie aby było elegancko
By żyło się lepiej
• Pytamy doświadczonego kolegę
Co robimy gdy robi się gorąco
• Pytamy doświadczonego kolegę
• Sami szukamy drogi
Co robimy gdy robi się gorąco
• Pytamy doświadczonego kolegę
• Sami szukamy drogi
• Próbujemy na siłę
Co robimy gdy robi się gorąco
• Pytamy doświadczonego kolegę
• Sami szukamy drogi
• Próbujemy na siłę
• Porzucamy i wracamy do
nawyków
Co robimy gdy robi się gorąco
Single
Responsibility
Open Closes
Principle
Liskov Substitution
Interface
Segregation
Dependency
Injection
Singletons
Tight Coupling
Untestable Code
Premature
Optimization
Indescriptive
Naming
Duplication
Single
Responsibility
Open Closes
Principle
Liskov Substitution
Interface
Segregation
Dependency
Injection
Singletons
Tight Coupling
Untestable Code
Premature
Optimization
Indescriptive
Naming
Duplication
• Nie ma kodu perfekcyjnego
• Ale jest wystarczająco dobry
 modyfikowalny
 refaktoryzowalny
 „disposible” over „maintainable”
• Kod który mogę w każdej chwili
wyrzucić i wymienić
Tworzymy dobry kod
Jak żyć?
Jak żyć?
Jak żyć?
Jak żyć?
Jak żyć?
Jak żyć?
2010
Jak żyć?
2010
Jak żyć?
2010
2009
Jak żyć?
2010
2009
Jak żyć?
2010
2009
Jak żyć?
2010
2009
2009
Jak żyć?
2010
2009
2009
Jak żyć?
2010
2009
2009
2008
Jak żyć?
2010
2009
2009
2008
Jak żyć?
2010
2009
2009
2008
2007
Jak żyć?
Jak żyć?
2002
Jak żyć?
2002
Jak żyć?
2002
1996 / 2000
Jak żyć?
2002
1996 / 2000
Jak żyć?
2002
1996 / 2000
2002
Jak żyć?
2002
1996 / 2000
2002
Jak żyć?
2002
1996 / 2000
2002
1994
Jak żyć?
Jak żyć?
Shu-Ha-Ri
jmarchwicki@ydp.eu
http://marchwicki.pl/blog
@kubem
Shu-Ha-Ri

More Related Content

Similar to [PL] Jak programować aby nie zwariować?

Tworzenie i utrzymywanie czystego kodu
Tworzenie i utrzymywanie czystego koduTworzenie i utrzymywanie czystego kodu
Tworzenie i utrzymywanie czystego kodupabloware
 
[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariować[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariowaćJakub Marchwicki
 
Pułapki programowania obiektowego
Pułapki programowania obiektowego Pułapki programowania obiektowego
Pułapki programowania obiektowego Adam Sawicki
 
Confitura 2015 - Code Quality Keepers @ Allegro
Confitura 2015 - Code Quality Keepers @ AllegroConfitura 2015 - Code Quality Keepers @ Allegro
Confitura 2015 - Code Quality Keepers @ Allegroallegro.tech
 
Jak stworzyć udany system informatyczny
Jak stworzyć udany system informatycznyJak stworzyć udany system informatyczny
Jak stworzyć udany system informatycznyqbeuek
 
Porażka nie wchodzi w grę, czyli o niezawodności
Porażka nie wchodzi w grę, czyli o niezawodnościPorażka nie wchodzi w grę, czyli o niezawodności
Porażka nie wchodzi w grę, czyli o niezawodnościKamil Grabowski
 
[Pl] conversation patterns for software professionals
[Pl] conversation patterns for software professionals[Pl] conversation patterns for software professionals
[Pl] conversation patterns for software professionalsMichał Bartyzel
 
Jak efektywnie podejść do certyfikacji w AWS?
Jak efektywnie podejść do certyfikacji w AWS?Jak efektywnie podejść do certyfikacji w AWS?
Jak efektywnie podejść do certyfikacji w AWS?The Software House
 
Jak zepsułem produkt kilka lekcji pokory - World Usability Day - Igor Farafon...
Jak zepsułem produkt kilka lekcji pokory - World Usability Day - Igor Farafon...Jak zepsułem produkt kilka lekcji pokory - World Usability Day - Igor Farafon...
Jak zepsułem produkt kilka lekcji pokory - World Usability Day - Igor Farafon...Uxeria
 
Mity, które blokują Twoją karierę
Mity, które blokują Twoją karieręMity, które blokują Twoją karierę
Mity, które blokują Twoją karieręPiotr Horzycki
 
Unit testing w praktyce... czyli właściwie jak?
Unit testing w praktyce... czyli właściwie jak?Unit testing w praktyce... czyli właściwie jak?
Unit testing w praktyce... czyli właściwie jak?Bartłomiej Cymanowski
 
Od codziennej higieny do strategicznej refaktoryzacji
Od codziennej higieny do strategicznej refaktoryzacjiOd codziennej higieny do strategicznej refaktoryzacji
Od codziennej higieny do strategicznej refaktoryzacjiMichał Bartyzel
 
Design principles 4 hackers - tech3camp (28142014)
Design principles 4 hackers - tech3camp (28142014)Design principles 4 hackers - tech3camp (28142014)
Design principles 4 hackers - tech3camp (28142014)Jakub Marchwicki
 
Praktyczne code reviews - PHPConPl
Praktyczne code reviews - PHPConPlPraktyczne code reviews - PHPConPl
Praktyczne code reviews - PHPConPlSebastian Marek
 
Patterns for organic architecture
Patterns for organic architecturePatterns for organic architecture
Patterns for organic architectureJaroslaw Palka
 

Similar to [PL] Jak programować aby nie zwariować? (20)

Tworzenie i utrzymywanie czystego kodu
Tworzenie i utrzymywanie czystego koduTworzenie i utrzymywanie czystego kodu
Tworzenie i utrzymywanie czystego kodu
 
Refaktoryzacja
RefaktoryzacjaRefaktoryzacja
Refaktoryzacja
 
[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariować[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariować
 
Pułapki programowania obiektowego
Pułapki programowania obiektowego Pułapki programowania obiektowego
Pułapki programowania obiektowego
 
Clean code w Ruby
Clean code w RubyClean code w Ruby
Clean code w Ruby
 
Confitura 2015 - Code Quality Keepers @ Allegro
Confitura 2015 - Code Quality Keepers @ AllegroConfitura 2015 - Code Quality Keepers @ Allegro
Confitura 2015 - Code Quality Keepers @ Allegro
 
Jak stworzyć udany system informatyczny
Jak stworzyć udany system informatycznyJak stworzyć udany system informatyczny
Jak stworzyć udany system informatyczny
 
Porażka nie wchodzi w grę, czyli o niezawodności
Porażka nie wchodzi w grę, czyli o niezawodnościPorażka nie wchodzi w grę, czyli o niezawodności
Porażka nie wchodzi w grę, czyli o niezawodności
 
[Pl] conversation patterns for software professionals
[Pl] conversation patterns for software professionals[Pl] conversation patterns for software professionals
[Pl] conversation patterns for software professionals
 
Jak efektywnie podejść do certyfikacji w AWS?
Jak efektywnie podejść do certyfikacji w AWS?Jak efektywnie podejść do certyfikacji w AWS?
Jak efektywnie podejść do certyfikacji w AWS?
 
Jak zepsułem produkt kilka lekcji pokory - World Usability Day - Igor Farafon...
Jak zepsułem produkt kilka lekcji pokory - World Usability Day - Igor Farafon...Jak zepsułem produkt kilka lekcji pokory - World Usability Day - Igor Farafon...
Jak zepsułem produkt kilka lekcji pokory - World Usability Day - Igor Farafon...
 
Mity, które blokują Twoją karierę
Mity, które blokują Twoją karieręMity, które blokują Twoją karierę
Mity, które blokują Twoją karierę
 
Unit testing w praktyce... czyli właściwie jak?
Unit testing w praktyce... czyli właściwie jak?Unit testing w praktyce... czyli właściwie jak?
Unit testing w praktyce... czyli właściwie jak?
 
Od codziennej higieny do strategicznej refaktoryzacji
Od codziennej higieny do strategicznej refaktoryzacjiOd codziennej higieny do strategicznej refaktoryzacji
Od codziennej higieny do strategicznej refaktoryzacji
 
M4j3
M4j3M4j3
M4j3
 
M4j3
M4j3M4j3
M4j3
 
Design principles 4 hackers - tech3camp (28142014)
Design principles 4 hackers - tech3camp (28142014)Design principles 4 hackers - tech3camp (28142014)
Design principles 4 hackers - tech3camp (28142014)
 
Praktyczne code reviews - PHPConPl
Praktyczne code reviews - PHPConPlPraktyczne code reviews - PHPConPl
Praktyczne code reviews - PHPConPl
 
Praktyki techniczne
Praktyki technicznePraktyki techniczne
Praktyki techniczne
 
Patterns for organic architecture
Patterns for organic architecturePatterns for organic architecture
Patterns for organic architecture
 

More from Jakub Marchwicki

Test with Spock like the first officer
Test with Spock like the first officerTest with Spock like the first officer
Test with Spock like the first officerJakub Marchwicki
 
GeeCON 2013 - EJB application guided by tests
GeeCON 2013 - EJB application guided by testsGeeCON 2013 - EJB application guided by tests
GeeCON 2013 - EJB application guided by testsJakub Marchwicki
 
GeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingGeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingJakub Marchwicki
 
[PL] Metadane - dane o danych
[PL] Metadane - dane o danych[PL] Metadane - dane o danych
[PL] Metadane - dane o danychJakub Marchwicki
 
[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancjiJakub Marchwicki
 

More from Jakub Marchwicki (6)

Test with Spock like the first officer
Test with Spock like the first officerTest with Spock like the first officer
Test with Spock like the first officer
 
JEE.next()
JEE.next()JEE.next()
JEE.next()
 
GeeCON 2013 - EJB application guided by tests
GeeCON 2013 - EJB application guided by testsGeeCON 2013 - EJB application guided by tests
GeeCON 2013 - EJB application guided by tests
 
GeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testingGeeCON 2012 hurdle run through ejb testing
GeeCON 2012 hurdle run through ejb testing
 
[PL] Metadane - dane o danych
[PL] Metadane - dane o danych[PL] Metadane - dane o danych
[PL] Metadane - dane o danych
 
[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji[PL] O klasycznej, programistycznej elegancji
[PL] O klasycznej, programistycznej elegancji
 

[PL] Jak programować aby nie zwariować?

  • 1. Jak programować aby nie zwariować? Jakub Marchwicki 04.04.2013
  • 3. Co to za gość?
  • 4. Co ja tu robię?
  • 5. Co ja tu robię?
  • 6. Co ja tu robię?
  • 7. Co ja tu robię?ból
  • 8. Co ja tu robię?ból liczba slajdów
  • 9. Co ja tu robię?ból liczba slajdów OK Ryzyko utraty zdrowia 35 slajdów
  • 10. Co ja tu robię?ból liczba slajdów OK Ryzyko utraty zdrowia 205 slajdów
  • 11.
  • 12. I po co to wszystko? Bo software to nasze hobby
  • 13. I po co to wszystko? Bo software to nasze hobby fach
  • 14. I po co to wszystko? Bo software to nasze hobby fach zawód
  • 15. I po co to wszystko? Bo software to nasze hobby fach zawód przyjemność
  • 16. I po co to wszystko? bo płacą nam za pisanie dokumentacji pisanie kodu to przyjemność
  • 19. Kiedy software jest dobry? Oprogramowanie musi działać Musi być na czas Musi być rozbudowywalne Modyfikowalne Musi mieć odpowiednią jakość Punkt wyjścia
  • 20. Kiedy software jest dobry? Oprogramowanie musi działać Musi być na czas Musi być rozbudowywalne Modyfikowalne Musi mieć odpowiednią jakość To zależy??? Punkt wyjścia
  • 21. Więc czym jest jakość Dla kogoś Dla siebie Dla kogo pracuje?
  • 22. Więc czym jest jakość Dla kogoś Dla siebie Dla kogo pracuje?
  • 23. „Jakość (jak piękno) jest sądem wartościującym, wyrażonym przez użytkownika. Jeśli nie ma takiego użytkownika – nie ma takiego sądu” Platon Więc czym jest jakość
  • 24. Więc czym jest jakość Dla kogoś Dla siebie Dla kogo pracuje?
  • 25. „Jakość to sposób myślenia, który powoduje, że stosuje się i bez przerwy poszukuje najlepszych rozwiązań” William Edwards Deming Więc czym jest jakość
  • 27. If design is a hypothesis how can you prove it? Czy mój software jest dobrej jakości?
  • 28. Czy mój software jest dobrej jakości? Oprogramowanie musi działać Musi być na czas Musi być rozbudowywalne Modyfikowalne Musi mieć odpowiednią jakość
  • 29. Jak programować aby nie zwariować?
  • 31. Konkretyzacja pewnej idei Wprowadzenie uporządkowanego sposoby pracy Ujęcie złożonych czynności w zestaw powtarzalnych kroków Framework to pewna obietnica
  • 32. No więc mamy to zadanie I ten ciekawy framework … Wyobraźmy sobie nowy projekt…
  • 33. …w którym framework nie zadziałał
  • 37. Porzucamy framework i robimy po staremu
  • 38. I jeżeli ma szczęście do pierwszy dwóch
  • 40. • Kod jest podstawowym medium komunikacji w projekcie • Zły kod to jak solenie herbaty koledze z zespołu albo plucie do kanapki – a przecież nie jesteśmy złośliwi Wartości
  • 41. • Jako zespół jesteśmy jednością – Jak ja pójdę na skróty, to kolega będzie się męczył – I jako całość i tak będziemy nieefektywni Wartości
  • 42.
  • 43. • Programy są częściej czytane niż pisane • Więcej czasu poświęcamy na modyfikację istniejącego kodu niż na tworzenie nowego Implementation Patterns
  • 44.
  • 45. • Komunikacja – kod źródłowy powinno się czytać jak książkę • Prostota – wprowadzaj złożoność tylko wtedy, kiedy jest to konieczne • Elastyczność – elastyczność to dodatkowa złożoność, więc wprowadzaj ją tylko tam gdzie to konieczne Implementation patterns
  • 46. • Lokalne konsekwencje – zmiana w jednym miejscu nie powoduje zmian w innych • Minimalne powtórzenia – DRY Implementation patterns
  • 47. • Dane i logika razem – ponieważ dane i logika z reguły zmieniają się w tym samym czasie • Symetria – utrzymuj podobny poziom abstrakcji w obrębie metody / klasy Implementation patterns
  • 48. „Czysty kod jest prosty i bezpośredni. Czysty kod czyta się jak dobrze napisaną prozę. Czysty kod nigdy nie zaciemnia zamiarów projektanta; jest pełen trafnych abstrakcji i prostych ścieżek sterowania.” Grady Booch – to jeden z tych panów od UMLa
  • 51. • Po prostu głęboko wierzymy że dobry kod nam pomoże • Choć nie wiemy jak, intuicyjnie staramy się go stosować • Z pokorą przyjmujemy karcący wzrok mnicha Nie wiemy że nie wiemy
  • 52. • Uczymy się… bez wnikania w kontekst  Nazywaj zmienne w taki a taki sposób  Stosuj komentarze w takich a nie innych przypadkach  Dziel funkcje na części zgodnie z takimi a takimi zasadami • Z czasem zobaczymy że z czystym kodem lepiej się pracuje… tak po ludzku
  • 53. Nasz mózg lepiej reaguje na czysty kod • Utrzymujemy koncentrację • Nie gubimy wątków, swobodniej podążamy tokiem myślenia • Cognitive load – możemy pomieścić poszczególne kawałki kodu w głowie więc potrafimy się miedzy nimi swobodnie przemieszczać
  • 54. • Nazwy • Funkcje • Komentarz • Formowanie kodu • Obiekty i struktury danych • Obsługa błędów Poziom I
  • 55. • Nazwy • Funkcje • Komentarz • Formatowanie kodu • Obiekty i struktury danych • Obsługa błędów Poziom I
  • 56. • Nazwy zmiennych, metod, klas powinny być wystarczająco opisowe aby zrozumieć jaką wartość przetrzymuje zmienna i jaką czynność wykonuje metoda. Zmienne
  • 57. • Nazwy nie powinny wymagać dodawania komentarza • Nazwy zmiennych nie mogą wprowadzać w błąd! • Nazwy metod nie mogą ukrywać funkcjonalności! Nazewnictwo
  • 58. int d1; //dni od rozpoczęcia int d2; //dni do zakończenia int d3; //dni wolnych int daysSinceStart; int daysTillEnd; int daysOf; public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>(); for (int[] x : theList) if (x[0] == 4) list1.add(x); return list1; } public List<int[]> getDates() { List<int[]> dateList = new ArrayList<int[]>(); for (int[] week : theWeeksArray) if (week[0] == BEGIN_DATE) dateList.add(x); return dateList; }
  • 59. for (int i=0; i<10; i++){ k += ((l[i]*1.5) / 3 ); } float milleageRate; const int NUMER_OF_EMPLOYEE = 3; float sum = 0; for ( int i=0; i<numberOfTrips; i++ ){ float totalCompensation = tripLength[i] * milleageRate; float deduction = totalCompensation / NUMER_OF_EMPLOYEE; sum += deduction; }
  • 60. • Korzystaj z nazw, które można wymówić Ułatwiają zapamiętywanie Umożliwiają swobodną dyskusję o kodzie Nazwewnictwo
  • 61. public class CsmrDt { public void crtshpcrt() {/*...*/}; public void remcrt() {/*...*/}; private final int ssntm = 10; /*...*/ } public class CustomerDataset { public void createShoppingCart() {/*...*/}; public void removeCart() {/*...*/}; private final int sessionTimeout = 10; /*...*/ }
  • 62. • Używaj rzeczowników lub wyrażeń rzeczownikowych do nazywania klas np.: Customer, Account, Page • Nie nazywaj klas za pomocą czasowników • Używaj nazw konkretnych a nie “wszystkoznaczących” ManagerFactoryProcessor Klasy
  • 63. • Używaj czasowników lub wyrażeń czasownikowych do nazywania metod np.: addUser, deleteCustomer, update • Twórz nazwy metod tak, aby wyrażały to co robią Metody
  • 64. • Nazwy powinny sugerować co zwracają • Nazwy muszą mówić o całym zakresie funkcjonalności Metody String findLastNameOfCustomerWithId(long customerId){...} Map<Long, Customer> customers; Customer getCustomer(Long id){ Customer customer = customers.get(id); if(customer == null){ customer = createNewCustomer(id); } return customer; }
  • 65. • Bądź konsekwentny i używaj tych samych słów do określania podobnych czynności, np.: add, get, DeviceManager, ProtocolController Metody
  • 66. • Nazwy • Funkcje • Komentarz • Formatowanie kodu • Obiekty i struktury danych • Obsługa błędów Poziom I
  • 67. • Zasada pierwsza: funkcje powinny być małe • Zasada druga: funkcje powinny być jeszcze mniejsze Funkcje
  • 68. Functions should do one thing. Should do it well Should do it only! Funkcje
  • 69.
  • 70.
  • 71. Funkcje • Korzystaj z nazw dokładnie opisujących przeznaczenie funkcji • Nie obawiaj się konstruowania długich nazw • Stosuj spójne nazwy - wykorzystuj te same frazy, rzeczowniki czy czasowniki dla funkcji wykonujących analogiczne operacje • addCustomer, putItemToBasket • UserSettings, AdminConfiguration • Nie ukrywaj funkcjonalności za złymi nazwami funkcji
  • 72. Funkcje • Pisz funkcje zawierające jak najmniejszą liczbę argumentów • Funkcją idealną jest funkcja bezargumentowa • Dopuszczalne są funkcje jedno- i dwuargumentowe • Unikaj funkcji już z trzema argumentami • Funkcje posiadające więcej niż trzy argumenty stosuj tylko w uzasadnionych sytuacjach
  • 73. writeField(outputStream, name); outputStream.writeField(name); createSquare(width, height); calculateRectangularPrismVolume(double height, double width, double depth); calculateRectangularPrismVolume(Area rectangle, double depth);
  • 74. Funkcje • Stosuj wyjątki zamiast zwracania kodów błędów • Korzystanie z kodów błędów tworzy głęboko zagnieżdżone struktury • Wyjątki pozwalają na oddzielenie przetwarzania błędów od prawidłowej ścieżki wykonywania kodu
  • 75. if (changeDate(date) == OK) { if (dateFilled(date) == OK) { if (dateFromFuture(date) == OK) { System.out.println("Data została zmieniona."); } else { System.out.println("Data niepoprawna."); } } else { System.out.println("Brak podanej daty."); } } else { System.out.println("Błąd podczas zmiany daty."); return ERROR; } try { changeDate(date); dateFilled(date); dateFromFuture(date); } catch (Exception e) { System.out.println(e.getMessage()); }
  • 76. Funkcje DRY – Don’t repeat yourself • Duplikacja zmniejsza czytelność • Zwiększa koszty utrzymania, refactoringu i poprawiania błędów • Prowadzi do rozbieżności funkcjonalnej modułów wykonujących to samo • Zmniejsza reusability kodu
  • 77. Funkcje Jeden poziom abstrakcji na funkcje • Nie realizuj w funkcji zadań które operują na innych poziomach abstrakcji • Pomieszane poziomy abstrakcji zmniejszają czytelność kodu, utrudniają zrozumienie logiki i prowadzą do zwiększenia duplikacji kodu
  • 78.
  • 79.
  • 80. • Nazwy • Funkcje • Komentarz • Formatowanie kodu • Obiekty i struktury danych • Obsługa błędów Poziom I
  • 82. Komentarze „Nie komentuj złego kodu – popraw go” Brian W. Kernighan i P.J. Plaugher
  • 83. Komentarze Są złe bo • Często się powtarzają • Są mylące • Nadmiarowe • Klamry zamykające • Zakomentowany kod • Informacje nielokalne • Nie są utrzymywane
  • 84. Komentarze • Konieczność dodania komentarza oznacza zazwyczaj kod do poprawienia • Napraw i uporządkuj zły kod a nie komentuj
  • 85. //Sprawdzenie czy klient ma możliwość korzystania ze zniżki if (customer.isStudent() || (customer.age < 18) || (customer.age > 65)) if (customer.isEligibleForDiscount())
  • 86. Komentarze Bywają dobre, np: • Komentarze prawne • Komentarze informacyjne • Wyjaśnienia • Ostrzeżenia • Komentarze TODO // Dopasowany format kk:mm:ss EEE, MMM dd, yyyy Pattern timeMacher = Pattern.compile("d*:d*:d* w*, w* d*, d*")
  • 87. Komentarze • Nieprawdą jest, że wszystkie funkcje powinny posiadać Javadoc, a każda zmienna komentarz • Ten typ komentarzy powoduje zaciemnianie kodu i dezorganizację
  • 88. public abstract class ContainerBase implements Container, Lifecycle, Pipeline, MBeanRegistration, Serializable { /** * The processor delay for this component. */ protected int backgroundProcessorDelay = -1; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * The container event listeners for this Container. */ protected ArrayList listeners = new ArrayList(); /** * The Loader implementation with which this Container is associated. */ protected Loader loader = null; /** * The Logger implementation with which this Container is associated. */ protected Log logger = null; /** * Associated logger name. */ protected String logName = null; /** * The Manager implementation with which this Container is associated. */ protected Manager manager = null;
  • 89. „If you decide to write a comment, then spend the time necessary to make sure it is the best comment you can write” Robert C. Martin Komentarze
  • 90. • Nazwy • Funkcje • Komentarz • Formatowanie kodu • Obiekty i struktury danych • Obsługa błędów Poziom I
  • 91. Formatowanie • Konwencje formatowania w zespole. Ustal i się ich trzymaj
  • 92. Formatowanie • Odpowiednie formatowanie kodu ułatwia czytanie klasy. • Redukuje czas potrzebny na szukanie składowych, konstruktorów itp. • Nie musimy przeglądać całej klasy aby sprawdzić czy ma konstruktor bo wiemy dokładnie gdzie go szukać
  • 93.
  • 94. • Nazwy • Funkcje • Komentarz • Formatowanie kodu • Obiekty i struktury danych • Obsługa błędów Poziom I
  • 95. • Ukrywaj szczegóły techniczne i stosuj terminy abstrakcyjne Abstrakcja danych public static interface Vehicle { double getFuelTankCapacityInGallons(); double getGallonsOfGasoline(); } public static interface Vehicle { double getPercentFuelRemaining(); }
  • 96. • Prawo Demeter – zasada minimalnej wiedzy • Moduł powinien nie wiedzieć nic o wnętrzu obiektów, którymi manipuluje Prawo Demeter
  • 97. • Prawo Demeter głosi, że metoda f klasy C powinna wywoływać tylko metody z: • Klasy C, • Obiektu utworzonego przez f, • Obiektu przekazanego jako argument f, • Obiektu umieszczonego w zmiennej instancyjnej klasy C. Prawo Demeter
  • 98. • Możesz bawić się ze sobą • Możesz bawić się własnymi zabawkami (ale nie możesz ich rozbierać) • Możesz bawić się zabawkami które dostałeś • Możesz bawić się zabawkami które zrobiłeś samodzielnie Prawo Demeter
  • 99. final String outputDir = context.getOptions().getScratchDir().getAbsolutePath(); Options options = context.getOptions(); File scratchDir = options.getScratchDir(); final String outputDir = scratchDir.getAbsolutePath();
  • 100. // before refactoring class Customer { String getMailingAddressLine1(); String getMailingAddressLine2(); String getShippingAddressLine1(); String getShippingAddressLine2(); } class Employee { String getHomeAddressLine1(); String getHomeAddressLine2(); } public void method() { customer.getMailingAddressLine1(); employee.getHomeAddressLine1(); }
  • 101. // before refactoring class Customer { String getMailingAddressLine1(); String getMailingAddressLine2(); String getShippingAddressLine1(); String getShippingAddressLine2(); } class Employee { String getHomeAddressLine1(); String getHomeAddressLine2(); } public void method() { customer.getMailingAddressLine1(); employee.getHomeAddressLine1(); } // after refactoring, before Demetering class Address { String getLine1(); String getLine2(); } Class Customer { Address getMailingAddress(); Address getShippingAddress(); } class Employee { Address getHomeAddress(); } public void method() { customer.getMailingAddress().getLine1(); employee.getHomeAddress().getLine1(); }
  • 102. // before refactoring class Customer { String getMailingAddressLine1(); String getMailingAddressLine2(); String getShippingAddressLine1(); String getShippingAddressLine2(); } class Employee { String getHomeAddressLine1(); String getHomeAddressLine2(); } public void method() { customer.getMailingAddressLine1(); employee.getHomeAddressLine1(); } // after refactoring, before Demetering class Address { String getLine1(); String getLine2(); } Class Customer { Address getMailingAddress(); Address getShippingAddress(); } class Employee { Address getHomeAddress(); } public void method() { customer.getMailingAddress().getLine1(); employee.getHomeAddress().getLine1(); } //after Demeterizing class Address { // same as above String getLine1(); String getLine2(); } class Customer { Address getMailingAddress(); Address getShippingAddress(); String getMailingAddressLine1(); String getMailingAddressLine2(); String getShippingAddressLine1(); String getShippingAddressLine2(); } class Employee { Address getHomeAddress(); String getHomeAddressLine1(); String getHomeAddressLine2(); } public void method() { customer.getMailingAddressLine1(); employee.getHomeAddressLine1(); }
  • 103. • Ukrywaj szczegóły wnętrza obiektów • Nie łam hermetyzacji bez powodu, łatwiejsze pisanie testów nie jest powodem Prawo Demeter BufferedOutputStream bos = context.createScratchFileStream(classFileName);
  • 104. • Za idealną formę struktur danych przyjmuje się obiekty transferu danych (DTO) • Są przydatne do komunikowania się z bazą danych, analizowania komunikatów z gniazd sieciowych itp. Data Transfer Objects
  • 105. • DTO są to mogą być klasy pozbawione funkcji, ale ze zmiennymi publicznymi • Częściej spotykaną formą jest postać typu beans • Posiada ona zmienne prywatne, do których dostęp uzyskuje się za pomocą getterów i setterów Data Transfer Objects
  • 106. public class Client { private String name; private String lastName; private long clientId; public Client(long clientId, String name, String lastName) { this.clientId = clientId; this.name = name; this.lastName = lastName; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLastName() { return lastName; } public void setlastName(String lastName) { this.lastName = lastName; } public long getClientId() { return clientId; } }
  • 107. Budowanie oprogramowania z wykorzystaniem struktur danych wpływa w przyszłości na: Budowanie oprogramowania z wykorzystaniem obiektów wpływa na: łatwość i elastyczność dodawania nowych funkcji – dodanie nowej funkcji nie wymaga zmiany żadnej ze struktur łatwość i elastyczność w dodawaniu nowych obiektów – nie wymaga zmiany żadnych funkcji ani innych obiektów trudność dodawania nowych struktur – musimy zmienić wszystkie funkcje trudność dodawania nowych funkcji – musimy zmienić wszystkie obiekty Obiekty vs struktury danych
  • 108. • Nazwy • Funkcje • Komentarz • Formatowanie kodu • Obiekty i struktury danych • Obsługa błędów Poziom I
  • 109. • Mówiliśmy o kodach błędu i wyjątkach • O blokach try-catch-finally
  • 110. • Grupuj wyjątki ze względu na kontekst i zachowuj symetrię w kodzie • Osłaniaj wyjątki: • przechwytuj i przekształcaj zgłaszane wyjątki • uniezależniaj się od wyjatków wprowadzonych przez API, używaj wyjątków specyficznych dla własnej aplikacji Klasy wyjątków
  • 111. ACMEPort port = new ACMEPort(12); try { port.open(); } catch (DeviceReponseException e) { reportPortError(e); logger.log("Wyjątek odpowiedzi urządzenia", e); } catch (ATM1212UnlockedException e) { reportPortError(e); logger.log("Wyjątek odblokowania", e); } catch (GMXError e) { reportPortError(e); logger.log("Wyjątek odpowiedzi urządzenia"); } finally { /*...*/ }
  • 112. ACMEPort port = new ACMEPort(12); try { port.open(); } catch (DeviceReponseException e) { reportPortError(e); logger.log("Wyjątek odpowiedzi urządzenia", e); } catch (ATM1212UnlockedException e) { reportPortError(e); logger.log("Wyjątek odblokowania", e); } catch (GMXError e) { reportPortError(e); logger.log("Wyjątek odpowiedzi urządzenia"); } finally { /*...*/ } LocalPort port = new LocalPort(12); try { port.open(); } catch (PortDeviceFailure e) { reportError(e); logger.log(e.getMessage(), e); } finally { /*...*/ } public class LocalPort { private ACMEPort innerPort; public LocalPort(int portNumber) { innerPort = new ACMEPort(portNumber); } public void open() { try { innerPort.open(); } catch (DeviceResponseException e) { throw new PortDeviceFailure(e); } catch (ATM1212UnlockedException e) { throw new PortDeviceFailure(e); } catch (GMXError e) { throw new PortDeviceFailure(e); } } /*...*/ }
  • 114. • Wykorzystuj zgłaszanie wyjątków lub zwracanie obiektu specjalnego przypadku Zwracanie null List<Item> items = getItems(); if (items != null) { for (Item i : items) { totalCost += i.getCost(); } } List<Item> items = getItems(); for(Item i : items) { totalCost += i.getCost(); }
  • 115. public interface Animal { public void makeSound(); } public class Dog implements Animal { public void makeSound() { System.out.println("woof!"); } } public class NullAnimal implements Animal { public void makeSound() { } }
  • 116. • Przekazywanie null jest gorsze od jego zwracania Przekazywanie null public class MetricsCalculator { public double rectanglePerimeterCalculate( double x, double y) { return 2 * (y + x); } /* ... */ }
  • 117. • Defensive programming Przekazywanie null public class MetricsCalculator { public double rectanglePerimeterCalculate( double x, double y) { if (x == null || y == null) { throw InvalidArgumentException("Niewłaściwy argument."); } return 2 * (y + x); } } public class MetricsCalculator { public double rectanglePerimeterCalculate( double x, double y) { assert x != null : "x nie może być null"; assert y != null : "y nie może być null"; return 2 * (y + x); } }
  • 120. • SOLID • Zasady programowania obiektowego • Zasady projektowania obiektowego Poziom II
  • 121. SOLIDny programista • The Single Responsibility Principle – klasa powinna mieć tylko jeden powód do zmiany • The Open Closed Principle – klasę można łatwo rozszerzać, nie modyfikując jej • The Liskov Substitution Principle – klasy pochodne muszą być przeźroczystymi zamiennikami klasy nadrzędnej
  • 122. • The Interface Segregation Principle – dla różnych klientów twórz osobne interfejsy • The Dependency Inversion Principle – bądź zależny od abstrakcji a nie od konkretnych implementacji SOLIDny programista
  • 123. • Należy znać hierarchię dziedziczenia, aby zrozumieć metodę • Kod metody polimorficznej jest rozrzucony po kilku klasach • Nie zawsze jest oczywisty stan obiektu, z którego dziedziczymy • Dodatkowe elementy (pola, metody) są mocno związane (coupling) z klasą nadrzędną Kompozycja i dziedziczenie
  • 124. • Niezależność klas zawieranych • Można je używać w wielu kontekstach • Niskie związanie (coupling) • Łatwiej testować Kompozycja i dziedziczenie
  • 125. To znaczy jaki? Kod obiektowy
  • 126. • Odpowiedzialność – tylko jedna  obiekty maja własną osobowość, unikaj schizofrenicznych obiektów • Enkapsulacja – to co się zmienia enkaspuluj • Preferencja kompozycji ponad dziedziczenie
  • 127. • Dokładanie ponad modyfikacje – Gdy dodajemy nową funkcjonalność raczej dokładamy nowe byty niż modyfikujemy istniejące. • Lokalne zmiany – Zmiana ma konsekwencje lokalne, a nie globalne. Zasięg rażenia zmian jest jak najmniejszy. • Nieinwazyjność zmian – Dodanie nowych rzeczy (odpowiedzialności, funkcjonalności, zachowań) do istniejących bytów jest przezroczyste ich dla klientów.
  • 128. public class Sql { public Sql(String table, Column[] columns) public String create() public String insert(Object[] fields) public String selectAll() public String fieldByKey( String keyColumn, String keyValue) private String ColumnList(Column[] columns) private String valuesList( Object[] fields, final Column[] columns) }
  • 129. abstract public class Sql { public Sql(String table, Column[] columns) abstract public String generate(); } public class CreateSql extends Sql { public CreateSql(String table, Column[] columns) @Override public String generate() } public class SelectSql extends Sql { public SelectSql(String table, Column[] columns) @Override public String generate() } public class InsertSql extends Sql { public InsertSql(String table, Column[] columns) @Override public String generate() private String valuesList(Object[] fields, final Column[] columns) } public class FindKeyBySql extends Sql { public FindKeyBySql(String table, Column[] columns, String keyColumn, String keyValue) @Override public String generate() } public class ColumnList { public ColumnList(Column[] columns) public String generate() }
  • 130. Odpowiedzialność. Enkapsulacja. Kompozycja • To co leży u podstaw możemy stosować na każdym poziomie • Projektując klasy • Projektując moduły, komponenty • Projektując systemy
  • 131. • Każdy wzorzec opisujemy w trzech kontekstach:  Odpowiedzialność  Enkapsulacja / hermetyzacja  Kompozycja Wzorce projektowe
  • 132. • Rozdziela i przesłania implementację zachowań, czynności. • Hermetyzujemy zmienny sposób tworzenia obiektów • Nowe funkcjonalności uzyskujemy poprzez dodawanie komend, poprzez kompozycję. Wzorce projektowe: komenda
  • 134. • Każdy element systemu:  Ma swoją odpowiedzialność  Hermetyzuje pewne zachowania  Składa się z kilku współpracujących elementów Moduły
  • 135. • Boundary: zewnętrzny interfejs, kontrakt, fasada • Control: logika biznesowa, implementacja • Entity: persystencja Boundary. Control. Entity
  • 137. • Każdy framework opisujemy w trzech zdaniach:  Odpowiedzialność  Enkapsulacja  Preferowanie kompozycji Frameworki
  • 138. • Pozwala na obiektowy dostęp do bazy danych • Enkapsulujemy typ bazy, sposób dostępu do danych • Preferencja kompozycji (?) ORM
  • 139. • Nie ważne czy na poziomie klasy, modułu, frameworka – stosujemy te same bazowe pojęcia • Dedukujemy, indukujemy – posługujemy się doświadczeniem • Rozumiemy że nie ma uniwersalnych rozwiązań – ważny jest kontekst.
  • 140. • Spring czy EJB Nie ma idealnych rozwiązań
  • 141. • Spring czy EJB • JSF czy JSP Nie ma idealnych rozwiązań
  • 142. • Spring czy EJB • JSF czy JSP czy Velocity Nie ma idealnych rozwiązań
  • 143. • Spring czy EJB • JSF czy JSP czy Velocity • JPA czy iBatis Nie ma idealnych rozwiązań
  • 144. • Spring czy EJB • JSF czy JSP czy Velocity • JPA czy iBatis czy JDBC Nie ma idealnych rozwiązań
  • 145. • Spring czy EJB • JSF czy JSP czy Velocity • JPA czy iBatis czy JDBC • MVC czy MVP Nie ma idealnych rozwiązań
  • 146. • Spring czy EJB • JSF czy JSP czy Velocity • JPA czy iBatis czy JDBC • MVC czy MVP • Java czy .NET Nie ma idealnych rozwiązań
  • 147. • Spring czy EJB • JSF czy JSP czy Velocity • JPA czy iBatis czy JDBC • MVC czy MVP • Java czy .NET czy Python Nie ma idealnych rozwiązań
  • 148. • Spring czy EJB • JSF czy JSP czy Velocity • JPA czy iBatis czy JDBC • MVC czy MVP • Java czy .NET czy Python czy PHP Nie ma idealnych rozwiązań
  • 149. Po co to wszystko?
  • 153. Bo nasz mózg pracuje zupełnie inaczej
  • 154.
  • 156. Affordance a quality of an object, which allows an individual to perform an action. For example, a knob affords twisting, and perhaps pushing, while a cord affords pulling
  • 157. public class Sql { public Sql(String table, Column[] columns) public String create() public String insert(Object[] fields) public String selectAll() public String fieldByKey( String keyColumn, String keyValue) private String ColumnList(Column[] columns) private String valuesList( Object[] fields, final Column[] columns) }
  • 158. abstract public class Sql { public Sql(String table, Column[] columns) abstract public String generate(); } public class CreateSql extends Sql { public CreateSql(String table, Column[] columns) @Override public String generate() } public class SelectSql extends Sql { public SelectSql(String table, Column[] columns) @Override public String generate() } public class InsertSql extends Sql { public InsertSql(String table, Column[] columns) @Override public String generate() private String valuesList(Object[] fields, final Column[] columns) } public class FindKeyBySql extends Sql { public FindKeyBySql(String table, Column[] columns, String keyColumn, String keyValue) @Override public String generate() } public class ColumnList { public ColumnList(Column[] columns) public String generate() }
  • 160.
  • 164.
  • 165.
  • 166. Po co to wszystko?
  • 168. Nie po to aby było ładnie
  • 169. Nie aby było elegancko
  • 170. By żyło się lepiej
  • 171. • Pytamy doświadczonego kolegę Co robimy gdy robi się gorąco
  • 172. • Pytamy doświadczonego kolegę • Sami szukamy drogi Co robimy gdy robi się gorąco
  • 173. • Pytamy doświadczonego kolegę • Sami szukamy drogi • Próbujemy na siłę Co robimy gdy robi się gorąco
  • 174. • Pytamy doświadczonego kolegę • Sami szukamy drogi • Próbujemy na siłę • Porzucamy i wracamy do nawyków Co robimy gdy robi się gorąco
  • 175. Single Responsibility Open Closes Principle Liskov Substitution Interface Segregation Dependency Injection Singletons Tight Coupling Untestable Code Premature Optimization Indescriptive Naming Duplication
  • 176. Single Responsibility Open Closes Principle Liskov Substitution Interface Segregation Dependency Injection Singletons Tight Coupling Untestable Code Premature Optimization Indescriptive Naming Duplication
  • 177. • Nie ma kodu perfekcyjnego • Ale jest wystarczająco dobry  modyfikowalny  refaktoryzowalny  „disposible” over „maintainable” • Kod który mogę w każdej chwili wyrzucić i wymienić Tworzymy dobry kod
  • 178.
  • 201. Jak żyć? 2002 1996 / 2000 2002 1994