wtorek, 24 czerwca 2008

Tools Dig: LiquiBase

Wczoraj marudziłem na brak railsowych migracji w popularnych frameworkach javowych, a już dziś dzięki uprzejmości Pawła Sto (p100 :) ), poznałem bardzo ciekawe narzędzie jakim jest LiquiBase. Narzędzie to posiada większość elementów z railsowych migracji oraz jest nawet śmiem twierdzić nieco lepsze od nich (odczuć mogą to zwłaszcza teamy developerskie, gdzie jest więcej niż 4 programistów i jedno repozytorium kodu :) ).

Dlatego wszem i wobec zachęcam wszystkich do zapoznania się z toolem (http://www.liquibase.org). Warto zwłaszcza zerknąć na screencasty: krótkim (6min) lub dłuższym, obszerniejszym (30min). Omawiają starszą wersję narzędzia, ale dają ogólny taki overviewu, warto obejrzeć.

Niniejszym rozpoczynam też nową mini-serię na moim blogu: Tools Dig . Często napotykam na ciekawe narzędzia w sieci. Jak zwrócił mi uwagę mój kolega, warto się takim znaleziskami dzielić z szerszą publiką, a do tego idealnie nadaje się ten blog. Co niniejszym czynię.

poniedziałek, 23 czerwca 2008

Migracje bazodanowe: czego w Javie nie znajdziemy?

Czytam sobie sporo o Railsach ostatnio. Na tyle mi się framework spodobał (i język Ruby też), że chwilowo nawet myślałem o całkowitej migracji Java -> Ruby & Rails. Ponieważ jednak firm RoR'owych u nas we Wrocławiu jak na lekarstwo (w sumie tylko jedna, pracowników serdecznie pozdrawiam :) ), to ostatecznie pomysł ten zarzuciłem. Nie zmienia to faktu, że czytanie książek i blogów o Railsach sporo mi dało. Inaczej teraz trochę patrze na programowanie, jest też kilka spraw, które w frameworkach Javowych bardzo mi od tego czasu brakuje.
Jednym z takich elementów są migracje (ang. migrations), potężne narządzie frameworka Ruby on Rails.
W Javie pisząc aplikacje wykorzystujące bazę danych przyzwyczailiśmy się już do frameworków tzw. mapujących. To znaczy takich, w których model biznesowy jest mocno zintegrowany z bazą danych. Boli nas trochę fakt, że gdy tworzymy aplikacje z wykorzystaniem jakiegoś narzędzia ORM'owego, musimy wyspecyfikować:

- pole w modelu
- getter
- setter
- mapowanie w kierunku a->b
- mapowanie w kierunku b->a
- definicje kolumny

Oczywiście nie można dramatyzować: model (a wiec odpowiednie fieldy, gettery, settery) pomoże nam stworzyć nasze ulubione IDE, a najnowsze frameworki (z wykorzystaniem adnotacji) umiejscawiają nam definicje bazodanowe w samym modelu. Wszystko robi się niby DRY (Don't Repeat Yourself), wszystko wydaje się być w jednym miejscu i wszelkie zmiany w projekcie można wprowadzać bezboleśnie. Zapominamy tutaj o jednej ważnej sprawie - danych w bazie danych.

Możemy wyobrazić sobie, że po miesiącu czy dwóch naszego developingu, powstaje aplikacja/prototyp, która zostaje wdrożona u klienta. Schemat bazy danych jest oczywiście generowany z naszego modelu na bazie produkcyjnej u klienta. Czysta, nowa, świeżutka baza wraz z aplikacją zostaje uruchomiona. My zabieramy się za kolejną iterację, a klient wdraża się w jej pierwszą wersję. W między czasie dodajemy nowe kolumny, zmieniamy nazwy tabel, łączymy pewne rzeczy w jedną całość - jesteśmy bardzo agile - nie boimy sie zmian. Przychodzimy do klienta, chcemy mu wygenerować nowa bazę a on nam mówi "Hola hola, ja tu już mam pewne dane, nie chce ich tracić". Po chwili namysłu dochodzimy do wniosku, że możemy wygenerować plik SQL, w którym umieścimy wszystkie zmiany w nowej bazie danych względem tej starej (znany wszystkim DDL, czyli alter table i takie tam) i tak gotowy skrypt uruchomimy po stronie bazy produkcyjnej.

Ok, rozwiązanie niby dobre. Spotkałem się z nim w praktyce, pliki takie nazywane były "patchami" (moim zdaniem nazwa dobra) i tworzone były dla każdej kolejnej iteracji przygotowywanej aplikacji. Trzymane wraz z kodem w repozytorium nie miały prawa zaginąć. Teraz tworząc pole String nickname w modelu User musiałem dodatkowo w patchu patch_078.sql umieszczać wpis "alter table add column nickname varchar". W momencie integracji wersji deweloperskiej z produkcyjną, po wprowadzeniu zmian w kodzie uruchamiany zostawał patch i schemat bazy był aktualny z modelem. Wszystko niby fajnie, ale właśnie tu zaczynają się schody. Po pierwsze przestaje mieć pojedyńczej informacji (w tym przypadku informacji o schemacie bazodanowym) w jednym miejscu - co szybko prowadzić może do pomyłek. Druga sprawa to brak powiązania tych zmian z kodem na repozytorium. Wprowadzę zmiany w kodzie, commitne, mnie trochę czasu, update'uje patch na repozytorium. Mijają cztery dni i okazuje się, że muszę cofnąć zmiany w moim modelu. Muszę PAMIĘTAĆ, że odpowiednie zmiany powinny być update'owane w patchu (rollback na repozytorium mi tego nie zapewni). Ból, ból, ból i zgrzytanie zębów.

O wiele ciekawiej rozwiązane jest to w Railsach. Patche (tutaj zwane migracjami) tworzone są za nas automatycznie. Taki patch zawiera nie tylko metodę updatującą schemat bazy, ale również wycofującą te zmiany. W ogólności każda migracja to klasa Ruby'ego implementująca dwie metody up oraz down. Metoda up wprowadza zmiany w schemacie bazy danych, metoda down je wycofuje. Przez co uzyskujemy patch działający w dwie strony. Zestaw operacji jakie możemy wykonać jest dowolny, możemy wstawiać dane, zmieniać strukturę schematu (z użyciem predefiniowanych metod podobnych do tych które znamy z DDL, czyli create/drop table, add/remove column i tak dalej). Każda taka migracja ma przypisany swój numer porządkowy, a sam schemat trzyma informacje o swojej wersji. Jeśli zatem przykładowo mamy schemat bazy danych w wersji 004, a w czasie developingu pojawiły się dwie nowe migracje 005 oraz 006, to wywolanie komendy rake migrate spowoduje, że framework wywoła w kolejności metody up, najpierw z migracji 005, a następnie z migracji 006,a na końcu zmieni wersję schematu na 006. Jeśli kiedykolwiek trzeba będzie sie cofnąć w zmianach schematu, na przykład do wersji 004, wykonane zostaną kolejno metody down w migracji 006, a poźniej w 005. Piękna sprawa!

Klasy migracji są tworzone dla modeli automatycznie, więc nie ma obawy, że do repozytorium nie zostaną przekazane razem. Wtedy cofnięcie się w ramach repozytorium do kodu z przed na przykład kilku dni nie stanowi problemu.

O migracjach w Rails można by mówić wiele, fakt faktem brakuje mi czegoś takiego w frameworkach Javowych. Słyszałem, że jakieś OMR'y generują patche dla konkretnej bazy danych w oparciu o zmiany jakie zaszły w modelu. Jakie? Nie wiem, może wy mi powiecie, jestem bardzo ciekaw. Wtedy byłoby już fajnie, chociaż wciąż nie pozostawalibyśmy DRY, ale przynajmniej były to już jakiś krok w dobrym kierunku.

Orginał tego postu wyglądał ciutkę inaczej od tego co tu przeczytałeś, ale durny siersciuch (kot) gonił muchę po mieszkaniu, przebiegł się po klawiaturze, skasował sporą część zaznaczonego tekstu, a blogspot automatycznie po kilku sekundach zapisał zmiany. 40% tekstu jest odtworzone, a więc podatne na błędy i gorsze jakościowo - nie cierpie pisać czegoś dwa razy.

Z kota zrobie jutro gyros.


update:
jeśli ktoś zna jakiś framework, który rzeczywiście na podstawie schematu bazy i modelu, jest w stanie wygenerować skrypt sql ze zmianami jakie należy wprowadzić w bazie, niech da mi prosze znać na maila lub w komentarzach. W JPA szukałem i się nie doszukałem.

sobota, 21 czerwca 2008

Świat kawy

Kawa, źródło życia chyba większości programistów. Chociaż staram się ograniczać, bo by mój żołądek nie wytrzymał, to jednak poranka przed kompem nie wyobrażam sobie bez kubka gorącej kawy z mlekiem.

Tym wstępem nie zaczynam jakiegoś referatu, czy innej rozprawki. Nie bójcie się o to, przynudzać nie będę. W zamian, będę się chwalił. A dokładnie będę się chwalił moją narzeczoną, która zaliczając 4 roku studiów na Architekturze Wnętrz popełniła coś takiego:


Chociaż ona uważa, że nie jest to jej najlepsza praca i miewała ciekawsze, to jednak dla mnie to jest mistrzostwo (czy jak mawiała moja polonistka miczostwo). Do takiego sklepu na filiżankę kawy chętnie bym przychodził. Jest to dla mnie zupełnie inna jakość, coś znacznie ciekawszego od tego, do czego przyzwyczaiły nas centra handlowe.

Może przesadzam, w końcu wszystko co wyjdzie z łap Magdy wydaje mi się zajebiste, ale osobiście uważam, że ten projekt dał radę.

Java Killers #008

Witam po dłuższej przerwie w kolejnej odsłonie cyklu Java Killers. Standardowo bez dłuższych wstępów, przejdziemy od razu do kodu, by główkować, dziwić się i przeklinać.

Oto on:


package javakillers.part008;

/**
* @author pawel zainspirowany koziolekweb
*/
public class Main
{
public static void main( String[] args )
{
foo(null);
foo((Object)null);
}

public static void foo(Object object )
{
System.out.print("object ");
}
public static void foo(Object ... objects )
{
System.out.print("objects ");
}

}


Pytanie, jaki będzie wynik uruchomienia powyższego programu, pozostaje wciąż otwarte. Odpowiedzi do wyboru (do koloru):

A) program się nie skompiluje
B) program się skompiluje, ale wyrzuci java.lang.ClassCastException
C) program się skompiluje, ale wyrzuci java.lang.NullPointerException
D) program się skompiluje, uruchomi i wyświetli "object object"
E) program się skompiluje, uruchomi i wyświetli "objects objects"
F) program się skompiluje, uruchomi i wyświetli "objects object"
G) program się skompiluje, uruchomi i wyświetli "object objects"

