Reużywalność* jest przereklamowana

Architektura, Różne takie, Wzorce projektowe

Budując systemy informatyczne za pomocą obiektowych języków oprogramowania wcześniej czy później natkniemy się na pojęcie „reużywalności” kodu . W najprostszych słowach – polega ono na nieumieszczaniu w kodzie źródłowym tworzonego rozwiązania wielu klas, metod lub komponentów implementujących identyczne funkcjonalności lub zadania (metoda DRY – Don’t Repeat Yourself)

Niestety, źle rozumiane podejście DRY (które w założeniu ma prowadzić do lepszego, czytelniejszego i łatwo-utrzymywanego kodu) może być przyczyną wielu projektowych problemów. Jeżeli naszym podstawowym założeniem w czasie pisania kodu będzie możliwość jego ponownego użycia w innym miejscu, może  doprowadzić to do większego skomplikowania oraz mniejszej czytelności tworzonego fragmentu rozwiązania. Dodatkowo, przenosząc opisany powyżej sposób postępowania z poziomu funkcji, metod oraz obiektów na poziom komponentów – sytuacja robi się już zupełnie mało zabawna.

Jakiś czas temu miałem okazję pracować nad aplikacją desktopową (stary, dobry WPF), która korzystała z danych pobieranych przez usługi sieciowe Dynamics 365. Jedną z podstawowych  funkcjonalności tejże aplikacji miało być wyświetlanie danych w postaci tabelarycznej (z możliwością wyszukiwania, filtracji oraz sortowania) w ramach kilku zdefiniowanych widoków. Czyli – chciałoby się powiedzieć –  „klasyczny grid”. Źródłem danych dla widoków było w omawianym przypadku kilka różnych encji systemu Dynamics 365. Dodatkowo, w zależności od kontekstu wywołania i źródłowej encji, zmieniał się sposób prezentacji oraz przeszukiwania listy rekordów. Niestety, osoba decyzyjna w projekcie, ogarnięta szałem (O_O) tworzenia „reużywalnych” komponentów  stwierdziła, że zespół odpowiedzialny za implementację powinien dostarczyć pojedynczą kontrolkę spełniającą następujące wymagania:

  • Wyświetlać pobrane dane w formie tabelarycznej z możliwością sortowania oraz filtrowania prezentowanych danych w dowolnej kolumnie.
  • Umożliwiać przeszukiwanie danych po wszystkich wyświetlanych kolumnach z możliwością użycia wieloznacznych symboli („wildcards”).
  • Kontrolka ma zapewniać ww. funkcjonalności niezależnie od źródła danych będącego tabelą w systemie Dynamics 365
  • Ma również zapewniać możliwość umieszczenia jej na dowolnym widoku w systemie

Niestety, na etapie podejmowania decyzji architektonicznych specyfikacja funkcjonalna aplikacji składała się z kilku ogólnych punktów. Możecie sobie wyobrazić do czego doprowadziło ww. podejście. W miarę klarowania się wymagań biznesowych okazało się, że wykorzystanie pojedynczego komponentu w wielu miejscach w systemie nie jest wcale najlepszym pomysłem. Na etapie testowania aplikacji tworzona kontrolka była rozbudowywana o nowe funkcjonalności, które na dodatek musiały działać inaczej w zależności od kontekstu uruchomieniowego. Doprowadziło to niestety do sytuacji w której stworzony kod stał się mocno skomplikowany, a ilość wprowadzonych wewnątrz niego poziomów abstrakcji była moim skromnym zdaniem niewspółmiernie duża w porównaniu z implementowaną funkcjonalnością. Dodatkowo, całkowity czas wykorzystany na stworzenie ww. komponentu był w moim odczuciu dużo większy niż w przypadku podejścia polegającego na implementowaniu kolejnych ekranów aplikacji z pominięciem procesu „uwspólniania” wykorzystywanych komponentów. Niestety, nie posiadam żadnych twardych danych liczbowych na potwierdzenie tejże tezy. Efekt implementacji rozwiązania, które w przekonaniu projektantów miało rozwiązać wszystkie problemy świata (a przynajmniej wszystkie problemy użytkowników systemu) był niestety w omawianym przypadku daleki od zamierzonego (skomplikowany kod, dużo parametrów konfiguracyjnych, obecność funkcjonalności generycznej kontrolki, które były finalnie wykorzystane tylko w jednym, konkretnym przypadku).

