People and technology
RSS Feed

Articles

  • Primitives w javie

    Trochę mnie nie było, ale i tematy się pozbierały. Jak pokonam na dobre lenia to opiszę wszystko co mi na wątrobie leży i w kajecie zanotowałem. Zaczynamy od tematu lekkostrawnego: primitives.

    Od jakiegoś czasu, przeglądając zasoby sieci można wywnioskować, że jednym z większych niepowodzeń Javy, jest nie w pełni obiektowy model. Mianowicie Java posiada typy takie jak int, boolean, float, etc. Dalej można doczytać, że na szczęście nadchodzą języki, które uratują nas od tego przekleństwa (Scala, Groovy, Clojure i pewnie wiele innych).

    Ale czy primitives (tak, nie wiem jak to się na PL tłumaczy) są aż tak złe?

    Są trochę niebezpieczne, jako że Java je auto (un)boxuje (od 1.5), na podstawie czego Joshua Bloch stworzył kilka Java Puzzlers. Nie są też obiektami, przez co nie pasują do obiektowego modelu. Jednak mają przynajmniej dwie zalety z powodu których powstaje ten wpis i z których można korzystać do woli.

    1. Każdy primivitive ma wartość domyślną
    2. Nigdy nie mogą być nullem

    Dlaczego jest to według mnie istotne? A szczególnie istotne w kontekście warstwy danych?

    Weźmy najprostszą flagę Boolowską, powiedzmy, że oznacza ona czy email usera został zwalidowany (kliknął jakiś link w @ or sth). Korzystając z Hibernate Criteria API tworzycie zapytanie wykorzystując ją jako warunek. Zapytanie ma wyciągnąć wszystkie nieaktywne konta użytkowników. Wyglądało by to mniej więcej tak:  (Pseudokod pewnie idealnie się kompiluje, jeśli nie to proszę nie informujcie mnie o tym ;))

    [sourcecode language="java"]
    public class Email {//nasza encja
    ...//adnotacje i inne potrzebne pierdoły
    private Boolean active;

    public void setActive(Boolean active){
    this.active = active;
    }
    public Boolean isActive(){
    return active;
    }
    .... // pola inne i metody
    }
    public class JakiesDaoEmail {
    public List<Email> mojaMetodaSzukajacaMaili(Boolean active){
    Criteria inactiveEmails = createCriteria().addRestriction(Restriction.eq("active", active));
    ...
    }
    }
    [/sourcecode]

    No i dobra, co jest tu nie tak i dlaczego primitive miałby nam zrobić dobrze, a przynajmniej trochę pomóc?

    Zacznijmy od tego co jest źle a później dopiero o rozwiązaniach. W przykładzie, tak jak jest zdefiniowany ten wihajster, użytkownik może mieć maila aktywnego, nie aktywnego i ch..olera go wie jakiego. O tym co oznacza null pogadamy przy okazji kolejnego wpisu na temat null object pattern (ten się za bardzo rozrósł i musiałem dzielić). Zapytanie więc zwróci nam nie pełną listę nieaktywnych userów.

    Oczywiście nie w ciemię bity  programista może zacząć zabezpieczać się przed nullem, w końcu wystarczy zainicjalizować pole w momencie deklaracji i w seterze sprawdzać czy nie dostaliśmy nulla. Korzystając z hiberneta można w restrykcjach na sztywno umieścić or by szukał też nulli, dołożyć jeszcze adnotację notnull i column z deklaracją default value dla kolumny i  ... o rly?

    Jeśli macie team dość zdyscyplinowany to pewnie można. Jeśli nie, to łatwiej przekonać wszystkich by korzystali z primitives.  Jak wspomniałem każdy typ podstawowy (czy jak się je oficjalnie nazywa), posiada wartość domyślną. No tak, obiektowe wersję też ją mają, ale null nie jest kandydatem z moich snów i marzeń.

    Korzystając z prymitywów zostanie nam wprawdzie jeden problem: unboxing, ale to już problem wyższej warstwy. W każdym bądź razie tworząc statystyki nie odkryjecie, że w systemie macie tak naprawdę jeszcze raz tyle userów o nie aktywowanych mailach ;)

    I ... to jeszcze nie koniec :) Obiektowe odpowiedniki primitivów zazwyczaj widziałem 'czyszczone' poprzez setActive(null). Powodzenia w debuggowaniu tak wyczyszczonej flagi. Mały bool może nie da 100% gwarancji, że NPE nie poleci (przekazanie Booleanu = null jako parametru w połączeniu z unboxem zrobią nam ała), ale znacząco utrudni psucie nam innych fragmentów kodu czy zaśmiecanie ich przez kod szukający nulli.

    I tak, wiem, że opisuję haki na bad practices, ale gdzie bym nie pracował to się z tym spotykam. Praktyka wstawiania siedzi tak mocno w nas, że ostatnio i Koziołek prezentując testy posłużył się nullem miast wstawiać zera. Na dzonie przeglądając example kody tu i ówdzie nulla też się znajdzie. No i niby nic, bo większość wie o co chodzi, koncepcja przekazana. Tyle że młodzież co jeszcze NPE nie szukała, się szybko uczy. A później będzie, że jak Koziołki tak robią to i oni powinni.

    Od dziś z powyższej przyczyny postaram się walczyć w moich pseudokodach z nullami. Amen. Rozejść się można, koniec wpisu (bosz z 2 tyg go produkowałem :/ Jeśli coś nie ma sensu to sorry, ale z 2x go dzieliłem. Feedback mile widziany :))

    Read More »

  • only private static ... methods?

    Kolejny temat który mi po 33degree został, powoli kończę zaległości :P

    Wpis inspirowany przez Hamleta D'Arciego. Na jednej z prezentacji (bodaj o inspekcjach w Intellij), wspomniał on o jednej z własnych praktyk programowania. Mianowicie uważa on, że wszystkie metody prywatne powinny być statyczne.

    Dlaczego?

    Odpowiedź jest całkiem prosta: w przypadku statycznych metod, java nie pozwoli nam odwoływać się do nie statycznych pól klasy. Proste a genialne :)

    No, ale moment, co zyskujemy na tym, że nie możemy korzystać z pól?

    • Wprowadzamy bardziej funkcyjne podejście do metod.
    • Można założyć, że dla 2 jednakowych inputów będziemy mieli taki sam output.
    • Problemy wielowątkowości nam odpadają (taaa, no powiedzmy). Nie próbujemy modyfikować w 2 wątkach tego samego pola.
    • Jest czyściej i łatwiej przeprowadzić ekstrakcję klasy, w końcu nasza metoda nie zależy bezpośrednio od klasy w której się znajduje.
    • Łatwiej jest zapewnić SRP (Single responsibility), metoda więc będzie robić raczej jedną rzecz a dobrze

    Jednak nie ma róży bez kolców. Osobiście nie wprowadzę takiego stylu w projektach w których uczestniczę ponieważ

    • Tworzę czasem metody które, np opakowują geta z mapy, tak tylko żeby lepiej mi się czytało co to robi.
    • Dziwne by było dla mnie też, przekazywanie  np klasy DAO do statycznej metody, tylko po to by na przykład pobrać pierwszy obiekt z zwracanej listy (znów w sumie kryterium czytelności)
    • Mam uczulenie na słowo static. Ostatnio eksperymentuję nawet z stałymi które nie są statyczne (o czym może więcej kiedyś, jak uda mi się to do końca doprowadzić)
    • Bałbym się, że ktoś nie zrozumie moich zamiarów i następnego dnia znajdę w mojej klasie mnóstwo staticów :cold:

    Pomysł jednak ciekawy, zachowam go na przyszłość i jak podciągnę własny skill level/zmienię styl, to może zacznę używać. Póki co nie mogę powiedzieć, że moje wszystkie metody prywatne mogą być statyczne.

    Co do screencastów, o których wspominałem jakiś czas temu to sobie odpuszczam. Próbowałem, kilka podejść zrobiłem i stwierdzam, że nie mam obecnie dość czasu (i chęci :( ), a dostarczenie czegoś mocno na kolanie skleconego nie zadowala mnie.

    Za to piszę coś małego w t5. Jak uda mi się kilka pomysłów wsadzić w ten mini projekcik, to wrzucę kod na sieć i na nim poćwiczymy T5 wspólnie :) W sumie dawno T5 nie używałem więc i mi się ćwiczenie przyda :)

    Do następnego

    Read More »

  • Ile metod ZAWSZE nadpisujesz w swoich obiektach?

    Hej, dziś temat mający korzenie w korytarzach hotelu gdzie odbywało się 33degree.

    Podczas jednej z przerw rozpoczeliśmy dyskusję nad odwiecznym problemem w javie: ile metod i kiedy powinno się nadpisywać z klasy Object. By zacieśnić grono podejrzanych metod: rozmawialiśmy o hashCode, equals, toString. Całość w kontekście naszych aplikacji wykorzystujących Hibernate'a. Cała sprawa dotyczy też jedynie obiektów VO (Value Object), entities, DTO (Data Transfer Object) a nie services, controllers i innych DAO i managerów.

    Jako wstęp do wpisu zachęcam do przeczytania kilku zasad tworzenia dobrych metod equals i hashCode, zebranych przez Andrzeja Ludwikowskiego w wpisach na jego blogu: equals i hashcode. Jeśli ktoś nie czytał, a pisze kod w javie, to obowiązkowo zalecam też lekturę książki Joshua Blocha Effective Java. Joshua dokładnie wyjaśnia wady i zalety oraz jak nadpisywać wszystkie 3 wymienione metody.

    Główną linią podziału pomiędzy nami było czy w equals i hashCode korzystać z ID generowanego przez hiberneta czy nie oraz czy nadpisywać metodę toString. Moim zdaniem korzystanie z id hibernatowego ma zalety do których należy

    • Pewność podczas identyfikacji obiektu. ID jest niepowtarzalne. Jeśli dwa obiekty są róne po porównaniu przez ID to na pewno jest to ten sam obiekt. Uwaga: owy obiekt może być w innym stanie, ale to historia na inny wpis.
    • Kolejną zaletą jest zwalenie odpowiedzialności za utworzenie identyfikatora na kogoś innego (czyt. Hibernate-a).
    • Przeważnie nikt też nie wpadnie na genialny pomysł zmiany wartości, którą postanowiliście zastosować do porównywania równości i generowania hashu (magia dwóch liter ID ;))

    Są jednak też wady, a podstawową jest to, że ID potrzebne do obu metod będzie dostępne dopiero po zapisie obiektu do bazy danych. Można to obejść, ale przeważnie w mało ładny sposób, który może nas później ugryźć w najmniej odpowiednim momencie, pomińmy więc tą możliwość.

    Dla wielu osób nie musi wyglądać to na poważny problem, ale niestety nim jest. Zastanówmy się teraz czy istnieje możliwość, że korzystamy z obiektów przed dodaniem ich do bazy?

    Jeśli tak to trzeba się zabezpieczyć przed nullem w  id. Jak to zrobić?

    1. Możemy sprawdzać czy id == null i jeśli tak to zwracamy jakąś stałą, np String.EMPTY, zero, etc. Nie wydaje się to być złe, nigdy nie dostaniemy NPE. Jednak problem pojawia się gdy korzystamy z kolekcji, szczególnie haszujących. Z powodu tego, że 2 obiekty będą dla systemu identyczne, możliwe jest doprowadzenie do utraty danych. Problemem jest również korzystanie z obiektu po zapisaniu go do DB. Zmienia się ID (na wygenerowane przez hiberneta) więc próba skorzystania z metoda takich jak .contains(obj) zakończy się niepowodzeniem. Możemy na przykład wyświetlić tą samą informację na ekranie dwukrotnie.
    2. Możemy przed użyciem obiektu zapisywać go do bazy danych/pobierać przed skorzystaniem  z niego numer ID. Rozwiązanie pozbawione powyższych wad, jednak w wielu systemach zupełnie nie akceptowalne. Podstawowa wada to utrata kolejnego numeru ID oraz czasu potrzebnego na komunikację z bazą. Jeśli wyświetlamy numer ID użytkownikowi, może go zdziwić, że po zamówieniu nr  6, kolejne zamówienie ma numer 30. Inną sprawą jest, że ID bazodanowe nie powinno być prezentowane użytkownikowi, ale chyba każdy z nas miał gdzieś okazję widzieć system, który łamał tę zasadę.  Komunikacja z bazą to za to zupełnie inny problem. Jeśli mamy jakąś formę wizarda to wypadało by zadbać by obiekty stworzone przez użytkowników, a nigdy nie dokończone, zostały kiedyś usunięte z bazy. I kolejny problem wtedy mamy

    Wracając do sedna i tego co Pan Michał radzi: da się uniknąć wykorzystywania ID w hashcode i equals więc starajmy się tego unikać. Pisząc encje zidentyfikujmy niezmienne własności obiektu i wykorzystajmy je w equals i hascode. Dobrymi kandydatami są data powstania obiektu czy wymagane pola, których później się nie da zmienić np login. Wykorzystując kombinację takich danych da się dobrze identyfikować obiekty i nie trzeba przy każdym obiekcie zastanawiać się nad strategią zapisywania do bazy.

    Czasem można wykorzystać też dane zmienne w czasie. Jeden z dyskutantów podał przykład z aplikacji nad którą aktualnie pracował. System służy do przeprowadzania ankiet. Według autora, nie ma problemu w wcześniejszym zapisaniu danych w bazie, przed rozpoczęciem korzystania z nich. Nie zdążyliśmy dokończyć dyskusji na ten temat, ale oto moja propozycją dla tego typu zagadnień.

    Jeśli posiadacie ograniczony zbiór możliwych obiektów to może nie warto zapisywać każdego z nich, tylko agregować je. Łatwo to uzyskać poprzez porównywanie wszystkich pól w obiekcie.

    Weźmy za przykład ankietę z dwoma pytaniami i trzema możliwymi odpowiedziami na każde z nich. Dla takiej ankiety istnieje zbiór 9 możliwych do utworzenia obiektów. Jeśli wypełni ankietę 1000 użytkowników to my nie będziemy gromadzić 1000 rekordów a jedynie 9. Spora oszczędność.

    Co zrobić jeśli mamy ankiety z pytaniami otwartymi i zamkniętymi? Nikt nie powiedział, że ankieta (a w zasadzie odpowiedzi do ankiety) musi być obiektem monolitycznym. Obiekt odpowiedzi możemy podzielić na podklasy: odpowiedzi do części otwartej i zamkniętej. Część zamknięta jest agregowana w wyżej opisane sposób, otwarta tradycyjnie. Sama tabela odpowiedzi staje się jedynie łącznikiem pomiędzy użytkownikiem, odpowiedziami do każdej części oraz samym zestawem pytań.

    Na koniec  słowo o metodzie toString(). Większość dyskutantów stwierdziła, że jej nie nadpisuje. Jako powód wymienili przykład z Effective Java, gdize Joshua podaje jako zagrożenie, możliwość rozpoczęcia parsowania przez użytkowników, wartości zwracanych z toStringa. Dla mnie to przykład jedynie książkowy, być może z racji tego jak projektuję aplikację.

    Nie uważam, by ukrywanie stanu w ValueObjects (do których zaliczam encje), było wskazane, gdyż może prowadzić jedynie do takich absurdów jak parsowanie toString czy nadużywania refleksji. Ok, kwestia tego jak piszemy aplikacje, jednak jeśli nie nadpisujecie toString, z wyżej wymienionego powodu, to nie wystawiajcie innej metody, która działa jak toString a jedynie inaczej się nazywa (zaproponowane podczas tej dyskusji).

    Nie unikniecie problemów związanych z parsowaniem stringów a jeydnie skomplikujecie sobie życie. Jeśli już więc unikamy toString, to wystawmy, przez odpowiedni interface,  zestaw metod do komunikacji, np myNoToStringObject.log.(LoggerAdapter, logLevel, logTemplate). Nie unikniemy wprawdzie tego, że ktoś przekaże nam własną implementację loggerAdaptera i i tak sparsuje Stringa, ale może choć utrudnimy mu życie na tyle, że zrezygnuje ;) Temat jest jednak dość obszerny by stworzyć kolejny wpis.

    Tymczasem w komentarzach wpisujcie swoje przemyślenia i dajcie znać ile wy metod zawsze nadpisujecie w obiektach.

    Read More »

  • Photos from 33degree

    Hi all,

    I just finished uploading some of photographs I taken on 33degree conference to my flickr account.

    To see all of them follow this link. Click those link for photos from day 1,  day 2, day 3 only.

    I won't upload everything I have taken on conference, but I will send them to Grzegorz. He will get them in original size (and that means hell big :)) and maybe will decide to share more of them or same but not resized.

    As per reusing and license. I share them under CC -BY license. Note however that if you want to use them commercially (yeah, right :D), you probably should ask person on photo for permission.

    On the other hand, if you are on one of photos and don't want it to be published then notice me, I will either remove photo or censor it :)

    Oh and don't get used to English on my blog. I'll be still posting mainly in Polish.

    DISCLAIMER

    I know that some of the photos are moved, too dark or just crappy as hell. I hate to use flash, as I consider it distracting and rude, so I tried to use only light that was in the room. There wasn't much of it there. I did my best, but those were my first steps with new camera and I still need to improve my technique. Next year batch will be better :)

    Read More »

  • 33degree - day 3

    No dobra, czas kończyć bo ciągnie się to za długo.

    Ostatni dzień był dla mnie głównie serią unconference Stefan Tilkov opowiadał o RESTcie w Javie (REST in Java). No cóż, o ile ciekawe, o  tyle mogłem wybrać coś innego ;) Failures Come in Flavors przedstawione przez Michaela Nygarda, przypuszczam, że dużo bardziej by pasowało do mojej obecnej sytuacji ;)

    Nie zrozumcie mnie źle, Stefan jest ekspertem od RESTa, dowiedziałem się więcej o dostępnych bibliotekach w Javie by zaaplikować RESTową architekturę, ale mi to akurat teraz jest zbędne.

    Następnie udałem się na najgorszą z wszystkich prelekcji: Marcin Kokott i Martin Chmelar w How to solve unsolvable problems in projects. Jak dla mnie to przyszli panowie, by zareklamować swoje usługi i przekonać nas by ich zatrudnić. Jak dla mnie porażka, nic więcej na ich temat nie napiszę.

    Kolejna prezentacja, mimo iż o tematach wszystkim dobrze znanych, była jednym z najjaśniejszych punktów konferencji. Szczepan Faber i Bartosz Bańkowski opowiadali o głównych grzechach popełnianych przez programistów (Lost Chapters of Divine Code: 7 Deadly Sins). Zgadzam się z nimi w pełni i staram się przekonywać ludzi, z którymi pracuję, do idei zawartych w ich prezentacji. No może nie do wszystkich. Przejdźmy przez t o co powiedzieli:

    1. Obiekt powinien nie mieć metod prywatnych, bądź mieć ich jak najmniej
    2. Obiekty bezstanowe nie powinny mieć metod statycznych
    3. Dziedziczenie komplikuje kod
    4. Nie powinno się tworzyć finalnych klas / finalnych metod
    5. Nie powinno się nazywać tej samej rzeczy na kilka sposobów
    6. Nie powinno się budować frameworków na wyrost
    7. static na polach prowadzi do stanu globalnego, który jest zły.

    Ad 1. Ogółem to zgadzam się, że obiekty nie powinny być zbyt duże, ale przesada z ekstrakcją metod prywatnych i zamianą ich w metody publiczne, będzie prowadzić do biegunki klas, które są używane przez jeden obiekt jedynie.

    Sam określiłbym to tak: jeśli wykorzystasz metodę prywatną w 2 obiektach, to wyekstrahuj ją do zewnętrznego obiektu by zachować zgodność z zasadą DRY.

    Ad 2. Niemal w pełni zgoda. Słowo kluczowe static jest zakazane. Tworzyłem dla klienta niedawno standard kodowania w javie i był to jeden z pierwszych zapisanych przeze mnie  punktów: nie korzystać z statycznych utility classes. Nie jest to do kości złe, ale prowadzi do pokusy tworzenia aplikacji quasi proceduralnych, które niesamowicie ciężko jest testować i zmieniać.

    Moja zasada: jeśli masz klasę, która posiada tylko statyczne metody, to jest ona uzasadniona jeśli może być wyekstrahowana do zewnętrznej biblioteki. Jako przykład podaję zawsze bibliotekę Apache Commons i klasę StringUtils. BTW jedna z bardziej użytecznych bibliotek.

    Ad 3. Dziedziczenie uważam za złe. Widziałem proste obiekty, które był absolutnie niezrozumiałe z racji wielopoziomowej hierarchii klas. Dziedziczenie ma swoje miejsce, ale jeśli używa się go by ponownie wykorzystać kod, to bardzo łatwo złapać się w pułapkę, że coś nie działa i nie wiemy dlaczego, bądź koszt zmiany jest duży.

    Dziedziczenie ma swoje miejsce i nie należy z niego całkowicie rezygnować, jednak w wielu przypadkach rozsądniej jest obiekt komponować, co prowadzi do bardziej elastycznej architektury.

    Ad 4. Ogólnie zgoda. Odwołali się tu oni do Joshua Blocha, który stwierdził, że klasa powinna być abstrakcyjna albo finalna. Problem z takim podejściem pojawia się w trakcie pisania testów, bądź udostępnieniu kodu jako biblioteki dla klienta. Czasem musimy nadpisać jedną / kilka metod, bo mamy potrzebę inną niż autor przewidział.

    Ad 5. W pełni zgoda. Borykają się z tym przeważnie projekty, które ciągną się na przestrzeni długiego czasu (a przynajmniej tak wynika z mojej obserwacji). Klient potrafi zmienić nazwę dla bytów co może przeniknąć szybko z dokumentów wymagań do kodu, a wtedy zaczyna się jazda, szczególnie jeśli zmienia się zespół programistów :)

    Ad 6. Podsumowując: do powieszenia obrazka na ścianie potrzebny jest Ci gwóźdź i młotek. Nie buduj więc maszyny wbijającej gwoździe i wieszającej na nich obrazki, szczególnie gdy masz tylko jeden obrazek

    Ad 7. Znów trudno się nie zgodzić. Stan globalny ciężko się zmienia i testuje. Hmm, może kompilator Javy powinien podczas kompilacji na każdym słowie static  wyrzucać prompta: "Czy jesteś pewien, że to chcesz zrobić?". Może to by ich oduczyło?

    Od chłopaków trafiłem do Neala Forda i  Abstraction Distractions. Opowiadał on o ... trudno powiedzieć o czym, ale było ciekawie ;) Na poważnie, ciężko jest to wszystko zamknąć w kilku zdaniach by nie spłycić analizy jakiej dokonał Neal, dotyczącej tego jak myślimy, projektujemy, kodujemy, pracujemy, żyjemy. Wplatał w historie z życia wzięte zagadnienia związane z IT i szło mu to bardzo sprawnie.

    Następnie wziąłem wolne  2.5 godziny i na korytarzu uczestniczyłem w licznych interesujących rozmowach. Jak na każdej konferencji: jeden z najlepszych momentów: możliwość pogadania z innymi devami.

    Na sam koniec odwiedziłem jeszcze Teda Newarda i posłuchałem o ... tym by nie słuchać nikogo i myśleć samemu za siebie (Rethinking "Enterprise"). Bardzo odprężający wykład na koniec.

    Jeszcze tylko losowanie, w którym udało mi się dostać licencję na Intellij (jej, już nie muszę korzystać z  Idei u klienta i samemu klepać kodu w eclipsie :) ) i czekając na pociąg udałem się z Łukaszem Kuczerą na miasto.

    Podsumowując: było rewelacyjnie. Już pod koniec day 1 wiedziałem że za rok na pewno tam jadę ponownie. Jak dla mnie najlepsza javowa (i nie tylko) konferencja w tej części europy. Świetni prelegenci, dużo uczestników (nie tylko z PL), znakomita organizacja, przystępna cena ... a z resztą: w ankiecie na idealną konferencję tak opisałem tą moją wymarzoną, a Grzegorz ją zorganizował, za co bardzo mu dziękuję. Było rewelacyjnie i za rok postarajcie się, żeby was na niej nie zabrakło.

    Co dalej na blogu? Kilka tematów, które przyszły do mnie na #33degree (teraz już technicznie stricte będzie). Pracuję też na screencastami, jak się uda i mnie technologia nie pokona (i brak czasu), to możecie się spodziewać kilku ciekawych, mam nadzieję, filmów o refactoringu i Tapestry. Tylko jeszcze w życiu osobistym posprzątam.

    Do następnego

    Read More »

Michal Gruca
Michal Gruca

Manager by title, developer at heart

Twitter Email

TOC