Zanim przeczytasz rozwiązanie, spróbuj pomyśleć nad odpowiedzią.


Prawidłowa odpowiedź to F) program się skompiluje, uruchomi i wyświetli "objects object". Czemu? Żeby się dowiedzieć, musicie odwiedzić blog koziołka, bo właśnie tam przeczytałem post, który zainspirował mnie, do dzisiejszego odcinka cyklu Java Killers. Polecam!

piątek, 20 czerwca 2008

Paradoks czasowo-przestrzenny

No i jeszcze z ciekawostek dzisiejszego dnia: dostałem informację od recenzenta, że praca magisterska jest już oceniona, po czym godzinę później dowiedziałem się od kolegi, że mój promotor mnie szuka,ponieważ moja praca magisterska jest jeszcze nie skończona...

Hmm....

Nie wiem do końca jak, czemu i w jaki sposób, ale jest jak jest. Mam ocenioną pracę, która podobno jeszcze nie jest skończona :) W poniedziałek czeka mnie wycieczka (hurra...) na Politechnikę, żeby sprawę wyjaśnić.

Ps. Dostałem 5.0 z recenzji :)

Rozmowy rekrutacyjne - esencja cz. 2

Kolejna ciekawą sprawą jest fakt, że na rozmowach rekrutacyjnych nie za wiele osób sprawdza wiedzę praktyczną. Zwykle osoba rekrutująca pyta się o poszczególne etapy kariery wypisane w CV, zadając pytania typu "Co było największym osiągnięciem w firmie X", "Jakie były Twoje zadania, gdy pracowałeś w Y". Udzielając odpowiedzi na nie pokazujemy rekrutującemu czy po pierwsze na prawdę tam pracowaliśmy (można być zatrudnionym jako programista, a w praktyce podawać kawę przez większość dnia). Poza tym sprawdzane jest jaki był nasz zakres kompetencji, jakie były stawiane przed nami problemy i co takiego tak na prawdę wnieśliśmy do firmy. Wszystko fajnie, z tym, że uważam, że dobry ściemniacz i lawirant, poradziłby sobie bez problemu w opowiadaniu czego on nie zrobił i jak pięknie to nie działało. Każdy może przecież upiększać i koloryzować swoje osiągnięcia. Dlatego dziwi mnie fakt, że na rozmowach o pracę nie proszono mnie o pisanie choćby kawałka kodu. A to przecież kod tak na prawdę świadczy o programiście.
Często pojawiają się pytania z dziedziny informatyki, Javy, wzorców projektowych. I to już jest rzeczywiście fajnie, ale uważam, że to wciąż za mało i choćby kawałek kodu do napisania mówił by o wiele więcej, niż tysiące sztampowych, powtarzających się w kółko pytań. W idealnym układzie powinno się prosić o napisanie choćby kawałka kodu, lecz nie zostawiać programisty samemu sobie, a patrzeć jak podchodzi do problemu. Ocenić logiczne myślenie, (nie)szablonowość, radzenie sobie z problemami. Żywe zadanie, żywy problem - to powinno być esencją rozmowy rekrutacyjnej. Chyba tylko w czasie jednej rozmowy o pracę poproszono mnie o napisanie kawałka kodu.