Nie chciałbym zostać źle zrozumiany… Reguła DRY jest jak najbardziej słuszna i powinna być stosowana tam, gdzie jest to możliwe. Jednak podobnie jak do większości wytycznych oraz wzorców projektowych należy do niej podchodzić zdroworozsądkowo. Zwłaszcza w przypadku, gdy jej implementacja wiązać się będzie ze zwiększonym kosztem dostarczenia całego rozwiązania, a zamiast uproszczenia kodu i uczynienia życia programisty prostszym – wprowadzi dodatkowy stopień komplikacji oraz zależności między komponentami. Wszyscy powinni pamiętać, że celem programisty jest rozwiązanie określonego problemu za pomocą działającego, czytelnego i rozszerzalnego kodu. Klienci w 90% przypadków nie płacą nam za tworzenie reużywalnych komponentów, tylko za dostarczenie określonej, działającej funkcjonalności. Niepoprawne zrozumienie omawianej idei może niestety spowodować sytuację, w której wytworzony kod będzie trudny w zrozumieniu, nierozszerzalny i przede wszystkim nie przynoszący (zarówno klientowi biznesowemu jak i osobom odpowiedzialnym za rozwój i utrzymanie systemu) jakichkolwiek korzyści.

* Jest to polski odpowiednik angielskiego „reusability”. Tak, wiem że słowo to nie istnieje w polskim słowniku, ale złośliwie będę go używał w dalszej części tekstu.

Total Views: 695 ,

4 comments

  • Pingback: dotnetomaniak.pl
  • Faktycznie nie masz twardych dowodów na poparcie swojej tezy ;). Z kontrolkami jest malutki problem – w wielu systemach chcesz mieć „klasyczny grid” w którym 80% funkcjonalności jest wspólnych dla wszystkich ekranów, a rózni się te 20%. Z Twojego opisu wynika że Szefo-Recyklinator postanowił zrobić kontrolkę która da zarówno te 80%, jak i WSZYSTKIE z tych 20%, więc sumarczynie da jakies z 200% albo ile tam. Z kolei z artykułu wynika że Ty optujesz za zrobieniem oddzielnej kontrolki dla każdego z tych ekranów, co z kolei dorpowadzi do tego że 80% kodu do jej osbsługi w każdym będzie redundantne – co też będzie piekłem w urzymaniu

    Nie pamiętam jak to wyglądało z dziedziczeniem kontrolek w WPF-ie, ale słusznym podejściem wydaje się zidentyfikować te 80%, z tego zrobić kontrolkę bazową, a funkcje charakterystyczne dla poszczególnych ekranów implementować w kontrolkach pochodnych od niej.

    Ewentualnie znaleść inne mechanizmy pozwalające „wtłoczyć” wymagane w danym ekranie funkcjonalności do kontrolki – jest ich trochę do wyboru.

    w DRY nie chodzi o to żeby zrobić jeden megakomponent z milionem przełączników – to jakaś potworność :P. W DRY chodzi o to żeby coś co jest wspólne – takie faktycznie było, żeby w przypadku modyfikacji modyfikowac jedno miejsce.

    takie milon-przełącznikowa konrolka łamie z kolei zasadę KISS 😉

    • Tytuł artykułu celowo jest prowokacyjny 😉
      Celem tekstu nie miało być udowodnienie, że reguła DRY i podejście polegające na tworzeniu reużywalnego kodu jest złe.
      Chciałem jedynie zaznaczyć, że reużywalność nie powinna być głównym celem „samym w sobie” i że rozumiana w zły sposób — nie przynosi korzyści. Co więcej, może często doprowadzić do wielu problemów w projekcie. Wydaję mi się, że na to kilka dowodów jest :).
      Z „techniczną” częścią Twojego komentarza oczywiście się zgadzam.
      Pozdrawiam.
      Piotr

  • Hej.
    Zgadzam się z Tobą. Bardzo często można znaleźć taki komponent do wszystkiego, ale czy to wina niepoprawnego wdrożenia zasady DRY? Możliwe, że również warto spojrzeć z innej perspektywy. Równie dobrze może to być niezastosowanie zasad pojedynczej odpowiedzialności, czy separacji interfejsów.

    W każdym razie popieram i też używam słowa reużywalność. Z pewnością za jakiś czas zostanie zaadaptowane do Słownika Języka Polskiego.

Dodaj komentarz