'Y'

Zasada YAGNI

Czy zasady OCP i DIP (z koncepcji SOLID) naruszają zasadę YAGNI? Przyjrzyjmy się tej kwestii szczegółowo.

Nov 15, 2016 3628
Czy zasady OCP i DIP (z koncepcji SOLID) naruszają zasadę YAGNI? Przyjrzyjmy się tej kwestii szczegółowo.

Różne zasady projektowania mają na celu rozwiązanie czasem sprzecznych zadań w projektowaniu oprogramowania. Można powiedzieć, że różne zasady "przeciągają" projektowanie w różne kierunki i trzeba samemu wybrać właściwy wektor, który będzie najbardziej pożyteczny w konkretnym przypadku. Zasada SRP popycha w stronę prostego rozwiązania, zasada OCP zachęca do izolacji elementów systemu, natomiast DIP jest skierowana na budowę prawidłowych zależności między klasami.

Zastosowanie jednej zasady może naruszyć inną zasadę. Na przykład, jakiekolwiek dziedziczenie może być rozpatrzone jako naruszenie zasady SRP, jako że zespół klas odpowiada za jedną odpowiedzialność (rysowanie figur). Jednoczesne wdrożenie zasady DIP i OCP, które często wymaga dziedziczenia, może doprowadzić do dodatkowych "pęknięć", tj. interfejsów/klas bazowych w systemie, które tym samym doprowadzą do naruszenia zasady SRP i/lub ISP.

Taka relacja między zasadami nie jest ustalona. Na prostym przykładzie, ustalenie hierarchii figur jest naruszeniem zasady SRP, jako że "rysowanie" w pierwszej iteracji równie dobrze może być wyświetleniem tekstu na pulpicie i rozpowszechnianie tej informacji we wszystkich klasach byłoby nadmierne. W miarę wzrostu złożoności systemu hierarchia dziedziczenia staje się pożyteczna w odniesieniu do SRP, do czasu gdy reprezentacja każdej figury zaczyna być na tyle skomplikowana, że pojęcie "odpowiedzialności" także się zmienia. Jeśli początkowo "pojedyncza odpowiedzialność" reprezentowała wszystkie figury, teraz jedna odpowiedzialność została rozdzielona na różne grupy - "reprezentację koła", "reprezentację kwadratu" itd.

Zasada YAGNI.jpg


Zasada YAGNI (You Aren't Gonna Need It) jest bardziej fundamentalną zasadą ("zasadą wyższą" lub "metazasadą"), która pomoże Ci zrozumieć, kiedy powinieneś przestrzegać zasad/schematów/reguł, a kiedy nie musisz tego robić.

Zasada YAGNI jest oparta na następujących obserwacjach:

  1. Programiści, podobnie jak wszyscy pozostali ludzie, nie są zbyt dobrzy w przepowiadaniu przyszłości.
  2. Koszty poniesione teraz mogą, ale nie muszą być uzasadnione w przyszłości.
  3. Każde elastyczne rozwiązanie nigdy nie będzie dostatecznie elastyczne.

Wyżej wymienione obserwacje prowadzą do następujacych wniosków: dowolna próba stworzenia elastycznego rozwiązania na wczesnym stadium programowania jest skazana na stworzenie zbyt skomplikowanego rozwiązania. Dzieje się tak, ponieważ na wczesnych stadiach nie jesteśmy jeszcze świadomi, jakich zmian będzie wymagał system w przyszłości i nie do końca jasne jest, w którym miejscu uda się "zbudować bezpieczną sieć" dla przyszłych zmian.

Jako że od samego początku nie można przewidzieć, jaka elastyczność będzie nam potrzebna, tym samym możemy stworzyć elastyczność tam, gdzie w przyszłości może się nie przydać. Możliwe, że wbudujemy dodatkową warstwę danych, lecz później ze względu na "nieszczelne abstrakcje" albo zablokujemy system dla jednej z baz danych, albo nigdy nie będziemy potrzebować tej funkcji. Możemy zbudować "szkielet" dla przetwarzania argumentów w wierszu poleceń w oddzielnej aplikacji, lecz koszt wybudowania go w innej aplikacji będzie na tyle wysoki, że nikt się za to nie weźmie.

Dobre projektowanie polega na tym, że dostajesz proste rozwiązanie, w którym zmiany w wymaganiach prowadzą do linearnego wzrostu wysiłku.

Najprostszą drogą do osiągnięcia tego celu jest ewolucyjne projektowanie: zaczynamy od wyodrębnienia dużych części systemu bez dodawania niepotrzebnych warstw abstrakcji. Nie będą nam potrzebne klasy bazowe, dopóki mamy przynajmniej dwa lub trzy obiekty podrzędne. I nawet jeśli takie obiekty podrzędne "mogą pojawić się w przyszłości", powinieneś zacząć budować hierarchię klas dopiero, gdy ta przyszłość nastąpi.

Istnieje sprawdzian dla zasady YAGNI: zbędne nałożenie abstrakcji (lub komplikowanie czegokolwiek) jest usprawiedliwione jedynie wtedy, gdy jego koszty w przyszłości będą zdecydowanie wyższe, niż obecnie.

Inwestycje w dobrze przemyślaną bibliotekę API będą uzasadnione jedynie w przypadku, gdy koszt późniejszego wprowadzenia zmian jest bardzo wysoki. Koszt ekstrakcji interfejsu/klasy bazowej w aplikacji będzie taki sam teraz, jak i za rok. Lecz za rok tego typu ekstrakcja będzie bardziej wykonalna pod względem ekonomicznym i praktycznym. Nie wykonasz niepotrzebnej pracy przed czasem, i tym samym możesz skupić się na czymś istotniejszym w danym momencie. Poza tym, za rok będziesz posiadać więcej informacji i zrozumienia jak powinna wyglądać klasa bazowa czy interfejs, ponieważ będą one oparte na prawdziwych, a nie wyimaginowanych wymaganiach.

Rozwiązywanie problemów w miarę ich pojawiania się umożliwi skupienie się na zadaniach, które są obecnie istotne i pomoże uniknąć pracy, która może okazać się całkiem niepotrzebna w przyszłości.

Sergey Teplyakov
Expert in .Net, C++ and Application Architecture

Udostępnij


Masz jeszcze jakieś pytania?
Skontaktuj się z nami
Thank you.
Your request has been received.