Można zadać sobie pytanie - a co mnie to obchodzi, przecież to nie ja rekrutuje. Niby tak i też nie do końca. Zakładając, że idę do pracy do takiej firmy, gdzie rekrutacja była poprowadzona po łebkach, mogę się spodziewać, że do mojego zespołu trafią: lawiranci, lenie, ściemniacze, cieniasy (lub hybrydy powyższych). O atmosferze pracy świadczy team! Chce pracować z ludźmi fajnymi, ale również osobami, które coś ze sobą wnoszą, kompetentnymi.
Oczywiście jest okres próbny, w praniu wychodzi, kto tak naprawdę się nadaję i każde kłamstewko wypowiedziane w czasie rozmowy o pracę wyjdzie na jaw. Dziwi mnie tylko fakt, że pracodawcom nie przeszkadza taki tryb. Osobiście uważam, że rekrutacja na stanowisko programisty powinna sprawdzać wiedzę kandydata rzetelnie, dokładnie i do bólu. Przynajmniej na to byłem przygotowany, a w kilku firmach nawet nie słyszałem pytań sprawdzających wiedzę, pracodawca brał wszystko na słowo. Dziwi mnie to, ale może rzeczywiście nie mnie to osądzać.

Oczywiście nie powinienem też dramatyzować. Kilka firm przeprowadziło rzetelne rozmowy rekrutacyjne i jeśli kiedykolwiek miałbym usiąść po drugiej stronie stołka, być osobą zadającą pytania, na pewno korzystałbym z doświadczenia z tamtych spotkań, które uważam za naprawdę udane.

