TL;DR
Refactoring to proces poprawy struktury kodu bez zmiany jego funkcjonalności. W tym artykule poznasz podstawowe techniki refactoringu Java, nauczysz się rozpoznawać „zapachy kodu” i zobaczysz praktyczne przykłady transformacji brudnego kodu w czysty, czytelny kod. Idealne dla developerów z 6-18 miesięcy doświadczenia.
Dlaczego refactoring jest kluczowy dla każdego programisty
Wyobraź sobie, że piszesz kod który ma działać przez najbliższe 5 lat. Za pół roku będziesz musiał dodać nową funkcjonalność, za rok – naprawić błąd, a za dwa lata kompletnie przepisać jeden z modułów. Czy będziesz pamiętać co robiłeś w tym kodzie? Czy nowy programista w zespole zrozumie Twoją logikę?
Refactoring to proces systematycznej poprawy struktury kodu bez zmiany jego zewnętrznego zachowania. To jak sprzątanie w domu – nie zmieniasz funkcji pokoju, ale robisz go bardziej funkcjonalnym i przyjaznym dla mieszkańców.
Co się nauczysz z tego artykułu
- Rozpoznawać „zapachy kodu” (code smells) w projektach Java
- Stosować podstawowe techniki refactoringu: Extract Method, Rename Variable, Extract Constant
- Bezpiecznie refactorować kod używając IDE IntelliJ IDEA lub Eclipse
- Rozumieć kiedy refactoring jest konieczny, a kiedy może zaszkodzić
- Pisać testy jednostkowe jako sieć bezpieczeństwa przed refactoringiem
Wymagania wstępne
Poziom: Podstawy – 6-18 miesięcy programowania w Java
Potrzebujesz: Znajomość podstaw Java (klasy, metody, zmienne), podstawy pracy z IDE (IntelliJ IDEA lub Eclipse), podstawowa znajomość JUnit
Narzędzia: Java 8, IntelliJ IDEA 2016 lub Eclipse Mars, JUnit 4
Czym są „zapachy kodu” i jak je rozpoznać
Code smells to objawy problemów w kodzie – sygnały ostrzegawcze, że coś wymaga poprawy. Nie są to błędy – kod działa, ale jest trudny do zrozumienia, utrzymania lub rozwijania.
Najczęstsze zapachy kodu w Java
1. Długie metody (Long Method)
// PRZED: Długa, nieczytelna metoda public void processOrder(Order order) { // Walidacja - 15 linijek kodu if (order == null) throw new IllegalArgumentException("Order cannot be null"); if (order.getItems().isEmpty()) throw new IllegalArgumentException("Order must have items"); // ... więcej walidacji // Kalkulacja ceny - 20 linijek kodu double totalPrice = 0; for (OrderItem item : order.getItems()) { double itemPrice = item.getPrice(); if (item.getQuantity() > 10) { itemPrice *= 0.9; // 10% rabat } totalPrice += itemPrice * item.getQuantity(); } // Zapis do bazy - 10 linijek kodu Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/shop"); PreparedStatement ps = conn.prepareStatement("INSERT INTO orders..."); // ... więcej kodu SQL }
2. Magiczne liczby (Magic Numbers)
// PRZED: Magiczne liczby if (user.getAge() > 65) { applyDiscount(0.15); } // PO: Wyjaśnione stałe private static final int SENIOR_AGE_THRESHOLD = 65; private static final double SENIOR_DISCOUNT_RATE = 0.15; if (user.getAge() > SENIOR_AGE_THRESHOLD) { applyDiscount(SENIOR_DISCOUNT_RATE); }
Podstawowe techniki refactoringu w praktyce
Extract Method – wyciąganie metod
Najczęściej używana technika. Gdy widzisz fragment kodu który robi coś konkretnego – wyciągnij go do osobnej metody z opisową nazwą.
// PRZED: Wszystko w jednej metodzie public void processOrder(Order order) { // Walidacja if (order == null) throw new IllegalArgumentException("Order cannot be null"); if (order.getItems().isEmpty()) throw new IllegalArgumentException("Order must have items"); // Kalkulacja double total = 0; for (OrderItem item : order.getItems()) { total += item.getPrice() * item.getQuantity(); } // Zapis database.save(order); emailService.sendConfirmation(order.getCustomerEmail()); } // PO: Podzielone na logiczne części public void processOrder(Order order) { validateOrder(order); double total = calculateOrderTotal(order); saveOrderAndNotify(order); } private void validateOrder(Order order) { if (order == null) { throw new IllegalArgumentException("Order cannot be null"); } if (order.getItems().isEmpty()) { throw new IllegalArgumentException("Order must have items"); } } private double calculateOrderTotal(Order order) { return order.getItems().stream() .mapToDouble(item -> item.getPrice() * item.getQuantity()) .sum(); } private void saveOrderAndNotify(Order order) { database.save(order); emailService.sendConfirmation(order.getCustomerEmail()); }
Rename Variable – lepsze nazwy zmiennych
// PRZED: Niejasne nazwy public double calc(List- items) { double t = 0; for (Item i : items) { double p = i.getPrice(); int q = i.getQuantity(); t += p * q; } return t; } // PO: Czytelne nazwy public double calculateTotalPrice(List
- items) { double totalPrice = 0; for (Item item : items) { double itemPrice = item.getPrice(); int quantity = item.getQuantity(); totalPrice += itemPrice * quantity; } return totalPrice; }
Bezpieczny refactoring z IDE
Nowoczesne IDE jak IntelliJ IDEA czy Eclipse mają wbudowane narzędzia refactoringu, które minimalizują ryzyko wprowadzenia błędów.
• Ctrl+Alt+M – Extract Method
• Shift+F6 – Rename
• Ctrl+Alt+V – Extract Variable
• Ctrl+Alt+C – Extract Constant
Krok po kroku: Extract Method w IntelliJ IDEA
1. Zaznacz fragment kodu który chcesz wyciągnąć
2. Naciśnij Ctrl+Alt+M
3. Wpisz nazwę nowej metody
4. IDE automatycznie wykryje parametry i typ zwracany
5. Zatwierdź – IDE zastąpi wszystkie podobne fragmenty
Kiedy refactorować, a kiedy nie
Refactoruj gdy:
- Dodajesz nową funkcjonalność – „Rule of Three”: gdy robisz coś po raz trzeci, refactoruj
- Naprawiasz błąd – często błędy są w brudnym kodzie
- Kod review – świeże spojrzenie ujawnia zapachy kodu
- Nie rozumiesz kodu – nawet własnego sprzed miesiąca
NIE refactoruj gdy:
- Zbliża się deadline – refactoring to inwestycja długoterminowa
- Kod działa i nie będzie zmieniany – „if it ain’t broken, don’t fix it”
- Brak testów – refactoring bez testów to hazard
Testy jako sieć bezpieczeństwa
Przed każdym refactoringiem napisz testy jednostkowe. To Twoja polisa ubezpieczeniowa – jeśli coś zepsujesz, od razu się dowiesz.
@Test public void shouldCalculateOrderTotalCorrectly() { // Given Order order = new Order(); order.addItem(new OrderItem("Book", 29.99, 2)); order.addItem(new OrderItem("Pen", 1.50, 3)); // When double total = orderService.calculateOrderTotal(order); // Then assertEquals(64.48, total, 0.01); }
Refactoring powinien być częścią codziennej pracy, nie osobnym zadaniem. Zasada „Boy Scout Rule”: zostaw kod w lepszym stanie niż go zastałeś. Nawet 5-10 minut refactoringu dziennie przynosi ogromne korzyści długoterminowe.
Tak, ale bądź ostrożny. Najpierw zrozum biznesową logikę kodu, napisz testy, a potem refactoruj małymi krokami. Skonsultuj się z autorem kodu lub tech leadem jeśli masz wątpliwości.
Przedstaw argumenty biznesowe: refactoring skraca czas rozwoju nowych funkcji, redukuje liczbę błędów i ułatwia wdrażanie nowych programistów. Zaproponuj „mikro-refactoring” – małe poprawki przy okazji innych zadań.
Zacznij od Extract Method (Ctrl+Alt+M), Rename (Shift+F6) i Extract Constant (Ctrl+Alt+C). Te trzy pokrywają 80% potrzeb refactoringu. Później poznaj Move Method i Change Method Signature.
Zacznij od własnego kodu, pokaż konkretne przykłady poprawy. Wprowadź „Definition of Done” która zawiera minimalny poziom czystości kodu. Organizuj code review skupione na jakości, nie tylko funkcjonalności.
To skumulowane problemy w kodzie które utrudniają rozwój. Jak dług finansowy – im dłużej odkładasz spłatę, tym wyższe odsetki. Regularne małe refactoring zapobiega „bankructwu technicznemu” projektu.
Tak, dlatego kluczowe są testy automatyczne i małe kroki. Refactoruj po jednej zmianie na raz, uruchamiaj testy po każdej zmianie. Używaj narzędzi IDE zamiast ręcznych zmian – to minimalizuje ryzyko.
Przydatne zasoby
- Refactoring.com – Martin Fowler – biblia refactoringu
- IntelliJ IDEA Refactoring Guide
- Eclipse Java Refactoring
- JUnit 4 Documentation
- Clean Code – Robert C. Martin
🚀 Zadanie dla Ciebie
Refactoring Challenge: Znajdź w swoim projekcie metodę dłuższą niż 20 linijek. Zastosuj Extract Method żeby podzielić ją na 3-4 mniejsze metody z opisowymi nazwami. Przed refactoringiem napisz test jednostkowy, po refactoringu sprawdź czy test dalej przechodzi.
Bonus: Znajdź w kodzie 3 magiczne liczby i zamień je na named constants. Udostępnij rezultat w komentarzu – czy kod stał się bardziej czytelny?
Czy masz swoje ulubione techniki refactoringu? Może zmagałeś się z szczególnie trudnym „zapachem kodu”? Podziel się swoimi doświadczeniami w komentarzach!