Chyba każdy, kto choć raz spróbował swoich sił w programowaniu, zetknął się na pewno z zasadą DRY (ang. Don’t Repeat Yourself – Nie Powtarzaj Się). W myśl tej reguły należy unikać wielokrotnego powielania identycznych (lub bardzo zbliżonych funkcjonalnie) fragmentów kodu. Najczęściej uzyskujemy to poprzez wydzielanie często powtarzanych operacji formie funkcji czy wręcz całych bibliotek. Innym sposobem jest wprowadzanie różnych form abstrakcji, która pozwala “nadbudowywać” istniejące już funkcjonalności oraz ułatwiać ich późniejszą ewolucję.
Pracując ze swoim poprzednim projektem zauważyłem, iż w różnych komponentach, część funkcjonalności związana z obsługą komunikatów i ostrzeżeń wyświetlanych na ekranie ma bardzo zbliżoną formę. Jest to swego rodzaju prosta maszyna stanów, którą można zobrazować poniższym grafem:
Głównym jej zadaniem jest prowadzenie interakcji z użytkownikiem. Komunikat ostrzegawczy zostanie wyświetlony w momencie wystąpienia pewnego określonego warunku/ów, np. przekroczona prędkość, niezapięte pasy bezpieczeństwa, zbyt wysoka temperatura oleju, itp. Sytuację tą opisuje tranzycja od stanu WAITING do stanu ALERT. Potwierdzeniu komunikatu przez użytkownika powinno przenieść alarm w stan “drzemki” SNOOZE. Jeśli po upływie zadanego czasu warunek nadal będzie spełniony, całość powróci do stanu ALERT, ponownie wyświetlając komunikat. W przeciwnym wypadku nastąpi przejście do stanu oczekiwania WAIT.
W dowolnym momencie możemy dezaktywować naszą maszynę, przechodząc do stanu INACTIVE. Spowoduje to zaprzestanie cyklicznego monitorowania warunku.
Ze względu na swoją elastyczność, maszynę stanów można dostosować również do jednorazowych komunikatów – przy potwierdzeniu wystarczy przeprowadzić ją do stanu INACTIVE. Komunikaty mogą być także wyświetlane po określonym czasie od uruchomienia systemu. Wystarczy w trakcie inicjalizacji wymusić na maszynie stan “drzemki” z określonym timeout’em, po którym sprawdzony zostanie zadany warunek i nastąpi przejście do stanu ALERT lub WAIT.
Hmmm… całość nie wygląda na zbyt skomplikowaną. Czy warto wyodrębniać tak prosty kod jako osobną jednostkę lub klasę?
Zdecydowanie tak, nawet jeśli w niektórych przypadkach część funkcjonalności będzie redundantna (nadmiarowa). Pamiętajmy, że powtarzanie podobnych fragmentów kodu jest niemal zawsze źródłem trywialnych, choć trudnych do wychwycenia, pomyłek. Pisząc go raz, w sposób możliwie jak najbardziej ogólny i uniwersalny, minimalizujemy ryzyko wprowadzenia błędu. Oszczędzamy cenny czas i nasze nerwy!
Dzisiejszy krótki przykład pokazuje, że tworząc software zawsze warto spoglądać zarówno wstecz jak i daleko w przyszłość. Pisanie oprogramowania to z natury proces iteracyjny – nie jest możliwe stworzenie “od razu” kodu idealnego. Ważne aby każda kolejna wersja była lepsza – szybsza, czytelniejsza, lepiej zaprojektowana i przemyślana niż poprzednia. Należy również przewidywać dalszy rozwój i wszędzie gdzie dostrzegamy taki potencjał, starać się poświęcić więcej czasu na wprowadzenie elastycznych lub bardziej uniwersalnych rozwiązań. Dziś poświęcimy “aż” 10 minut – jutro zaoszczędzi nam to godziny pracy.
Tyle teorii – niedługo spróbujemy wcielić ją w życie 🙂 I znowu będzie dużo kolorków!