Na forum 4programmers.net korzystamy z plików cookies. Część z nich jest niezbędna do funkcjonowania
naszego forum, natomiast wykorzystanie pozostałych zależy od Twojej dobrowolnej zgody, którą możesz
wyrazić poniżej. Klikając „Zaakceptuj Wszystkie” zgadzasz się na wykorzystywanie przez nas plików cookies
analitycznych oraz reklamowych, jeżeli nie chcesz udzielić nam swojej zgody kliknij „Tylko niezbędne”.
Możesz także wyrazić swoją zgodę odrębnie dla plików cookies analitycznych lub reklamowych. W tym celu
ustaw odpowiednio pola wyboru i kliknij „Zaakceptuj Zaznaczone”. Więcej informacji o technologii cookie
znajduje się w naszej polityce prywatności.
Wiadomo że OOP w Javie poszło w zupełnie innym kierunku niż początkowe założenia OOP.
Zamiast klas z metodami mamy rachityczne encje/DTO z akcesorami (brak logiki biznesowej) lub beany sesyjne bez stanu, zamiast dziedziczenia kompozycje i interfejsy.
Można też zrozumieć anonimowe klasy zamiast lambdy. W sumie naturalne rozwiązanie.
Pytanie 1:
Czy to wszystko może prowadzić (i prowadzi) w waszym kodzie do klas które mają metody po kilkadziesiąt linii (2-3 ekrany)?
Pytanie 2:
Czy są sytuacje w których długie metody są nieuniknione? Jakie to sytuacje?
Nie bardzo rozumiem Twoją tezę jakoby Java rozminęła się gdzieś z założeniami OOP.
Mam na myśli głównie to co już napisałem.
Dodatkowo:
Zasada 'bez pośredników'. Wyrzuć obiekty które nie robią nic poza przyjmowaniem żądania i przekazywaniem go innemu obiektowi.
Zasada 'nie spodziewaj się, że wykonam całą robotę'. Nie pytaj innych obiektów o ich wartość (wartości) i nie pracuj na nich sam. Każ obiektowi wykonać pracę dla Ciebie i dać Ci ważniejszy wynik.
"Programowanie obiektowe", Peter Coad/Jill Nicola, 1993
W wymienionej serii (Coad/Yourdon, OOA/OOD/OOP) nie ma nawet wspomnienia o interfejsach - podstawa dzisiejszego OOP w Javie.
Długie metody w dowolnym języku (nie musi być obiektowy), to przejaw lenistwa lub głupoty autora.
Metoda na 20 linii jest już za długa, a co dopiero mówić o stronach (ekranach).
Osobiście stopień skomplikowania metody wolę mierzyć liczbą instrukcji warunkowych (pętle, ify, switche).
W wymienionej serii (Coad/Yourdon, OOA/OOD/OOP) nie ma nawet wspomnienia o interfejsach - podstawa dzisiejszego OOP w Javie.
Ale przecież interfejsny nie mają za dużo wspólnego z obiektowym programowaniem, w takim sensie w jakim ty go rozumiesz(małpka dziedziczy po zwierzątku). Także, bulszit, interfejsy != obiektowe podejście.
To jest raczej robienie czegoś co naturalne jest w np: Ruby, mianowicie duck typing, i w tym kierunku bym szedł.
nie ma nawet wspomnienia o interfejsach - podstawa dzisiejszego OOP w Javie.
A jak to się ma do łamania zasad OOP? Naprawdę wierzysz, że książka, którą napisano w latach 90tych (informacja z wiki) opisuje "początkowe" założenia OOP z lat 70? I fakt, że w tej książce nikt nie wspomniał o interfejsach jest jakoś tajemniczo powiązany z tym, że ludzie piszą długie kawałki kodu?
Mam jakieś takie wrażenie, że nie do końca rozumiesz, czym jest programowanie obiektowe. Za to przeczytałeś kilka tekstów i je dodatkowo źle zrozumiałeś.
Czy to wszystko może prowadzić (i prowadzi) w waszym kodzie do klas które mają metody po kilkadziesiąt linii (2-3 ekrany)?
nie, poza paroma zamierzonymi dlugimi klasami/metodami nie przekraczam kilkaset linii na klase i wiecej niz (malego) ekranu na metode.
Czy są sytuacje w których długie metody są nieuniknione? Jakie to sytuacje?
nie ma takich sytuacji
przyznam troche draznia mnie pomysly typu 'max 25 linijek na metode' albo 'min 80% pokrycia testami', imo zwlaszcza doswiadczeni programisci powinni polegac na swoim zdrowym rozsadku a nie rozkochiwac sie w tego typu regulkach.
Można też zrozumieć anonimowe klasy zamiast lambdy. W sumie naturalne rozwiązanie.
W Javie 8 przecież są już lambdy.
Co do linii to w Clean Code, jeśli się nie mylę, wujcio opowiadał o jakimś hobbystycznym projekcie jego ziomka, który założył sobie, że jego metody nie będą dłuższe niż 3 czy tam 4 linijki. No i spoko było mówił :D
niezdecydowany
bez sensu(bo dlaczego, 3/4 a nie 5 ?), liczba linii zawsze powinna być po coś, np: Sandi Metz i jej 6 lini, ma taką podstawę że metoda może maksymalnie zbudować if'a + els'a - i to jest koniec odpowiedzialności.
Może rozgraniczmy na dobry początek to co wynika z języka od tego co wynika ze sposobu w jaki jest używany.
Sama składnia języka powoduje, że trzeba się trochę napisać by cokolwiek napisać. Java jest barokowa z tymi wszystkimi nawiasami, zawijasami i wąsami. W niewielkim stopniu poprawia to wprowadzenie lambd. W tej samej kategorii "siedzą" interfejsy. To, że nikt o nich nie wspominał w tej czy innej książce o OOP nie oznacza, że nie są one OOP. Teoria tworzenia kodu (w tym OOP) ewoluuje i dziś gdy silny nacisk kładzie się na IoC i przerzucenie wiązania obiektów na kontener interfejsy są bardzo fajne.
Kolejnym elementem są DTO, których historia sięga zamierzchłych czasów gdy trzeba było używać interfejsu Serializable na potrzeby Hibernate czy serializacji do XML. To powodowało, że do niektórych pól klasy należało dodać słówko transient, co powodowało, że trzeba było pisać własne metody do serializacji i deserializacji (by tworzyć poprawne obiekty) co w efekcie powodowało, że napisanie prostego DTO było szybsze i łatwiejsze. Zresztą i tu mamy "zonk" z serialVersionUID, który nie doczekał się żadnego rozsądnego mechanizmu pozwalającego na automatyzację zarządzania wersjami klasy.
@vpiotr, a twoje pytania dotyczą sposobu korzystania z języka.
ad 1. Jest to przejaw nie tyle co lenistwa, co podejścia "jakoś(ć) to będzie" i tworzenia kodu "good enough", czyli zaspokajania potrzeb biznesowych, a nie technicznych. Obecnie w projekcie odpuściłem sobie sonara, bo nie miałem siły walczyć z ludźmi o to by przed mergem przepuszczali kod przez sonara i starali się eliminować największe babole.
ad 2. Tu odpowiedzialność jest pomiędzy językiem, a człowiekiem. Czasami język nie pozwala na tworzenie wizualnie krótkich metod ponieważ np. wymagana jest odpowiednia obsługa wyjątków (np. kilka różnych klas, dla których wspólna nad klasa to Exception). Z drugiej strony niektóre operacje np. na danych są z natury długie np. ręczne transformowanie obiektów z jednej domeny do innej. Tu skrócenie kodu czasami jest bardzo trudne i wymaga wprowadzenia niepotrzebnych komplikacji np. całej gamy konwerterów.
Jednak, to są nieliczne przypadki. Zazwyczaj długość metody zależy od tego jak programista myśli o operacji, którą metoda reprezentuje, czy jest to operacja atomowa, czy też kompozycja kilku kroków.
Jako, że odpowiedź na pytanie @Wizzie nie mieści się w komentarzu....
Obecnie wprowadzanie DTO jest średnio przydatne. Encje powinny zawierać w sobie logikę, która pozwala przynajmniej na ich "samookreślenie się" w ramach domeny porównaj http://4programmers.net/Mikroblogi/View/6593#entry-6593 Jednak jest pewna grupa problemów, gdzie DTO (w postaci rachitycznego POJO) jest całkiem dobrym pomysłem.
Gdy jest częścią definicji API w REST. Obiekty REST-owe (czytaj JSONy) co do zasady są tylko kontenerami na informacje. Nie ma sensu pchać do nich logiki. Szczególnie, że zmiana logiki może pociągnąć za sobą zmiany w strukturze obiektu. Wprowadzenie DTO w takim wypadku jest uzasadnione gdyż będzie ono pełnić rolę "niezależnego" API. Czegoś w rodzaju interfejsu, ale na poziomie struktur danych.
Gdy dokonujemy transformacji w strukturach danych pomiędzy niezależnymi elementami systemu. Przypadek podobny do poprzedniego z tą różnicą, że nie wychodzimy poza JVM. Dzięki takiemu podejściu możemy sobie ustalić w miarę stabilne API da poszczególnych elementów oraz co ważne nie ma pokusy używania kodu z jednego elementu w innym. Tu uwaga warto obserwować wskaźniki duplikacji kodu. Dzięki temu można w odpowiednim momencie wydzielić nowe klasy.
Podsumowując, DTO nadal są przydatne, ale należy ich używać tam gdzie wzorzec ten został wymyślny - do dogadywania różnych części systemu, które niekoniecznie powinny albo w ręcz nie mogą współdzielić pewnych fragmentów logiki.
ad 1. Jest to przejaw nie tyle co lenistwa, co podejścia "jakoś(ć) to będzie" i tworzenia kodu "good enough", czyli zaspokajania potrzeb biznesowych, a nie technicznych. Obecnie w projekcie odpuściłem sobie sonara, bo nie miałem siły walczyć z ludźmi o to by przed mergem przepuszczali kod przez sonara i starali się eliminować największe babole.
Mam wrażenie że w przypadku o którym myślę (z życia) chodziło o agresywne powstrzymywanie się od dziedziczenia.
"Przy braku dziedziczenia (tylko implementacja interfejsu!) nie ma przecież sensu zostawiać jakiś reużywalny kawałek kodu (wydzielona nie-prywatna metoda) użytkownikom klasy, bo przecież i tak z niego nie skorzystają" - tak mogli myśleć ludzie generujący "grube" metody. Ale to tylko moje zgadywanie.