poniedziałek, 20 września 2010

Solidne programowanie

Chyba każdemu z nas zdarzyło się pracować z kodem, w którym zmiana małego fragmentu pociągała za sobą lawinę nieprzewidzianych zachowań programu. Historie o klasach, które mają kilka tysięcy linii kodu są niestety na porządku dziennym. Przeważnie programiści zwracają uwagę tylko na to, aby program działał poprawnie, a kwestie łatwego utrzymania i rozszerzenia funkcjonalności programu odchodzą na dalszy plan. W dalszym etapie projektu okazuje się, że zmiana małego fragmentu kodu jest prawie niemożliwa bez ponownego napisania znacznej części istniejących funkcji. Aby temu zapobiec, do projektu wprowadzane są „haki”, które mają ułatwić jego aktualne modyfikacje, a jednocześnie sprawiają, że program staje się coraz bardziej złożony, a jego kod trudny do zrozumienia – brzmi znajomo?

Programowanie zorientowane obiektowo miało na celu zapobieganie takim sytuacjom - stąd tak wielka popularność języków obiektowych. Jednakże to, że program jest napisany w języku obiektowym, jeszcze nie znaczy, że jest napisany w sposób obiektowy. Aby zbliżyć deweloperów do idei programowania obiektowego, Robert Cecil Martin (aka Uncle Bob) zdefiniował pięć zasad, które powinien spełniać program obiektowy. Zasady te to:

1. Single Responsibility Principle
2. Open/Closed Principle
3. Liskov Substitution Principle
4. Interface Segregation Principle
5. Dependency Inversion Principle

Jak to w życiu bywa, dla zasad potrzebna jest chwytliwa nazwa – uważni czytelnicy zapewne odkryli, iż pierwsze litery każdej z zasad składają się na słowo „SOLID”. Dzisiaj przyjrzymy się bliżej literce „S”.

Zasada Single Responsibility Principle (SRP) mówi o tym, że każda klasa powinna mieć tylko jedną odpowiedzialność. Dobra, ale co to właściwie jest odpowiedzialność? Uncle Bob definiuje odpowiedzialność jako powód do zmiany. A więc klasa, która jest odpowiedzialna tylko i wyłącznie za jedną rzecz, ma także tylko jeden powód, dla którego mogłaby się zmienić. Jak to wygląda w praktyce? Wyobraźmy sobie klasę, która generuje liczby doskonałe i wyświetla je na ekranie w odpowiednim formacie. Przyjrzyjmy się odpowiedzialnością tej klasy – zastanówmy się, jakie mogą być powody, dla których ta klasa mogłaby się zmienić. Powody są dwa:
1) Zmianie może ulec algorytm generacji liczb doskonałych
2)Zmienić może się format wyświetlania danych.
A więc klasa ta posiada dwie odpowiedzialności. Powinna więc być podzielona na dwie mniejsze klasy.
Ważne jest też nazewnictwo klasy. Otóż każda klasa powinna mieć nazwę, która wskazuje na jej odpowiedzialność. Po klasie o nazwie PerfectNumberGenerator możemy się spodziewać tego, że generuje liczby pierwsze. I to wszystko. Każda funkcja w tej klasie, która nie będzie związana z generacją liczb doskonałych (np. funkcja drukowanie liczb na ekran w odpowiednim formacie) nie powinna istnieć w tej klasie.

Warto zwrócić uwagę na to, iż jeśli klasa ma w swojej nazwie słowo typu Manager, Controller itp., tak naprawdę nie jesteśmy w stanie nic powiedzieć o odpowiedzialności tej klasy, więc po pierwsze klasa została źle nazwana, a po drugie, bardzo prawdopodobne jest to, że klasa ma więcej niż jedną odpowiedzialność.

Dlaczego zasada SRP jest tak bardzo przydatna? Otóż klasa powinna enkapsulować swoją odpowiedzialność przed innymi odpowiedzialnościami. Jeśli w jednej klasie istnieje więcej niż jedna odpowiedzialność, zmiana jednej z nich może mieć negatywny skutek na działanie pozostałych.

To by było na tyle z mojej strony, jeśli chodzi o literkę „S” ze słowa SOLID. Jeśli chcesz się dowiedzieć, o czym mówią pozostałe literki, zachęcam do śledzenia mojego bloga – post o literce „O” już w przyszłym tygodniu :)

Natomiast jeśli chcesz wiedzieć więcej na temat SRP, zachęcam do zapoznania się z artykułem Uncle Boba http://www.objectmentor.com/resources/articles/srp.pdf oraz rozdziałem 10. książki „Clean Code” Roberta C. Martina (książka jest na tyle dobra, że polecam zapoznanie się z całością).

Brak komentarzy:

Prześlij komentarz