czwartek, 19 czerwca 2008

Rozmowy rekrutacyjne - esencja cz. 1

Jestem obecnie w trakcie poszukiwania pracy. Jakieś 10 dni temu porozsyłałem moje CV po różnych firmach IT we Wrocławiu, a później po krótkim okresie oczekiwania zostałem zapraszany na kolejne rozmowy o pracę. Odwiedziłem kilka(-naście) większych i mniejszych firm IT i z wnioskami z tych spotkań chciałbym się z Wami podzielić. Jeśli szukacie lub planujecie szukać pracy w najbliższym czasie potraktujcie ten wpis jako pewnego typu przewodnik po procesie rekrutacji.
Zacznę na początek od pytań, które pojawiają się zawsze lub prawie zawsze.

"Kim jest Paweł Szulc?"

To pytanie rozwala i niszczy. Pojawia się na samym początku rozmowy rekrutacyjnej i wydaje mi się, że zadawane jest po to, aby już na samym początku zbić nas z tropu. No bo słyszycie takie pytanie i co w ogóle wtedy myślicie? Co to jest za pytanie, jaki jest jego sens? Czy mam teraz w 15 zdaniach opisać swoją osobowość, charakter, życiorys a na końcu odnieść się do tego wszystkiego w pięknym podsumowaniu? Czy może pytają się kim jest Paweł Szulc jako programista, co umie, co potrafi, gdzie zdobył szlify i doświadczenie. Moją pierwszą reakcją było zadanie sobie samemu pytania, jakiej odpowiedzi oni oczekują. Ponieważ nie byłem sobie w stanie na to pytanie sam odpowiedzieć, spytałem się ich: w jakim sensie, w jakim kontekście zadane jest to pytanie. Odpowiedź powala na kolana: "Dowolnym".
Musicie sobie zdać sprawę, że jest to pytanie na krasomówczą pułapkę. Wydaje mi się, że to pytanie zadawane jest po to, żeby tak naprawdę usłyszeć co ciekawego opowie nam ta osoba o sobie. Nie chcą wiedzieć, kim jest Paweł Szulc. W 15 zdań nikt nie jest w stanie siebie opisać i pracodawcy dobrze o tym wiedzą. To pytanie z samej natury ma być enigmatyczne, ma lekko zagiąć, zdziwić. Chodzi o sprawdzenie jak osoba poradzi sobie w takiej sytuacji, czy umie coś o sobie powiedzieć i jeśli tak to w jaki sposób. Ponieważ usłyszałem to pytanie na 90% rozmowach rekrutacyjnych, szanse są, że i wy je usłyszycie. Warto być tego świadomym i mieć przynajmniej szkielet jakieś gadki gotowy na poczekaniu.

