Nadużycia OOP

Obiektówka jest spoko, ale pewne rzeczy są nadużywane w kodach, które chcą uchodzić za obiektowe.

  • Dziedziczenie. Jeśli nie zmusza cię język albo framework, to dziedziczenie zwykle nie jest specjalnie dobrym pomysłem. Powoduje większe związanie implementacji między klasami. Lepiej kompozycji użyć albo przekazywać referencje. Albo wydzielić interfejs i niech dwie klasy implementują ten sam interfejs. To zwykle wystarczy, żeby pozbyć się dziedziczenia.
  • Gettery/settery - czasem się przydają, ale to nie znaczy, że każde pole w każdej klasie ma dostać getter i setter. Problem z getterami i setterami jest taki, że niszczymy hermetyzację pozwalając na to, żeby obiekty odczytywały/zapisywały bezpośrednio dane obiektu. Na tym etapie moglibyśmy równie dobrze zrobić wszystkie pola publiczne, bo na to samo wychodzi (i czasem wszystkie pola publiczne są okej! To, że piszemy OOP nie znaczy, że nie potrzebujemy czasem jakiegoś pojemnika na dane).
  • Zależności między obiektami - podzielenie apki na wiele różnych obiektów, które się ze sobą komunikują, ma tę wadę, że jeśli to zrobimy bezpośrednio (czy to refaktoryzując istniejącą apkę, czy to tworząc apkę od nowa, ale ze starym podejściem w głowie), to przeniesiemy nasz nieobiektowy spaghetti kod w sferę OOP, tworząc wiele różnych zaplątanych ze sobą obiektów. Tego nie zawsze widać na pierwszy rzut oka, bo przecież wszystko jest popakowane w klasy. A jednak jest gigantyczny coupling między poszczególnymi klasami. Dlatego projektując obiekty warto zwracać uwagę na to, żeby klasa robiła coś konkretnego i nie była specjalnie zależna od innych, a jeśli jest zależna od innych, to i tak warto zwracać uwagę od których innych klas jest zależna (czy te zależności nie wykraczają poza pewne granice architekturalne w apkce)
  • Magia na kółkach - czyli kod, po którym skaczą małpy. Jeśli w każdej metodzie i w każdym argumencie masz znaczek @, który coś tam wstrzykuje magicznie, to wiedz, że coś się dzieje (w ekosystemie JS/TS spotkałem się w tym w Nest.js). Albo jeśli w kodzie odpalają się skutki uboczne w najmniej spodziewanych miejscach, np. w niepozoronych getterach. I patrzysz na kod, tam się nic nie powinno dziać. A się zadziewa. Ogólnie lepiej tworzyć bardziej przewidywalny i bardziej prosty kod niż robić jakąś magię (chyba, że ta magia czemuś ma służyć. Zrobiłem kiedyś bibliotekę do niemutowalności Transmutable, która działała właśnie na zasadzie magii. Ale to akurat miało sens, bo to był najbardziej oczywisty sposób osiągnięcia tego)
  • Kod, do którego język zachęca, a nie zawsze jest to sensowne. Tutaj nie ma dobrej recepty. Pisząc w Rust łapię się na tym, że bardzo dużo generyków tworzę. Myślę, że to normalne i generyki się przydają w statycznie typowanych językach, jednak potem trzeba je wszędzie pisać, co nie jest wygodne. Więc mimo że uważam generyki za spoko, patrzę, gdzie jednak tego nie potrzebuję. Ogólnie więc apelowałbym o krytyczne spojrzenie. Podobnie ze wspomnianym już dziedziczeniem. Ludzie jak widzą, że coś jest w języku i używanie tego jest łatwe, to zaczynają używać wszędzie. Albo destructuring w JS. Przydatny, ale nadużywany. Ludzie potrafią bez wyraźnego powodu tworzyć wielopoziomowy destructuring, który nie jest ani krótszy ani bardziej czytelny. Ale ktoś miał satysfakcję, że użył destructuringu. Nie idźmy tą drogą.
  • Komentarze

    1. Lepszy destructuring niż 15 argumentów

      OdpowiedzUsuń
      Odpowiedzi
      1. Raczej alternatywą wtedy byłoby nie 15 argumentów, tylko zwyczajne nie robienie destructuringu np.
        function foo1(config) {
        console.log(config.a);
        console.log(config.b.c.d);
        }
        vs.
        function foo({ a, b: { c: { d } }}) {
        console.log(a);
        console.log(d);
        }

        dla mnie wersja pierwsza jest czytelniejsza. Plus bardziej odporna na zmiany w kodzie (co jeśli będziemy chcieli przekazać gdzieś cały obiekt, zamiast pojedynczych wartości?).

        Usuń

    Prześlij komentarz

    Popularne posty z tego bloga

    Dlaczego nie da się nadgonić frontendu

    Absurdy Rekrutacji 2023

    Przygody juniora (1)