sobota, 20 grudnia 2008

Prostota i elegancja Ruby'ego

Załóżmy, że potrzebujemy metodę, która na podstawie otrzymanej kolekcji klientów zwróci nam kolekcję ich nazwisk.


Java:

public Collection<String> surnames(Collection<Customer> customers) {
Collection<String> surnames = new ArrayList<String>(customers.size());
for (Customer customer : customers) {
surnames.add(customer.getSurname());
}
return surnames;
}

Ruby:

def surnames(customers)
customers.collect {|customer| customer.surname}
end


Czyż to nie ładniejsze i przyjemniejsze w pisaniu i czytaniu? :)

środa, 10 grudnia 2008

IntelliTrac 0.1 beta

Opublikowałem IntelliTrac w umownej wersji 0.1 beta. Jeśli ktokolwiek ma 10 min wolnego czasu i IntelliJ IDEA 7/8, jest proszony o krótką zabawę z pluginem:


Wszelkie bugi/uwagi można zgłaszać na ww. stronie w zakładce "issues" (trzeba mieć konto Google).


niedziela, 14 września 2008

Operacje arytmetyczne w Javie

Mała zagadka, która przyszła mi na myśl przy rozwiązywaniu egzaminu na javablackbelt.com:

Co się stanie, jeśli spróbujemy uruchomić następujący program, i dlaczego?

class Test {

public static void main(String[] args) {
byte x = 0;
byte y = 1;
byte z = x + y;
System.out.println(z);
}

}

wtorek, 9 września 2008

GP Bahrajnu

Stało się. Grand Prix Bahrajnu dobiegło końca. Po pewnych problemach przy starcie (pole position), udało mi się szybko objąć prowadzenie i dowieźć je do mety.
W pewnym momencie przewaga nad Felipe Massą wynosiła 40 sekund. Jednak po pierwszej wizycie w alei serwisowej zaczęła topnieć. Miękkie opony nie spisywały się najlepiej przy moim brawurowym sposobie jazdy, dzięki czemu Massa pod koniec odrabiał po kilka sekund na okrążenie. Ostatecznie nie udało mu się jednak nadrobić całej straty.
Trzeci Lewis Hamilton, za nim nieoczekiwanie Jenson Button i Mark Webber.


niedziela, 24 sierpnia 2008

Wakacje z Szatanem

Pewnie było to już na jakimś JoeMonster, ale tak mnie to wgięło, że stwierdziłem, że warto odświeżyć sprawę ;)
Podczas wakacji byłem m.in. na Helu. Bardzo mnie zainteresował oficjalny rozkład jazdy PKS w miejscowości Kuźnica:


Autobus linii 666, który kursuje do miejscowości Hel(l). Cóż za zbieg okoliczności ;) Mają fantazję panowie z PKS Wejherowo ;)

środa, 6 sierpnia 2008

Nie powinieneś mieć szefa

Ostatnio natknąłem się na bardzo interesujący artykuł o różnicach między pracą w małych firmach a pracą w korporacjach: http://mojstartup.pl/index.php/2008/03/27/nie-powinienes-miec-szefa/

Polecam pełną lekturę: http://www.paulgraham.com/boss.html

niedziela, 3 sierpnia 2008

Niejawne założenia

Błędy (bugi) są bardzo ciekawym zjawiskiem w programowaniu. Jakże często zdarza nam się mówić "to źle działa", "tu jest na pewno jakiś błąd" itp. Rodzi się pytanie, jak w deterministycznym środowisku może zaistnieć błąd? Programista pisze kod, a następnie komputer przetwarza go na kod maszynowy i wykonuje w kółko kilka operacji na liczbach binarnych. Gdzie jest tu miejsce na błąd? Mniej więcej od połowy lat 90., kiedy pewna seria procesorów Pentium miała faktyczną usterkę techniczną, komputery w zasadzie "nie mylą się". Skąd zatem błędy? Bugi?
Otóż, wg mnie, występują następujące zasadnicze źródła "błędów" (zachowań systemu niezgodnych z przeznaczeniem; pomijam błędy składniowe):
  • niejasne lub sprzeczne wymagania

  • niedbałość, ograniczenia techniczne

  • niejawne założenia

O ile o pierwszych dwóch przyczynach napisano bardzo wiele i wszyscy zdają sobie z nich świetnie sprawę, o tyle niejawne założenia uważam za zaniedbane, dlatego chciałbym zanalizować ich szkodliwość.

Ileż razy zdarzyło się Wam siedzieć nad debuggerem kilka godzin zanim zorientowaliście się, że analizowana usterka wynika z tego, że inny programista założył coś o jakimś fragmencie kodu? Np. "A no tak, bo ta metoda spodziewa się czegoś tam..."? NullPointerException to chyba najczęściej lecący wyjątek w Javie, a z czego on wynika? Oczywiście z założenia, że w tym miejscu na pewno nie pojawi się wartość null. Trudno w takich przypadkach mówić o czyjejkolwiek winie bezpośrednio.

Problemy z niejawnymi założeniami występują wszędzie tam, gdzie

  • nie ma żadnej dokumentacji (albo jest marna)
  • brak komunikacji w zespole
  • brak głębokiego zrozumienia działania systemu
  • architektura systemu jest nadmiernie skomplikowana i niezrozumiała