"Czemu wolałby Pan pracować w mniejszej firmie?"

Na początek, żeby coś sobie wyjaśnić. Nie aplikowałem mojego CV do żadnej z firm typu Siemiens, Comarch czy innych większych korporacji. Nie ma w tym jakieś konkretnej przyczyny. Po prostu nie bawi mnie praca w firmie, gdzie struktura pracy nakazuje raportowanie do czterech rożnych szefów, gdzie przychodzę pracować jako programista Java kończę jako programista C++. Słyszałem różne historie i jakoś się zraziłem. W życiu zawodowym otarłem się o mniejsze firmy (w sensie mniej niż 100 osób) i z każdą doświadczenie mam jak najbardziej pozytywne. Ja WIEM, że 3/4 studentów po informatyce rzuca się na większe firmy. Jestem tego świadomy. Osobiście się temu dziwie, bo chyba jeśli w takich firmach jest taka rotacja pracowników, że cały czas kogoś nowego przyjmują, bałbym się trochę składać tam papiery.
No ale mam świadomość, że tak jest. Pracodawcy mniejszych firm jak widać też mają. Praktycznie na każdej rozmowie, na której byłem pytano się mnie: "A czemu nie korporacja?". Po trzeciej takiej rozmowie miałem już gotową gadkę i byłem na to pytanie przygotowany, ale z początku w sumie było jedno z tych pytań, które mnie dziwiło, nie dlatego, że nie wiedziałem jak na nie odpowiedzieć, a dlatego, iż dziwiłem się, że w ogóle było zadawane. Dla mnie naturalnym był fakt, że najpierw szukam zatrudnienia przede wszystkim w mniejszych firmach IT. Jak widać nie dla wszystkich jest to naturalne.

"Ile chciałby Pan zarabiać?"

Nie powinno nikogo dziwić, że pytanie to będzie zadane. Osobiście uważam, że trzeba przed rozmową rekrutacyjną dokładnie wiedzieć, ile się chce zarabiać w danej firmie i kwotę to podać natychmiast, po zadaniu pytania. Na jednym wydechu, bez zająknięcia. Wtedy pracodawca widzi, że sprawę mamy przemyślaną, wiemy dokładnie czego chcemy. To pytanie nigdy nie jest negocjacją. Pracodawca odpowie "aha" lub "yhmmm", zapisze sobie kwotę na papierze i o tym czy mu kwota ta pasowała dowiemy się dopiero, po kilku dniach od rozmowy. W całym moim życiu miałem dwa wyjątki od tej reguły: raz osoba rekrutująca spytała się czy nie da się mniej, innym razem rekrutująca osoba powiedziała, że im to odpowiada i czy się decyduje na pracę (tak tak, miałem się określić w dniu rozmowy rekrutacyjnej - rekord świata moim skromnym zdaniem ;) ).
Dlatego powtarzam, na to pytanie trzeba być przygotowanym. Osobną sprawą jest kwestia ile powiedzieć, że chce się zarabiać. To wszystko zależy. Jak już pisałem jakiś czas temu, w Polsce nie obowiązują zachodnie standardy podawania widełek płacowych. Szkoda, naprawdę, ale takie są realia. Sprawę pogorsza fakt, że na takich serwisach jak ocenpracodawce.pl, zwykle piszą albo frustraci, których wywalono z roboty, albo sami pracodawcy, żeby podnieść sobie rankingi. Nie istnieje nic takiego jak średnia dolnośląska czy średnia wrocławska. U jednego pracodawcy X złotych może zarobić już początkujący programista, u innego na start można otrzymać co najwyżej 2/3 tej sumy. Osobiście wydaje mi się, że należy przekalkulować ile się wie i jak się samego siebie ocenia, następnie zrobić research wśród znajomych i kolegów ile zarabiają i odnosząc się do ich wiedzy i umiejętności odnaleźć, gdzieś tam swoją średnią.

