Prezentacja ma swoje korzenie w refleksji na temat użycia mocków w TDD. Przysłuchując się i zaczytując w dyskusjach na temat tego, czy mocki są dobre, czy złe, czy psują enkapsulację, czy też ją wzmacniają, czy prowadzą do kruchych testów, czy też są dobrym sposobem projektowania stabilnych interakcji, doszedłem do przekonania, że użycie mocków nie jest kwestią „stylu” TDD, a tym bardziej „stylu testowania”. Jest raczej głęboką konsekwencją specyficznej wizji projektowania obiektowego. Prezentacja będzie wycieczką po obiektowości, widzianej przez pryzmat dwóch pojęć: kompozycyjności i kompozycjonalności, z których spróbujemy wyprowadzić niektóre dobrze znane zasady projektowania i wzorce oraz zrozumieć dwa sposoby spojrzenia na kompozycję obiektów: jako sieci i jako języka wyższego poziomu. W końcu osadzimy w tym wszystkim mocki jako logiczny wybór podczas pisania kompozycjonalnych aplikacji z użyciem TDD.
4. I argue that there are not different
kinds of TDD. There are different
design conventions, and you pick the
testing techniques and tools most
appropriate for the conventions you’re
working in.
Nat Pryce
https://groups.google.com/forum/#!topic/clean-code-discussion/A6sJQjnwvnA
37. public class Sender
{
Recipient recipient;
public Sender(Recipient recipient)
{
this.recipient = recipient;
}
...
}
KONSTRUKTOR
38. public class Sender
{
List<Recipient> observers
= new List<Recipient>();
public ReportAllTo(Recipient observer)
{
this.observers.Add(observer);
}
...
}
REJESTRACJA
42. ROLA 4
ROLA 3
ROLA 1
ROLA 2
Oddziel tworzenie od użycia:
Otwórz logikę na różne implementacje
Oddziel tworzenie od użycia:
Otwórz logikę na różne implementacje
45. new SecureArea(
new OfficeBuilding(
new DayNightSwitchedAlarm(
new SilentAlarm("222-333-444"),
new LoudAlarm()
)
),
new StorageBuilding(
new HybridAlarm(
new SilentAlarm("222-333-444"),
new LoudAlarm()
)
),
new GuardsBuilding(
new HybridAlarm(
new SilentAlarm("919"), //call police
new LoudAlarm()
)
)
);
52. DOBRA ABSTRAKCJA?
public interface Employee
{
int GetAge();
string GetName();
string GetSurname();
decimal GetPay();
void SetPay(decimal newPay);
PayGrade GetPayGrade();
}
53. DOBRA ABSTRAKCJA?
public interface Employee
{
bool IsEligibleForRetirement();
bool IsAt(PayGrade payGrade);
EmployeeName GetName();
Money GetPay();
void SetPay(Money money);
}
54. DOBRA ABSTRAKCJA?
public interface Employee
{
void GiveRaise(RaiseFactor factor);
void EvaluateRetirement();
void SendTo(Destination d);
}
55. DOBRA ABSTRAKCJA?
public class NullEmployee : Employee
{
void GiveRaise(RaiseFactor factor) {}
void EvaluateRetirement() {}
void SendTo(Destination d) {}
}
56. DOBRA ABSTRAKCJA?
public class NullEmployee : Employee
{
void GiveRaise(RaiseFactor factor) {}
void EvaluateRetirement() {}
void SendTo(Destination d) {}
} Stabilne Interfejsy:
optymalizuj pod kątem łatwości
tworzenia nowych implementacji
Stabilne Interfejsy:
optymalizuj pod kątem łatwości
tworzenia nowych implementacji
107. new SecureArea(
new OfficeBuilding(
new DayNightSwitchedAlarm(
new SilentAlarm("222-333-444"),
new LoudAlarm()
)
),
new StorageBuilding(
new HybridAlarm(
new SilentAlarm("222-333-444"),
new LoudAlarm()
)
),
new GuardsBuilding(
new HybridAlarm(
new SilentAlarm("919"), //call police
new LoudAlarm()
)
)
);
108. new SecureArea(
new OfficeBuilding(
new DayNightSwitchedAlarm(
new SilentAlarm("222-333-444"),
new LoudAlarm()
)
),
new StorageBuilding(
Both(
new SilentAlarm("222-333-444"),
new LoudAlarm()
)
),
new GuardsBuilding(
Both(
new SilentAlarm("919"), //call police
new LoudAlarm()
)
)
);
109. new SecureArea(
new OfficeBuilding(
new DayNightSwitchedAlarm(
new SilentAlarm("222-333-444"),
new LoudAlarm()
)
),
new StorageBuilding(
Both(
new SilentAlarm("222-333-444"),
new LoudAlarm()
)
),
new GuardsBuilding(
Both(
new SilentAlarm("919"), //call police
new LoudAlarm()
)
)
);
110. new SecureArea(
new OfficeBuilding(
new DayNightSwitchedAlarm(
Call("222-333-444"),
new LoudAlarm()
)
),
new StorageBuilding(
Both(
Call("222-333-444"),
new LoudAlarm()
)
),
new GuardsBuilding(
Both(
Call("919"), //call police
new LoudAlarm()
)
)
);
111. new SecureArea(
new OfficeBuilding(
new DayNightSwitchedAlarm(
Call("222-333-444"),
new LoudAlarm()
)
),
new StorageBuilding(
Both(
Call("222-333-444"),
new LoudAlarm()
)
),
new GuardsBuilding(
Both(
Call("919"), //call police
new LoudAlarm()
)
)
);
112. new SecureArea(
new OfficeBuilding(
new DayNightSwitchedAlarm(
Call("222-333-444"),
PlaySirens()
)
),
new StorageBuilding(
Both(
Call("222-333-444"),
PlaySirens()
)
),
new GuardsBuilding(
Both(
Call("919"), //call police
PlaySirens()
)
)
);
113. new SecureArea(
new OfficeBuilding(
new DayNightSwitchedAlarm(
Call("222-333-444"),
PlaySirens()
)
),
new StorageBuilding(
Both(
Call("222-333-444"),
PlaySirens()
)
),
new GuardsBuilding(
Both(
Call("919"), //call police
PlaySirens()
)
)
);
118. new SecureArea(
OnOfficeEntered(
DependingOnTimeOfDay(
duringDay: Call(Guards),
atNight: PlaySirens()
)
),
OnStorageEntered(
Both(
Call(Guards),
PlaySirens()
)
),
OnGuardsBuildingEntered(
Both(
Call(Police),
PlaySirens()
)
)
);
Język Wyższego Poziomu:
Programuj na wyższym
poziomie abstrakcji
Język Wyższego Poziomu:
Programuj na wyższym
poziomie abstrakcji
119. Z CZEGO SKŁADAMY SAMOCHODY?
●
SILNIK
●
KOŁA
●
TARCZE
●
WYCIERACZKI
●
NIE MYŚLIMY W KATEGORIACH
ŚRUBEK!
120. Z CZEGO SKŁADAMY SAMOCHODY?
●
SILNIK
●
KOŁA
●
TARCZE
●
WYCIERACZKI
●
NIE MYŚLIMY W KATEGORIACH
ŚRUBEK!
Kompozycjonalność:
Dodawaj reguły dziedziny
używając komponentów dziedziny
Kompozycjonalność:
Dodawaj reguły dziedziny
używając komponentów dziedziny
123. public ConfigUpdates CreateUpdates()
{
return ConfigurationUpdates(
Of(log),
Of(localSettings),
OfResource(Devices()),
OfResource(Groups())
);
}
Języki, nie język:
Podziel kompozycję na serię
małych specyficznych języków
Języki, nie język:
Podziel kompozycję na serię
małych specyficznych języków