People and technology
RSS Feed

Articles

  • Google wspiera open source

    Przedwczoraj na blogu googla pojawiła się informacja, że otwierają 2 wtyczki WindowBuilder i CodePro Profiler. Pierwsza służy do budowania GUI i jest naprawdę dobrym kawałkiem softu, druga to profiler (jak nazwa wskazuje :P) czyli służy do znajdowania wąskich gardła w aplikacji.

    Oba projekty przejdą pod skrzydła fundacji Eclipse'a i zostaną Eclipse projects w pierwszej połowie 2011 roku. Wtedy zostaną opatrzone licencją EPL (Eclipse public licence).

    Według mnie jest to ważne wydarzenie dla wszystkich użytkowników Eclipsa. Są to 2 dobre wtyczki, których wielu osobom przez kilka lat brakowało, a teraz są i to jako OS :).

    Google wycenia wartość przekazanego kodu i praw intelektualnych na 5 milinów $. Sporo. Ciekawy jest również podany przez nich powód, czyli wiele próśb od userów :) Choć google starają się nie być złymi to jednak jestem przekonany, że mają w tym jakiś głębszy cel.

    Ponadto w wtorek Apache ogłosiło, że rozpoczyna współpracę z Googlem. Powstaje strona pod adresem http://www.apache-extras.org/ gdzie hostowane są projekty związane z projektami apache, ale nie będące bezpośrednio pod skrzydłami Apacha (dla przykładu, Apache Shrio ma realma do Atlassian Crowda, który można znaleźć na nowej stronie).

    Jako, że nie jest to formalnie część ASF to nie jest narzucana licencja ani proces zarządzania, co było wytknięte Apaczom na ostatnim trójmiejskim JUGu. Widać zdają sobie oni sprawę, że nadmiar formalizmów mógł ich w końcu zabić, do czego w komunikacie się według mnie przyznają, stwierdzając, że ta inicjatywa ma służyć dalszemu podnoszeniu innowacyjności ich projektów.

    Co do zysków googla, to poza utrzymaniem domeny nic ich to nie kosztuje (w sumie jest to ten sam code.google.com co wcześniej, a same projekty można, podobno, bezproblemowo przenieść), a wokół apaczów muszą się kręcić z racji Harmony. Ciekawe jak się potoczy dalej ta przyjaźń.

    To garść nowości z szerokiego świata na dziś. Ciekaw jestem waszej opinii na temat nowych inicjatyw googlowych, jako że ja mieszkam u klienta w tym tygodniu i za dobrze nie miałem czasu na własne przemyślenia. Nawet ten wpis się pisał przez 3 dni :P

    Read More »

  • Nom, nom, nom. Yummie logs

    Dziś lightowo będzie. Ostatnio nie miałem czasu pisać to chcę nadrobić kilkoma krótszymi wpisami.

    Większość z nas wie, że logowanie jest dobre. Wprawdzie są osoby, które uważają, że każda linia kodu do tworzenia logów to linia stracona, ale ja się z tym nie mogę zgodzić. By to wyjaśnić zacznijmy od mojej historii, by łatwiej było zrozumieć dlaczego dla mnie ten temat jest istotny.

    Pan Michał uczył się programować w Javie na studiach, głównie z książki Core Java I i II oraz korzystając z pomocy Jakuba Neumana (z którym miałem laborki). Pojęcie debuggera było mi całkowicie obce, ba pojęcie IDE było obce. Do dziś pamiętam jak dziwiłem się po co w eclipsie trzeba tworzyć projekty. Przecież wystarczy wszystko skompilować i działa :P

    Niestety, ale wtedy nie cały mój kod był tak doskonały jak jest teraz ;) Zdarzał się błędy :( Na szczęście to już za mną :E Wtedy trzeba było jednak znaleźć miejsce w którym aplikacja postąpiła źle (no bo wiadomo, że to nie ja się pomyliłem). Naturalnym rozwiązaniem było System.out.println(); najlepiej co drugą linijkę by zbierać informacje na temat stanu obiektu i możliwych przyczyn błędu. W pracy zacząłem szybko sam zauważać wady takiego podejścia i pojawiła się potrzeba posiadania jakiegoś lepszego medium do logowania. Wpierw próby z przekierowaniem System.out do pliku logów, następnie żmudna nauka log4j i kolejnych frameworków wspierających mnie w tym zadaniu. W moim kodzie znaleźć można przeważnie dużo log.trace/.debug , ponieważ nie jestem nauczony korzystać z debbugera. Walczę z sobą by korzystać z niego częściej, ale logi są przydatne i dla mnie wygodnie się z nimi pracuje. Ponadto są niemal nic nie kosztują przy odpowiednim zastosowaniu.

    Log4j znać winien każdy, slf4j powinno się znać, jak nie znamy to polecam nadrobić, gdyż jest to świetna biblioteka, znacząco ułatwiająca logowanie. Tworząc ten wpis zakładam, że rozumiesz drogi czytelniku, po co tworzy się logi.

    A gdzie w tym wszystkim Tapestry? Ano dziś pokażę wsparcie dla logowania. Przed, bądź po lekturze tego tekstu polecam wszystkim, którzy nie czytali, zapoznać się z serią wpisów  Tomasza Nurkiewicza na temat tworzenia logów. Teksty te wybiegają daleko ponad to co ja pokażę, tu wystarczy nam wiedzieć czym i po co są logi

    No to zaczynajmy, spójrzmy na nasz projekt. Na stronie guessGame wyświetlamy aktualnie poprawny wynik. Nie jest to szczególnie mądre, gdybyśmy teraz wprowadzili opłaty i wygraną za poprawne trafienie, to szybko zostalibyśmy bankrutami. No, ale trzeb przecież sprawdzić czy aplikacja działa i co wylosowała, inaczej skąd mamy wiedzieć, że to w ogóle działa.

    Po pierwsze wstrzykujemy instancję org.slf4j.Logger do naszej klasy

    [sourcecode language="java"]
    @Inject
    private Logger log;
    [/sourcecode]

    I tyle. Tapestry samo zadba o zainicjalizowanie loggera, jako że slf4j jest natywnie wspierany przez framework. Podczas poprawiania nawigacji, wyekstrahowaliśmy z metody setupRender metodę restet(). Wypada sprawdzić co zostało wylosowane

    [sourcecode language="java"]
    void reset() {
    numberToGuess = new Random().nextInt(10) + 1; // moved from setupRender
    log.debug("{} is drawed number", numberToGuess);
    }
    [/sourcecode]

    Wynik jest przewidywalny: [DEBUG] pages.GuessGame 6 is drawed number

    No, ale mamy też bardziej typowe potrzeby logujące, np potrzebujemy sprawdzić co użytkownik kliknął by wiedzieć czy dobra wartość jest przekazywana do kolejnej strony.

    [sourcecode language="java"]
    Object onActionFromGuess(int guess) {
    log.debug("[Enter] onActionFromGuess with param '{}'", guess);
    final boolean isCorrectAnswer = numberToGuess == guess;
    resultPage.setCorrectAnswer(isCorrectAnswer);
    resultPage.setPlayerGuess(guess);
    log.debug("[Exit] onActionFromGuess to page '{}'", resultPage);
    return resultPage;
    }
    [/sourcecode]

    Wynik znów przewidywalny (kliknięty link nr 7)
    [DEBUG] pages.GuessGame [Enter] onActionFromGuess with param '7'
    [DEBUG] pages.GuessGame [Exit] onActionFromGuess to page [email protected]'

    Problemem jest to, że  takich linii Enter - Exit w kodzie może się zrobić dużo. Do tego wyglądają niemal identycznie i idealnie zaśmiecają nam kod. W tym miejscu przychodzi nam z pomocą mała adnotacja @Log

    Usuwamy obie linijki log.debug(...); z metody onActionFromGuess i wstawiamy nad nią adnotację @Log. Otrzymamy takie coś

    [sourcecode language="java" highlight="1"]
    @Log
    Object onActionFromGuess(int guess) {
    final boolean isCorrectAnswer = numberToGuess == guess;
    resultPage.setCorrectAnswer(isCorrectAnswer);
    resultPage.setPlayerGuess(guess);
    return resultPage;
    }
    [/sourcecode]

    A wynikiem dla kliknięcia w 7 będzie
    [DEBUG] pages.GuessGame [ENTER] onActionFromGuess(7)
    [DEBUG] pages.GuessGame [ EXIT] onActionFromGuess [[email protected]]

    Czyli odrobinę inaczej niż ja sam napisałem, ale daje tyle samo informacji.

    Adnotować można wszystkie metody na stronach, bez względu na ich widoczność. Adnotacja w pełni respektuje nasze ustawienia dla loggera więc gdy przenosimy się na produkcję, to nic nie będzie wyświetlane. Poziom logowania jest domyślnie ustawiony na Debug, ale można to zmienić.

    To przyjemnego logowania i do następnego razu.

    Read More »

  • Metaprogramming zamiast konwencji nazw

    Tak chwalę wam i chwalę konwencję nazw i jak to fajnie jest ją mieć, a każdy chyba wymieni mi przykłady, że czasem nie jest to najlepszy pomysł by tylko na niej polegać. I co jak ktoś chce mieć własne nazwy metod lub co gorsza, wykonuje legendarną zmianę wszystkich frameworków bo ma pojo klasy. Czy taka osoba jest skazana na zmienianie nazw po wsze czasy?
    Nie. Nasz dzielny bohater nie jest stracony, gdyż dziś pozna tutaj inne sposoby informowania na oznaczanie ważnych metod w cyklu życia strony/requestu.

    Nasi dzisiejsi bohaterowie to adnotacje i zostali przedstawieni javie w jej 5tym wydaniu. Są już dość długo na rynku, ale do dziś wielu nie może ich zaadoptować. Natomiast tapestry z racji bycia nowym frameworkiem rozpoczęło swój żywot przyjmując w pełni ich dobrodziejstwo.

    Adnotować możemy wiele rzeczy, pola, metody, konstruktory itd. Kilka adnotacji nawet już się na blogu pojawiło, mimo iż starałem się ich za wcześnie nie pokazywać. Streśćmy więc może co już znamy i co jeszcze przyjdzie nam poznać lepiej.

    @Persist - tę adnotację już znamy. Umieszczona nad polem powoduje, że strona zachowuje się jakby posiadała stan (a teoria mówi, że HTTP jest bezstanowe). Zapisywane wartości pakowane są do mapy i wsadzane do sesji użytkownika. Każda z wartości jest związana dzięki temu z danym użytkownikiem, stroną i konkretnym polem a Tapestry troszczy się o to by nie pojawiły się te informacje nigdzie indziej. Poprzez atrybut value adnotacji można doprecyzować zachowanie podczas zapisu.

    @InjectPage - również znamy, umieszczone nad polem wstrzykuje obiekt strony o klasie tej samej co pole. Pozwala to nam przekazywać wartości i nawigować pomiędzy stronami. Adnotacja posiada opcjonalny atrybut, informujący o konkretnej instancji strony do wstrzyknięcia. Do użycia w przypadku gdy klasa pola jest interfejsem implementowanym przez stronę. Dość to naciągane, ale i taką opcję mamy.

    To teraz nowe zabawki. Poznaliśmy już metody  onActivate i onPassivate. Działają dobrze, ale strasznie upierdliwe są i dużo pisać trzeba przy nich. No więc dla leniwych (jak ja) mamy adnotację

    @ActivationRequestParameter - Można nią adnotować jedno pole jedynie, ale dla większości będzie to wystarczająco. Jeśli jest to własny obiekt (nie string, bool etc) to potrzeba będzie dostarczyć translatora (tak jak w przypadku onActivate i onPassivate). Wyjątek stanowią encje hibernata, dla których tapestry samo tworzy translatory (o ile mamy bibliotekę integrującą tapestry z hibernatem w naszym projekcie)

    Zmniejszając ilość kodu w naszej aplikacji trudno jest nie zauważyć wszystkich metod get i set jakie  powstają by wspierać templaty .tml. No więc czas i to usunąć przy pomocy adnotacji @Property. Generuje ona dla prywatnego pola gettery i settery. Dodatkowo, korzystając z atrybutów adnotacji, możemy ustawić by tapestry generowało tylko getter/setter w przypadku gdy drugą metodę stworzymy sami bądź gdy nie chcemy by takowa była dostępna w aplikacji.

    Pamiętacie naszą metodę setupRender(){} ? Otóż okazuje się, że dobrze by było gdyby się nazywała init(){} a nad nią dało się umieścić adnotację @SetupRender. I wiecie co? Da się :) Każda z metod cyklu życia strony ma swój odpowiednik w adnotacji.

    Programując w tapestry natkniemy się na o wiele więcej adnotacji, lecz pozwólcie mi zostawić kilka na przyszłe wpisy, gdy będę zajmować się związanymi z nimi pojęciami. Poza tym wpis mi się robi długi ;)

    Do następnego

     

    PS nie twierdzę, że konwencja nazw jest zła. Wręcz przeciwnie, lubię ją, ale nie zawsze jest ona najlepszym wyjściem. Do pisania na szybko preferuję nazywać moje metody zgodnie z konwencją, gdyż tak mi jest łatwiej (tak, tak onActionFrom też któregoś dnia zamienimy na adnotację). Później natomiast to już różnie bywa. Moja rada: dogadajcie się w teamie jak wam bardziej pasuje programować. Tapestry się do was dostosuje :)

    Read More »

  • Pierwsze kroki w konfiguracji aplikacji w Tapestry5

    Dzisiejszy wpis będzie tylko wstępem do konfiguracji, jako że muszę uzupełnić w tym względzie własne braki :).
    No to dziś będzie nudno, bo będzie dużo xmla... hmm no może jednak nie. Tapestry należy do tych szkieletów aplikacyjnych, w których nie musimy pisać ni linijki w xmlu (pomijając web.xml i templaty, które są dokumentami XHTML czyli XMLami).
    Niektórzy stwierdzą w tym momencie, że bez sensu, nie da się programować w notatniku i na żywo podmieniać na produkcji kodu zmieniając wszystko. A ja powiem, że dzięki temu można dbać o jakość, testować, popełniać mniej błędów, korzystać z wsparcia IDE, refaktoryzować, etc.
    To co warto nadmienić przed przejściem dalej, to że T5 jest zbudowane na module IOC więc cała nasza konfiguracja będzie interakcją z modułem wstrzyknięć. Nadmieniam to tutaj, gdyż mówiąc na co dzień o IOC mam na myśli nasze klasy wstrzykiwane do innych naszych klas. Gdy piszę o konfiguracji, to mam na myśli interakcję z klasami dostarczanymi z Tapestry. Wiem, zagmatwałem :(

    No ale do kodu (z którego komentarze pozwalam sobie wycinać).
    Specyfikacja JEE wymaga od nas byśmy zajrzeli na początek do web.xml, gdzie ponad standardową deklarację XMLa i web app (wymagane przez kontener servletów) znajdziemy następujący fragment

    [sourcecode language="html"]
    <context-param>
    <param-name>tapestry.app-package</param-name>
    <param-value>pl.rits.blog.projektBlogowy</param-value>
    </context-param>
    <filter>
    <filter-name>app</filter-name>
    <filter-class>org.apache.tapestry5.TapestryFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>app</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    [/sourcecode]

    Mam nadzieję, że na dziś się już XMLa naoglądaliście, bo więcej go w tym wpisie nie znajdziecie. Dewianci niech otworzą jakiś projekt Springowy/facowy/strursowy i wrócą za miesiąc, bo w najbliższej przyszłości nie przewiduję więcej XMLa na blogu (no .tml-e się pewnie pojawią, ale niewiele!).

    Słowo wyjaśnienia się teraz należy co widać w zamieszczonym kodzie. Zdefiniowaliśmy root projektu, dzięki temu T5 będzie się w stanie znaleźć w naszej aplikacji (od podanego tu pakietu, szukane są pakiety pages, components, etc).

    Druga istotna informacja to rejestracja filtra tapestry i określenie jego nazwy na app. Definiuje ona nazwę klasy w której będziemy dokonywali konfiguracji naszej aplikacji. Dla przykładu: jeśli pozostanie ona zdefiniowana jako app, to tapestry będzie szukać klasy ${rootProjektu}.services.AppModule.java. Brak tej klasy nie jest błędem, ale uniemożliwia nadpisanie jakichkolwiek domyślnych ustawień tapestry. Wyłączy nam też możliwość definiowania nowych services więc de facto poza pół statycznymi aplikacjami, ta klasa będzie zawsze obecna.

    Przejdźmy więc do niej i sprawdźmy co w niej znajdziemy. Niestety jest tego niewiele. Nie ma interfejsu, dziedziczenia ani, co gorsza, XMLa! :( Hańba!

    Jest za to kilka metod. Przypomnę, że tapestry to Convention over Configuration więc korzysta z konwencji nazw by umożliwić nam konfigurację. Niestety zmiany w tej klasie będą wymagały restartu aplikacji, live class reloading tu nie działa, z doświadczenia za to wiem, że to nie jest uciążliwy problem. Po pierwszej konfiguracji jedyną zmianą jest dokładanie kolejnych services. Spójrzmy na 2 z metod znajdujących się domyślnie w klasie (tj znajdujących się w mavenowym archetypie):

    [sourcecode language="java"]
    public static void bind(ServiceBinder binder) {
    // binder.bind(MyServiceInterface.class, MyServiceImpl.class);
    }
    public static void contributeApplicationDefaults(MappedConfiguration configuration) {
    configuration.add(SymbolConstants.SUPPORTED_LOCALES, "en");
    configuration.add(SymbolConstants.PRODUCTION_MODE, "false");
    configuration.add(SymbolConstants.APPLICATION_VERSION, "0.0.1-SNAPSHOT");
    }
    [/sourcecode]

    Pierwsza metoda służy do powiadomienia kontenera IOC tapestry o istnieniu naszego service (w springu zwanego beanem, co BTW jest dla mnie najbardziej denerwującą rzeczą w całym springu).
    Serwisy w tapestry standardowo składają się z interfejsu oraz jego implementacji, choć pierwsze może zostać pominięte (niezalecane). Nazwa powinna być znana użytkownikom HiveMind (który był stworzony na potrzeby poprzedniego tapestry).
    Powiązanie pomiędzy implementacją a interfejsem tworzone jest po .class, dzięki czemu możemy refaktoryzować nasz kod w dowolnym IDE, a i tak będzie nas ono wspierało. Powiązania są również wyszukiwalne, choć oba punkty stają się coraz mniej aktualne wraz z wzrastającym wsparciem  wszystkich IDE dla Springa. Wspominam o tym jednak, gdyż w dawnych czasach, zdarzyło mi się pomagać koledze utrzymującemu naszą aplikację, znaleźć błąd w mojej klasie. Po dłuższej chwili okazało się, że nastąpiły zmiany w klasach, które nie zostały odzwierciedlone w plikach XML.

    Druga metoda dokłada się do domyślnych ustawień aplikacji, co to dokładnie oznacza wyjaśnię w jednym z przyszłych wpisów. Do metody tapestry dostarczy nam obiektu, który jest taką a'la mapą do której można tylko wkładać. Klucz odpowiada za nazwę opcji a wszystkie opcje można znaleźć w obiekcie SymbolConstatns. Opisy poszczególnych ustawień można znaleźć na stronach tapestry.
    My dodamy jedno od siebie configuration.add(SymbolConstants.COMPRESS_WHITESPACE, "false");
    Dzięki temu łatwiej się developuje (przynajmniej mi) bo więcej widać. Co to zmienia? Przed zmianą podejrzyjcie dowolną stronę wygenerowaną przez T5, a następnie tę samą stronę po zmianie (w przeglądarce korzystamy z opcji source/pokaż źródła ctrl+u).

    I wszystko jasne.  Tapestry kompresuje mnóstwo rzeczy by do klienta szło jak najmniej danych. Domyślnie tapestry Gzipuje niektóre dane (o czym za chwilę poniżej) oraz wycina zbędne białe znaki (co właśnie zmieniliśmy). Domyślny rozmiar danych by zostały skompresowane to 100 bajtów, ale da się limit ten zmienić w sposób analogiczny do kompresji białych znaków.

    Ciekawostka. Opcja Application_Version jest przydatna :) Na czas developmentu opcję tę kasujemy, przywrócimy ją dopiero jak aplikacja pójdzie live. Dlaczego? Odpowiada ona za przygotowywanie tzw. Assetów (czyli wszystkiego co może zostać wysłane do przeglądarki). Przygotowanie polega na wkomponowaniu w adres URI zasobów numeru wersji. Dzięki temu przeglądarka może cachować po stronie klienta zasoby i pobierać je ponownie dopiero gdy zmieni się numer wersji. Gdy nie podamy tej opcji w ogóle to za każdym uruchomieniem generowany jest losowy numer, co pozwala nam uniknąć ręcznego czyszczenia cachu by zobaczyć wyniki naszych zmian.

    To na dziś tyle. Może krótko, ale jak wspominałem sam mam braki w temacie. Jednak pomimo tego czułem potrzebę omówienia zagadnienia konfiguracji. Przepraszam również, że wpis ukazuje się tak późno. Był gotów w zeszłą niedzielę, ale po windows updatcie i pewnej dozie nerwów z tym związanych, postanowiłem go opublikować w poniedziałek. Naiwny, nie widziałem wtedy jeszcze, że czeka mnie piekielny tydzień.
    Postaram się nadrobić tekstem jutro :)
    Do przeczytania

    Read More »

  • Czas wyjść do ludzi

    Jako, że Tapestry zmieniło stronę główną, upgradowało dokumentację i ogółem jest super a najlepsza przeglądarka wydała właśnie najnowszą betę to może i dla bloga jest dobry czas by się pokazać w pełni publicznie. Dotąd wpisy były znane nie licznym, teraz czas się rozpropagować i oczekiwać jakiegoś feedbacku.

    Nie jest to wprawdzie dla mnie najlepszy okres, pracy mam co nie miara bo u klienta drobna restrukturyzacja, ale kiedyś trzeba zacząć się mocniej starać. Postaram się nadrobić na dniach zaległości. Co do tapestry to czeka mnie konfiguracja, dzielenie wartości w szerszym scopie niż page i request, wstrzyknięcia, coś o budowaniu URLi, internacjonalizacja, metaprogramowanie i kilka innych tematów. Jak skończę podstawy to planuję screencasty albo poświęcenie większej uwagi innym tematom. Od dawna czeka na mnie gradle. Zacząłem się nim bawić w okolicach ver 0.7/0.8, ale wtedy uznałem, że to za wcześnie by w to wejść i jakoś się z mavenem przemęczę ten czas. Czeka też na mnie ibatis 3 (w sumie to obecnie myBatis). Wersja 2 była dla mnie zwycięzcą jeśli chodzi o frameworki do utrwalania, choć nie na każdym polu. Śledząc informacje od wczesnych bet o nowej wersji mam wrażenie, że myBatis będzie w stanie zastąpić mi całkowicie ORMy, bądź zwiększyć choć pole zastosowania. Przyglądałem się też od dłuższego czasu różnym językom innym niż java, ale to na później odchodzi, jako że czasu brak. O tematach nie tyczących się technologi bezpośrednio nawet nie będę pisać.

    Jak widać jest trochę tematów, które się tu pojawią. Mam nadzieję utrzymywać tempo choć jednego wpisu na tydzień, mniej będę uznawać za osobistą porażkę.

    No to zaczynamy :)

    PS będę też twittować, choć jeszcze nie jestem pewien jak chcę wykorzystać Twittera, to wiem że go tu jakoś należało by podpiąć ;)

     

    Do następnego wpisu, oby szybko.

    Read More »

Michal Gruca
Michal Gruca

Manager by title, developer at heart

Twitter Email

TOC