Najważniejsze jest jednak, żeby się CENIĆ. Warto to powtórzyć dwa razy: najważniejsze, żeby się cenić. Znam przypadki kolegi, który pracował w firmie IT we Wrocławiu za 1600zl na rękę. Przepraszam, ale w obecnej dobie to się robi po prostu śmieszne. Albo przykład, o którym już kiedyś pisałem, chłopaka, który przez 3 miesiące pracował za darmo na "praktykach" mimo, że wykonywał robotę taką jak wszyscy inni w firmie. Pracodawcy widząc osobę, która aż się prosi, żeby ją wykorzystać, zrobią to, bez wahania. Nigdy, prze nigdy, nie bądźcie takimi osobami! Ceńcie się za swoją wiedzę i doświadczenie. Dla dobra swojego i naszego ogółem.

ciąg dalszy nastąpi....

poniedziałek, 16 czerwca 2008

Porsche nie w najbliższym czasie...

W najbliższym czasie na Porsche raczej mnie nie będzie stać. Wydawać się by się mogło oczywistość - mam 24 lata, na Porsche przyjdzie jeszcze czas... jeśli w ogóle.

Ale ja miałem plan!! Piękny, genialny, plan. Oczywiście serwis (praktycznie nie)społecznościowy, no bo cóż innego mógłbym wymyślić? Jestem informatykiem, od czasów naszej-klasy, każdy z mojej branży pluje sobie w brodę - "przecież ja to mogłem zrobić". Ale ten pomysł był naprawdę świeży, oryginalny. Czegoś takiego na świecie nie było.

No i pielęgnowałem tą ideę, liczyłem dni do końca pracy magisterskiej. Pomysł powstał rok temu, a ja spokojnie sobie czekałem. Plan był prosty: skończyć studia, a następnie zabrać się za to z kopyta i po dwóch latach jeździć nowiutkim Porsche :)

Co się okazało? Pracę oddałem do recenzji 8 czerwca, 2 tygodnie wcześniej powstał portal, w założeniach identyczny do mojego pomysłu. Po prostu taka kopia jeden do jednego. Grrrrr.... jestem zły, wściekły i wkurzony. Jak jeszcze im to wyjdzie, serwis wypali, zdobędą sławę, kobiety i pieniądze, to się chyba po prostu potnę ;).

Rada dla wszystkich: uczcie się na moich błędach. Zwlekanie nie popłaca. Jak coś Was natchnie, bierzcie się od razu do roboty. W innym wypadku będziecie potem tak jak ja, przez dwa dni gryźć klawiaturę, a trzeciego dnia wylewać swoje frustracje na blogu.

niedziela, 1 czerwca 2008

Rails 2.1

Jeszcze niedawno pisałem o problemie jaki stawia przed młodym adeptem Railsów wybór wersji (1.2.6 vs 2.0.2), a już zdążyła wyjść kolejna wersja RoR opatrzona numerkiem 2.1. Z taką prędkością z jaką rozwija się się framework (półroku kolejne wydanie) trudno będzie nadążyć chyba jakiemukolwiek autorowi książki. Nie mamy jeszcze książki na świecie o Rails 2, (bo nawet The Rails Way opisuje wersję edge) a tu już ogłoszono Railsy w wersji 2.1.