Dobry kod to taki, który nie tylko "działa", ale też ma czysty prosty i przejrzysty design oraz jest dobrze przetestowany (wszyscy to wiedzą). Zazwyczaj w parze z tymi cechami idzie jawność założeń. Przeglądając dobry kod i dokumentację, zyskujemy jasność co do założeń: na czym ta klasa operuje (a na czym nie), jakich argumentów ta metoda się spodziewa (a jakich nie) itd. Postulat jawności założeń prowadzi nas wprost w ramiona Design By Contract, metodologii, w której zależności pomiędzy klasami formułuje się na zasadzie kontraktu między dostawcą usługi a klientem (analogicznie do prawdziwych kontraktów biznesowych).
Jaki płynie wniosek z tych rozważań? Według mnie, powinniśmy pójść w stronę pełnej jawności założeń. Wszystkie publiczne metody, nagłówki klas, powinny jasno i dobitnie stwierdzać: co przyjmują jako parametr, a co nie (np. czy może być null), co zwracają itd. Idea ta wywodzi się ze wspomnianego Design by Contract - jasno określić kontrakty klas (zasady, na jakich działają), żeby potem nie było "niejasności" (jak w życiu). Jestem także za tworzeniem "zewnętrznej" dokumentacji (poza kodem) - oczywiście nie jakichś opasłych tomów, ale kilka zwięzłych diagramów, rzeczowy opis działania jakiegoś mechanizmu z pełną specyfikacją założeń - wtedy nie będziemy musieli narażać się na wielogodzinne "odkrywanie" nieujawnionych domniemań.

wtorek, 22 lipca 2008

IntelliJ IDEA + Trac = IntelliTrac

Witam,

niedawno zacząłem prace nad moim pierwszym pluginem do IntelliJ IDEA. Będzie to plugin udostępniający integrację z Trakiem (http://trac.edgewall.org/). Zapraszam na stronę hostującą projekt na Google Code - http://code.google.com/p/intellitrac/ (wszelkie uwagi, sugestie, pomoc - mile widziane).

środa, 11 czerwca 2008

MessageFormat - c.d.

MessageFormat to np. świetne narzędzie do formatowania różnych walut:

Object[] arg = new Object[] {1.32};
String pattern = "{0,number,currency}";
Locale us = new Locale("us", "US");
Locale pl = new Locale("pl", "PL");
Locale de = new Locale("de", "DE");

MessageFormat format = new MessageFormat(pattern, pl);
System.out.println(MessageFormat.format("PL: {0}", format.format(arg)));

format = new MessageFormat(pattern, us);
System.out.println(MessageFormat.format("US: {0}", format.format(arg)));

format = new MessageFormat(pattern, de);
System.out.println(MessageFormat.format("DE: {0}", format.format(arg)));


W wyniku dostajemy:


PL: 1,32 zł
US: USD 1.32
DE: 1,32 €


Jest wiele innych zastosowań tej klasy, po dokumentację zapraszam tutaj: http://java.sun.com/j2se/1.4.2/docs/api/java/text/MessageFormat.html
.

sobota, 7 czerwca 2008

MessageFormat

OK, za inspiracją Radka Holewy, postaram się choć trochę rozruszać mojego bloga ;)

Wezmę na warsztat bardzo ciekawą klasę MessageFormat w Javie. Pisząc kod pod IntelliJ IDEA, w momencie kiedy używamy konkatenacji Stringów, np.


"Masz na imię: " + imie + ", na nazwisko: " + nazwisko + ", masz " + wiek + " lat. "


środowisko podpowiada nam, żeby użyć StringBuildera lub MessageFormat. Decydując się na StringBuildera, otrzymujemy coś takiego:


new StringBuilder().append("Masz na imię: ").append(imie).append(", na nazwisko: ").append(nazwisko).append(", masz ").append(wiek).append(" lat. ").toString()


Umówmy się, że nie jest to najmilsze dla oka rozwiązanie ;) Zupełnie inaczej sprawa ma się z MessageFormat. Korzystając z opcji "replace (...) with java.text.MessageFormat call", otrzymujemy:


MessageFormat.format("Masz na imię: {0}, na nazwisko: {1}, masz {2} lat. ", imie, nazwisko, wiek);


Wow! Wygląda to znacznie bardziej seksownie. W pierwszym Stringu mamy treść tekstu z ponumerowanymi zmiennymi, pozostałe argumenty to użyte w Stringu zmienne. Przykład ten pokazuje, jak wiele ciekawostek można poznać, korzystając z naprawdę dobrego środowiska programistycznego ;)


"OK, wygląda to ładnie, ale co z wydajnością?" - zapyta dociekliwy Czytelnik. Stringi są niemutowalne (immutable), wobec czego wyrażenie typu string1 + string2 jest wysoce nieefektywne (tworzony jest po prostu nowy obiekt z połączenia dwóch pierwszych). Do operacji łączenia Stringów powinno się używać zatem StringBuilder lub StringBuffer. Tak też jest w przypadku MessageFormat - używa StringBuffer do budowania ciągu wyjściowego.

Reasumując, używanie MessageFormat jest nie tylko ładniejsze, ale też bardziej efektywne. Mały benchmark oraz szerszy pokaz możliwości MessageFormat postaram się opisać w następnym poście ;)