Dobre zarządzanie poziomami abstrakcji kodu sprawia, że kod jest łatwiejszy do zrozumienia i w wielu przypadkach do utrzymania. Lecz nie jest to łatwe zadanie 🙂
Jak sobie pomóc?
Opowiadanie o kodzie
Jednym ze sposób jest opowiadanie o swoim kodzie. Rzeczy na najwyższym poziomie abstrakcji powinniśmy być w stanie wytłumaczyć osobom kompletnie nietechnicznym – znającym tylko wymagania biznesowe. Rzeczy z niższych warstw powinniśmy być w stanie wytłumaczyć coraz to bardziej technicznym osobom. Przykładowo będąc back-end deweloperem, można spróbować opowiedzieć o kodzie z drugiego poziomu abstrakcji front-end deweloperowi. A o trzecim przykładowo koledze, drugiemu back-end deweloperowi.
Mieszanie poziomów abstrakcji
Dobrze znaną zasadą jest nie mieszanie poziomów abstrakcji ze sobą. Przykładowo mając trzy poziomy abstrakcji A (najwyższy), B (średni) oraz C (najniższy). Nie powinniśmy mieszać ich w dowolny sposób. Poziom A powinien wykorzystywać poziom B, a poziom B powinien wykorzystywać poziom C.
Przykład
Załóżmy, że pracujemy nad obsługą robota sprzątającego – taki robot ma przycisk WŁĄCZ pozwalający na uruchomienie robota a co za tym idzie sprzątanie mieszkania. Moglibyśmy przykładowo wyznaczyć trzy poziomy abstrakcji:
Najwyższy poziom abstrakcji
Na tym poziomie sprawa jest najprostsza. Mówimy, że po kliknięciu przycisku switchOn rozpocznie się odkurzanie (startVacuuming).
class Robot{
public void switchOn(){
startVacuuming();
}
}Środkowy poziom abstrakcji
Następny poziom abstrakcji to definicja tego co oznacza odkurzanie:
– rozpoczęcie ssania (switchOnSunction)
– jazda (drive)
class Robot{
private void startVacuuming(){
switchOnSunction();
drive();
}
}Najniższy poziom abstrakcji
Następny poziom abstrakcji opisuje detale związane z rozpoczęciem zasysania (otwarcie pojemnika na zabrudzenia – compartment.open(), uruchomienie zasysania – sunctionMechanism.start()) oraz z jazdą (pobranie mapy – Map map = mapStorage.getMap(), jazda zgodnie z mapą – driveAccordingToMap(map)).
class Robot{
private void switchOnSunction(){
compartment.open();
sunctionMechanism.start();
}
private void drive(){
Map map = mapStorage.getMap();
driveAccordingToMap(map);
}
}Oczywiście następnym poziomem abstrakcji pewnie mogłoby być zdefiniowanie tego co oznacza jazda zgodnie z mapą (driveAccordingToMap). Lecz na potrzeby przykładu, pozostanę przy trzech poziomach.