Oczywiście wszystko to ma swoją logikę, w Portland odbywa się teraz konferencja RailsConf i jak to bywa na konferencjach, trzeba coś ogłosić - taka już natura chyba każdej większej konferencji :). Ale fakty pozostają mimo wszystko te same: framework się rozwija, co cieszy niezmiernie.

Jeśli ktoś jest żądny wiedzy co nowego w najnowszych railsach, może przeczytać wpis na oficjalnym blogu frameworka. Ja narazie w szczegóły wdawać się nie będę, bo po prostu nie czuję się kompetentny. Gorąco zachęcam natomiast do obejrzenia RailsCast'ów poczynając od #106 do #109 włącznie, gdzie Ryan Bates opisuje najnowsze featury w Rails 2.1. Warto obejrzeć wszystkie, nawet jeśli jesteś takim newbs'em jak ja ;).

Java Killers #007

Witam na kolejnej odsłonie cyklu Java Killers. Dzisiejszy przykład jest hybyrdą przykładu nadesłanego przez Damiana Szczepanika oraz małego triku, który znalazłem na sieci (niestety źródło zapodziałem :( ). Myślę, że dzisiejszy JK nie powinien sprawić kłopotu nikomu, kto zdawał SCJP, ale kto wie, moze się mylę?
Zatem spojrzmy na naszych bohaterów, trzy klasy: Matcher1, Matcher2 oraz Matcher3.


1 package javakillers.part007;
2
3 /**
4 * @author pawel
5 */
6 public class Matcher1
7 {
8 void g(int x)
9 {
10 System.err.print("int ");
11 }
12
13 void g(long x)
14 {
15 System.err.print("long ");
16 }
17
18 void g(Integer x)
19 {
20 System.err.print("Integer ");
21 }
22 }
23
24


1 package javakillers.part007;
2
3 /**
4 * @author pawel
5 */
6 public class Matcher2
7 {
8 void g(short x)
9 {
10 System.err.print("short ");
11 }
12
13 void g(byte x)
14 {
15 System.err.print("byte ");
16 }
17
18 void g(long x)
19 {
20 System.err.print("long ");
21 }
22
23 void g(Integer x)
24 {
25 System.err.print("Integer ");
26 }
27 }
28
29


1 package javakillers.part007;
2
3 /**
4 * @author pawel
5 */
6 public class Matcher3
7 {
8 void g(int x)
9 {
10 System.err.print("short ");
11 }
12
13 void g(Integer x)
14 {
15 System.err.print("Integer ");
16 }
17
18 void g(Object x)
19 {
20 System.err.print("Object ");
21 }
22 }
23
24


I na koniec metoda, która to wszystko uruchomi:


9 public static void main(String[] args)
10 {
11 int prim = 10;
12 Object obj = prim;
13 Integer intObj = (Integer) obj;
14
15 new Matcher1().g(prim);
16 new Matcher2().g(prim);
17 new Matcher3().g(obj);
18 new Matcher3().g(intObj);
19 }

Pytanie, które pozostaje otwarte, to co zwróci nam wywołanie tej metody? Odpowiedzi do wyboru aż sześć:

A) int Integer Object Integer
B) int long Object Integer
C) int Integer Integer Integer
D) int long Integer Integer
E) Integer Integer Integer Integer
E) Integer Integer Object Integer

Zanim przeczytasz rozwiązanie, spróbuj pomyśleć nad odpowiedzią.

Prawidłowa odpowiedź to oczywiście B) int long Object Integer. Aby zrozumieć czemu tak a nie inaczej należy wiedzieć, że przekazując metodzie wartość typu innego niż się spodziewała, dokonana zostaje konwersja typów (method-call conversion jeśli chcemy się trzymać terminologii). Konwersja jest możliwa tylko, jeśli typ metody jest "szerszy" (ang. widening conversion) od typu przekazywanego. Tak więc int'a przekażemy do metody z longiem ale nie na odwórt. Typy od "najwęższych" do "najszerszych" uszeregowane są następująco:

byte -> short -> int -> long -> float -> double

Ot i cała filozofia. Odnośnie ostatniego Matchera3, w pierwszym przypadku spodziewamy się obiektu klasy Object i ją dostajemy, w następnym wywołaniu obiektu klasy Integer i ją dostajemy. Mimo że jest to wciąż jeden i ten sam obiekt, to jednak kontekst wywołania jest różny, stąd i inne dopasowanie typów podczas wywoływania metody.