Java/06advanced13 min

Czysty kod i SOLID

SOLID to pięć zasad projektowania obiektowego, które prowadzą do kodu łatwego w zmianie i testowaniu. W połączeniu z podstawami czystego kodu są fundamentem utrzymywalnych serwisów Java w ProfessNet.

S — Single Responsibility

Klasa ma jeden powód do zmiany. Jeśli robi za dużo (logika + zapis + e-mail), rozbij ją.

// źle — serwis robi wszystko
class ReportService {
  void generate() { /* dane + format + zapis + wysyłka */ }
}

// dobrze — odpowiedzialności rozdzielone
class ReportBuilder { Report build(ScanResult r) { ... } }
class ReportStorage { void save(Report r) { ... } }
class ReportNotifier { void notify(Report r) { ... } }

O — Open/Closed

Klasy otwarte na rozszerzenie, zamknięte na modyfikację. Nowe warianty dodajemy przez nowe implementacje, nie przez if/else rosnący w nieskończoność.

interface Exporter { String export(Report r); }

class JsonExporter implements Exporter { /* ... */ }
class CsvExporter implements Exporter { /* ... */ }
// nowy format = nowa klasa, bez ruszania istniejących

L — Liskov Substitution

Podtyp musi działać wszędzie tam, gdzie typ bazowy — bez niespodzianek. Nie nadpisujemy metody tak, by łamała kontrakt (np. rzucała tam, gdzie bazowa nie).

Standard ProfessNet: jeśli podklasa musi rzucić UnsupportedOperationException z metody bazowej, to znak, że hierarchia jest zła — przemyśl interfejsy.

I — Interface Segregation

Małe, wyspecjalizowane interfejsy zamiast jednego „grubego". Klient nie powinien zależeć od metod, których nie używa.

// źle — interfejs zmusza do implementacji wszystkiego
interface ProbeOps { void scan(); void export(); void archive(); }

// dobrze — rozdzielone role
interface Scannable { void scan(); }
interface Exportable { String export(); }

D — Dependency Inversion

Zależymy od abstrakcji, nie od konkretów. Klasy wysokiego poziomu nie tworzą zależności same — dostają je przez konstruktor.

// dobrze — zależność od interfejsu, wstrzyknięta
class InventoryService {
  private final ProbeRepository repository;   // interfejs, nie klasa konkretna

  InventoryService(ProbeRepository repository) {
    this.repository = repository;
  }
}

Praktyki czystego kodu

ZasadaCo znaczy
Wyrażające nazwyrunScan zamiast proc, bez magicznych liczb
Krótkie metodyjedna metoda = jedno zadanie
Bez duplikacji (DRY)wspólny kod wydzielony, nie skopiowany
Niezmiennośćrecord, pola final, brak setterów gdzie się da
Mało parametrówwięcej niż 3-4 → opakuj w obiekt
// magiczna liczba → nazwana stała
private static final int STALE_AFTER_MINUTES = 1440;

if (probe.minutesSinceLastSeen() > STALE_AFTER_MINUTES) {
  probe.markStale();
}

Wskazówka: SOLID to wskazówki, nie dogmat. Nie wprowadzaj abstrakcji „na zapas" dla pojedynczej implementacji — to YAGNI. Refaktoruj, gdy pojawia się druga implementacja albo realna potrzeba zmiany.


Pięć zasad SOLID plus dyscyplina czystego kodu dają serwisy, które zmienia się bez strachu i testuje bez gimnastyki. To inwestycja, która zwraca się przy każdym kolejnym wymaganiu.