Some of posts from this blog has been moved to dywicki.pl. You will be automatically redirected to new blog if you would submit comment.
New posts are published on dywicki.pl, this blog contains old content and it is not continued.

Niektóre posty z tego bloga zostały przeniesione do dywicki.pl. Zostaniesz automatycznie przekierowany jeśli bedzięsz chciał dodać komentarz.
Nowe posty sa publikowane na dywicki.pl, ten blog zawiera stare treści i nie jest kontynuowany.

Form Layout

Filed under Eclipse,Java,JFace,SWT by

Jakiś czas temu Michał Mech pisał o tym jak można rozkładać komponenty w Swingu przy pomocy Group Layoutu. Dzisiejszego dnia mam zamiar pokazać Wam drugą stronę medalu – mianowicie Form Layout, który można wykorzystać przy tworzeniu aplikacji w SWT.
Continue Reading »

4 responses so far

Praca, rutyna i walka z zawodową codziennością

Filed under Ogólne by

Chciałbym dzisiaj poruszyć dość ważną kwestię, jaką bez wątpienia jest rutyna i frajda z pracy. Motorem dla mnie była głównie rozmowa, którą odbyłem dzisiaj z kolegami, gdy siedząc przy piwie dyskutowaliśmy na temat alternatyw i sposobów wzbudzania w sobie entuzjazmu.
Może na początku kilka definicji zaciągniętych ze słownik języka polskiego wydawnictwa PWN.
Continue Reading »

7 responses so far

Testy jednostkowe

Filed under Ogólne,Testy jednostkowe by

Praktyka

W tym miejscu bazuję na swoim bądź co bądź skromnym doświadczeniu, które nabyłem pracując w AGI. Była to pierwsza firma, w której spotkałem się z wykorzystaniem testów jednostkowych. Pamiętam do dzisiaj walki o 70% pokrycie kodu testami. :).
Nie mniej, nie robiliśmy tego tylko po to by zobaczyć zielone słupki w raporcie wygenerowanym przez PHP Unit. Takie pokrycie kodu testami gwarantuje znaczne ograniczenie błędów wychodzących z czasem, głównie dlatego, że znajduje się już podczas pisania testów.
Continue Reading »

23 responses so far

Pragmatyzm kontrolowany

Filed under Ogólne,Wiadomości by

Jakiś czas temu postanowiłem zmienić myśl przewodnią bloga. Zapewne nikt nie zauważył tego, że zniknął tekst “żubr powstaje z jęczmienia” na rzecz “Pragmatyzmu kontrolowanego”. Czym było to podyktowane? Ano tym by tą gromadę różnych not, nie zawsze łączących się ze sobą tematycznie, podeprzeć myślą, jaką jest poszerzanie horyzontów i dzielenie się zdobytymi z biegiem czasu doświadczeniami.
Continue Reading »

3 responses so far

O abstrakcji klas i interfejsów

Filed under Java,Ogólne,PHP by

Od jakiegoś czasu na forum.php.pl spotykam się z różnymi zdaniami na temat interfejsów i klas abstrakcyjnych. Argumenty, które czasami się trafiają są chybione.

Zacznijmy od tego, że trzeba potrafić rozróżnić interfejs od klasy abstrakcyjnej, to nie to samo!
Interfejs jest najwyższym poziomem abstrakcji, który definiuje nowy, wolny od implementacji typ. Bez jakiejkolwiek linii kodu, tylko sygnatury metod publicznych.
Klasa abstrakcyjna jest już początkiem konkretnej implementacji, zawiera kod ogólny i wymusza w klasach dziedziczących dorzucenie konkretnych metod, które są specyficzne, inne, różne. Mogą trafić się takie przypadki, że klasa abstrakcyjna zawiera 5 metod, a jej pochodne tylko jedną. Czy jest to uzasadnione? Oczywiście. Ta jedna metoda determinuje nowy typ, który jest jawną specjalizacją.
Continue Reading »

8 responses so far

Obiekty biznesowe w aplikacji.

Filed under MVC,PHP by

Pierwsze błędy

Pamiętam swoje pierwsze implementacje MVC, w czasach gdy słowo framework nie było jeszcze trendy a wiele osób, w tym i ja, nawet go nie używało. W owych pierwszych implementacjach MVC model był pewnego rodzaju fasadą, która zapewniała dostęp do danych.
Problem polegał na tym, że kod np klasy User wyglądał następująco:
Continue Reading »

20 responses so far

Agavi 0.11 RC3, flow

Filed under Agavi,Framework,PHP by

Mam niebywałą przyjemność oznajmić, że dnia 23 lutego zostało wydane, jak sam tytuł posta wskazuje, Agavi 0.11 RC3. Do pierwszej, w pełni stabilnej wersji jest już coraz bliżej.
Zgodnie z rozkładem jazdy został otwarty jeden ticket, którego realizacja została odsunięta na sam koniec. Mianowicie, opis migracji z wersji 0.10 do 0.11. Ogrom zmian, które przetaczały się przez trunk repozytorium mógł przyprawić o zawrót głowy. Zmiany z rewizji na rewizję potrafiły w jednym momencie zniszczyć skrzętnie budowane narzędzia, które opierały się na zmieniających się wciąż mechanizmach.
Co zyskało Agavi o wersji 0.10? Przede wszystkim developerzy uwolnili projekt od niezręcznej i nieporęcznej konfiguracji w plikach INI, która poza łatwością odczytu nastręczała przede wszystkim problemów… a to brak hierarchiczności, brak możliwości łączenia konfiguracji, w końcu brak narzędzia do walidacji zapisanych danych. W poście “Dlaczego konfiguracja w XML” porównywałem XML również do YAMLa.
Sporą zmianą, naturalnie, na lepsze było zrezygnowanie z tradycyjnego flowu Mojavi 3. Do tej pory wyglądało to w ten sposób, że każda akcja miała metodę getRequestMethods, która zwracała informacje o tym w jaki sposób dostępna jest akcja. Czy to GET, POST, bądź cokolwiek (odpowiednie stałę w klasie Request – GET, POST, NONE). Teraz o sposób dostępu do akcji determinuje nazw akcji. Akcja o nazwie executeRead będzie wykonana w chwili żądania typu GET. Metoda o nazwie executeWrite będzie wykonana w chwili gdy otrzymamy formularz via POST. Metoda execute będzie wykonywana zawsze (o ile walidacja przebiegnie bez zakłuceń). Zysk z tego jest taki, że implementacja różnych kontrolerów nie wpływa na kształt akcji. W chwili gdy wiązały się z tym stałe GET/POST implementacja wywołań z poziomu konsoli była ciężka. W zapowiedziach pojawia się ConsoleRequest, ponieważ z Agavi 0.11 wyleciały kontrolery zależne od kontekstu. Jest jeden Controller, różne są implementacje requestu vide ConsoleRequest (jeszcze niegotowy, będzie w 1.0), WebRequest oraz SecureWebRequest.
W międzyczasie pożegnaliśmy również stałe View::SUCCESS, ERROR, INPUT, ALERT, a metoda getDefaultViewName każdej akcji zwraca po prostu suffix do nazwy widoku (np. metoda akcji “Cart” zwraca wartość “Product”, stąd klasa widoku to CartProductView).
Co więcej w połączeniu z innym mechanizmem Agavi, Output types, zmiany formatu widoku oraz języka nie wiążą się z implementacją bądź powielaniem logiki biznesowej. Implementujemy tylko logikę związaną z widokiem.
Warto również wspomnieć, że od tej chwili metoda Controller::forward(module, action) jak i samo używanie powiązanych akcji jest odradzane, jako źródło potencjalnych problemów (dlaczego widok nie jest uruchamiany) tym bardziej, że tworzenie widoków i akcji załatwia samo Agavi przez taski dla Phinga. W chwili, gdy chcemy użyć innego widoku, spoza tych, które dostarcza sama akca po prostu zwracamy array(module, view name, parameters). Zniknęła również możliwości zrobienia forwarda z widoku (ogólnie problemy z request methods, to co było post-only nie szło przy fowardzie przy żądaniu otrzymanym via get), co wydaje się jak najbardziej uzasadnione.
Widok nie jest organem decyzyjnym, który powinien wskazywać na wykonanie logiki biznesowej. Nie mniej jest możliwość przekierowania do widoku innej akcji.. poprzez redirect bądź poprzez zwrócenie array(module, view name, parameters).

To co jest bolesne w execution flow oferowanym w Agavi to niestety jego prostota. Przede wszystkim brakuje mi (jak w wielu miejscach Agavi) interfejsów. Jest to dla mnie naturalne, że dążę do generalizacji, interfejs jest podstawowym elementem, który uniezależnia od implementacji. Interesuje nas to, co jest widoczne na zewnątrz a nie to co wewnątrz implementacji. Brakuje mi opakowań dla tych tablic, które informacje o widoku. Prosty kontener, bean, który zawiera tylko informacje, ale nie jest tablicą. Przede wszystkim mam możliwość kontroli danych, które otrzymuje. Mogę już w fazie tworzenia obiektu reprezentującego flow wstępnie przeprowadzić jego walidację (czy widok istnieje?).
Zmiany w akcjach i widokach jest jak najbardziej pozytywna i rzeczywiście usprawnia działanie całości. Nie mniej do wersji 2.0 w Agavi na pewno zajdzie ich jeszcze sporo, miejmy nadzieję, że również w celu uporządkowania struktur, usunięcia nadmiaru klas abstrakcyjnych i zastąpienia ich interfejsami (pamiętaj, zanim napiszesz linijkę w klasie, która jest autonomiczna, a której implementacja może się zmieniać, generalizuj, twórz typ bazowy).

Pytaniem ciągle jest czy Agavi podąży w stronę Symfony? Jak najmniej pisania.. Twórcy Symfony ochrzcili wersję 1.0 swojego frameworka nazwą, czy też przydomkiem “enterprise”. Ciężko mi powiedzieć czy było to uzasadnione. Temat Symfony-Agavi często pojawia się w rozmowach między Michałem Mechem a mną. Obaj jesteśmy zgodni w dwóch kwestiach – w Symfony pisze się bardzo szybko oraz ma ono bardzo dobrą dokumentację. Nie ustępuje ona pod żadnym względem dokumentacji Zend Frameworka.

Myślę, że najlepszym życzeniem dla nas wszystkich będzie to: by developerzy Agavi nadążyli z dokumentacją za implementacją.

5 responses so far

Agavi, Output types

Filed under Agavi,Framework,MVC,PHP by

Jedną z nowości jaką niesie Agavi w wersji > 0.10 jest mechanizm output types. Jest to bardzo proste rozwiązanie, które umożliwia uniknięcie gimnastyki z tworzeniem widoków w różnych technologiach, z którymi wiąże się różna logika. Banalny przykład. Te same dane prezentujemy w postaci HTML jak i PDF a do tego możemy je pobierać przez XmlHttpRequest. Dane są praktycznie identyczne, różny jest format wynikowy i proces jego tworzenia. Dla zwykłej strony wskazujemy szablon, dorzucamy dane i koniec, dla XmlHttp zwracamy JSONa. Stworzenie outputu w formacie PDF nie będzie tak proste jak pozostałych, ponieważ konieczne będzie stworzenie układu strony, dorzucenie fontów etc. Ogólnie w żaden sposób nie da się połączyć tych formatów w jednym widoku bez sporej ilości warunków i “protez”. By uniknąć zakopania się w tym wszystkim zwykle tworzy się dodatkową akcję, która w sporej części pokrywała się z pierwotną a różni się tylko widokiem i szablonami. Począwszy od Agavi 0.11 problem przestaje istnieć.

W pliku konfiguracyjnym output_types.xml określamy renderer dla danej technologii, dodajemy obiekty przedefiniowane (parameters name=”assigns”) i następnie konfigurujemy mapowania adresów do plików (swoją drogą najlepsza implementacja tego mechanizmu z jaką się do tej pory spotkałem). Jest odpowiedni plik zawierający definicję routingu.

Zajmijmy się jednak w pierwszej kolejności konfiguracją output types:

< ?xml version="1.0" encoding="UTF-8"?>
<output_type name="html">
  <renderer class="AgaviPhpRenderer" extension="tpl.php">
    <parameters>
      <parameter name="assigns">
        <parameters>
          <parameter name="routing">r</parameter>
          <parameter name="request">req</parameter>
          <parameter name="controller">ctl</parameter>
          <parameter name="user">usr
          </parameter>
          <parameter name="translation_manager">tm</parameter>
        </parameters>
      </parameter>
      <parameter name="i18n">
        <parameters>
          <parameter name="mode">subdir</parameter>
        </parameters>
      </parameter>
    </parameters>
  </renderer>
  <parameters>
    <parameter name="Content-Type">
    text/html; charset=UTF-8
    </parameter>
  </parameters>
</output_type>

<output_type name="json">
  <renderer class="AgaviPhpRenderer" extension="js.php"
    ignore_slots="true" ignore_decorators="true">
    <parameters>
      <parameter name="Content-Type">
        text/javascript; charset=UTF-8
      </parameter>
    </parameters>
  </renderer>
</output_type>

Jak widać trochę tej konfiguracji jest, nie mniej celowo usunąłem przekazywanie parametrów do drugiego formatu wynikowego by pokazać, że w najskromniejszej wersji definicja taka potrafi się zmieścić maksymalnie w 10 linijkach.
Do wszystkich parametrów możemy odwoływać się w widoku. Specyficzne są parametry o nazwie assigns oraz i18n. Pierwszy z nich Agavi wykorzysta po to by od razu w fazie tworzenia renderera wrzucić do niego wskazane obiekty, które znajdują się w kontekście. Drugi z atrybutów jest szczególnie przydatny podczas tworzenia aplikacji z wieloma językami. Parametr i18n jest prefiksem dla nazwy pliku. W przypadku gdy przypiszemy mu wartość subdir framework będzie szukał szablonów po katalogach np. pl/IndexSuccess, en/IndexSuccess. Inne, dopuszczalne wartości to postfix oraz prefix. Nazwy szablonów to odpowiednio IndexSuccess_pl oraz pl_IndexSuccess
Atrybut extension określa suffix dla nazwy pliku, którego użyje Agavi przy wczytywaniu szablonu np IndexSuccess.tpl.php.
Argumenty ignore_slots oraz ignore_decorators odnoszą się do strategii budowania widoku. W chwili gdy zrezygnujemy z nich wynik nie będzie dekorowany. Tzn. w odpowiedzi użytkownik zobaczy tylko treść wygenerowaną przez widok akcji.
Tutaj drobna uwaga. W wersji stabilnej Agavi 0.11 mechanizm ten zachowuje się nieco inaczej. Wybór plików oraz zachowanie dekoratora determinuje layout i elementy layer.

Następnie w routes.xml dla każdej ścieżki możemy określić również format wynikowy danych. Np:

<route pattern="/ajax$" output_type="json" stop="false" />

W tym momencie, wszystkie adresy kończące się na /ajax będą obsługiwane w nieco inny sposób niż pozostałe. To znaczy, że nie będzie dekorowany output. Dodatkowo zostaną użyte inne pliki szablonów do generowania treści.

Zdaję sobie sprawę z tego, że opisałem ten mechanizm dość chaotycznie i bardziej skupiłem się na jego konfiguracji, ale na przykładową aplikację będziecie musieli poczekać do czasu gdy skończę artykuł dla PHP Solutions (czyżby Agavi tematem numeru?) bądź do pojawienia się nowego Code-House. :)

2 responses so far

Propel 1.2 a istniejąca baza danych

Filed under PHP by

Wiele razy spotykałem się z negatywnymi opiniami na temat Propela. Przyznaję, nie jest to narzędzie doskonałe, ale bez wątpienia, w tej chwili jest to wiodący ORM dla PHP.

Jedną z wad Propela, która pojawia się chyba najczęściej jest XML i definiowanie tabel w pliku XML. Otóż drodzy moi, nie jest to konieczność. Schemat z istniejącej bazy danych można bez problemu przenieść do XMLa a następnie bez najmniejszego problemu wygenerować z niego klasy. Możemy zrobić to dwoma poleceniami. Pierwsze jest dostępne po instalacji przy pomocy PEARa, drugie przy korzystaniu z Phinga:

// propel-gen project target
propel-gen sheep creole
propel-gen sheep om
// bądź phing -Dproject=project -Dtarget=target
phing -Dproject=sheep -Dtarget=creole
phing -Dproject=sheep -Dtarget=om

Naszym oczom ukaże się kilka informacji o przebiegu całego procesu, po czym będziemy mogli korzystać z wygenerowanych klas. :)

Propel 1.3
Propel 1.3 korzysta z PDO dlatego też, task “creole” niestety nie działa. Jeśli ktoś chce korzystać z możliwości generowania schematu musi niestety korzystać na przemian z wersji 1.2 i 1.3 (1.2 generuje schemat, 1.3 generuje klasy).

Migrowanie pomiędzy bazami danych
Propel umożliwia zrzucenie struktury bazy danych do pliku zawierającego definicje tabel. Aby to zrobić wystarczy skorzystać z taska sql. Warto pamiętać, że schemat SQL jest budowany na podstawie pliku XML. Zmieniając jedną dyrektywę w konfiguracji generatora (propel.database.url) można bez problemu przenieść całą bazę

Przenoszenie danych
Istnieje również możliwość przeniesienia danych z istniejącej bazy, służy do tego task datadump. Propel zrzuca zawartość wszystkich tabeli do plików XML po to by móc następnie wygenerować z niego zapytania insert. Aby to zrobić wystarczą dwa polecenia:

propel-gen sheep datadump
propel-gen sheep datasql

Propel a ociężałość
Trudno się nie zgodzić, że używanie narzędzi typu ORM powoduje wydłużenie czasu wykonywania skryptu, ale jak by nie patrzeć, znacznie też skraca czas potrzebny na tworzenie kodu odpowiedzialnego za warstwę DAO, co zwykle tuż po tworzeniu widoku zajmuje najwięcej czasu.
Myślę, że warto tu wspomnieć o Propelu 2.0, który ma obsługiwać dostęp do pól przez metody __get i __set dzięki czemu całość może stać się lżejsza a ilość kodu, który jest generowanego ulegnie widocznemu zmniejszeniu.

3 responses so far

Singleton

Filed under Java,Ogólne,PHP by

Singleton jest chyba pierwszym z “wzorców projektowych” jaki wszyscy poznaliśmy. Prosty w implementacji, jeszcze łatwiejszy w użyciu, ale pociągający za sobą stos negatywnych konsekwencji.

W poszukiwaniu informacji i zdań o singletonie w polskim internecie trafiłem na Wikipedię, gdzie znalazłem zdanie, które podsumowało to czym jest tenże “wzorzec”:

Singleton jest też uznawany za antywzorzec, gdyż często jest tylko eufemizmem dla zmiennej globalnej.

W książce “Refaktoryzacja do wzorców projektowych” padają kolejne dwa ważne zdania:

Singleton to przede wszystkim wykorzystanie mechanizmów chroniących języka programowania do ochrony tylko jednego aspektu: jednostkowości.
Prawdziwym problemem z singletonami polega na tym, że są doskonałą wymówką, aby lekko potraktować kwestię widoczności obiektów.

Główną przesłanką do stosowania singletonu jest to by mieć tylko jedną instancję danej klasy, ale czy nie da się załatwić tego w inny sposób? Oczywiście, że da się. Problemem jest tylko to by poświęcić więcej czasu na projekt, po prostu pomyśleć. W chwili gdy mamy połączenie z bazą danych i tak jest ono tworzona w jakimś miejscu, zwykle jest to jakiś kontroler bądź inny przyczółek w którym koncentruje się “władza”. Jest to miejsce w którym i tak musimy daną instancję skonfigurować. Co to znaczy? Ano to, że cały ten singleton i tak nie jest autonomiczny, ponieważ jest zależny od czynników zewnętrznych. Idąc dalej – czy nie lepiej by było pchnąć stworzony już obiekt do tych miejsc gdzie będzie potrzebny?
Oczywiście, ktoś powie, że wydłużą się definicje metod i tak dalej. Fakt, to może być problem, ponieważ metody, które przyjmują powyżej 4 argumentów stają się “ciężkie”. Ciężkie również pod względem zapamiętania ich wywoływania. Nie można tu również zapominać o tym, że nie musi być przymusu przekazywania za każdym razem danej instancji. Mamy do dyspozycji konstruktory jak również kompozycję, ogólnie pojętą fazę “konfiguracji”. Zaletą unikania singletonów jest bardzo duży plus – obiekt nie jest widoczny tam gdzie nie powinien. Jest to znacznie lepsze podejście tym bardziej, że globalnie dostępny obiekt lubi kusić, kusić łatwością dostępu. Zawsze gdy myślisz o tym by użyć singletonu myśl o nim jak o zmiennej globalnej, bo tym w gruncie rzeczy się wkrótce stanie, elementem, który będzie powodował, że kod stanie się nieczytelny a kontrola dostępu do instancji wbrew pozorom, zamiast trudniejsza, jeszcze łatwiejsza.

Wydajność

Za singletonem może przemawiać to, że powoduje on wzrost wydajności poprzez oszczędność pamięci (mniej stworzonych obiektów, mniej zużytej pamięci). Niestety często pomijanym faktem jest to, że zysk z takiego singletonu i tak jest niezauważalny, a w samym PHP wywołania statyczne są znacznie wolniejsze od tradycyjnych “dynamicznych” metod.

Singleton a testy jednostkowe

Singleton znacznie utrudnia testowanie kodu, ponieważ uniemożliwia on pełne rozbicie komponentów. Elastyczniejsze okazuje się użycie metod, które pozwalają “wstrzyknąć” określony obiekt, który jest w danej chwili potrzebny. Elementy, które są przykryte singletonem są niewymienne, muszą być stałe. W chwili gdy singleton tworzy sam instancję klasy pochodnej zaczynamy mieć do czynienia w gruncie rzeczy z abstract factory (fabryką abstrakcyjną) bądź factory method (metodą fabryczną) co w efekcie można nazwać bardzo prosto – przerostem formy nad treścią.
Raz stworzony i zaszyty wewnątrz singletonu obiekt jest świętą krową, nie da się go zastąpić mimo, że na potrzeby testów potrzebny jest leciutki obiekt, który tylko dostarczy odpowiednie dane bądź zachowa informacje o wywołaniach (stub, mock object). Co gorsza, w chwili gdy mamy do czynienia z typowym “kontekstem”, który tworzy w prywatnym konstruktorze kolejne usługi nie mamy możliwości ich podmiany na czas testów. Osobiście spotkałem się z sytuacją, w której testy kończyły się niepowodzeniem, ponieważ w konstruktorze kontekstu było tworzone okno aplikacji.

Połączenie singleton+singleton a Java

Warto zapamiętać, że odwołania pomiędzy singletonami w Javie nie mogą występować w fazie inicjowania obiektów. To znaczy że kod, w którym konstruktor singletonu A wymaga singletonu B, a ten z kolei singletonu A to dostaniemy odpowiedni wyjątek. Przykładowo: kontekst tworzy nowe połączenie, które pobiera instancję jeszcze niestworzonego kontekstu by dobrać się do konfiguracji.

Wnioski

Zanim zdecydujesz się na użycie singletonu przeczytaj trzy cytowane zdania i zastanów się czy rzeczywiście nie ma alternatywy? Nie ma sytuacji w której singleton jest niezbędny, zawsze można znaleźć coś lepszego niż zmienna globalna do przekazywania instancji. Pamiętaj singleton jest wypaczeniem idei programowania obiektowego na potrzeby leniwych programistów.

17 responses so far

« Newer Entries - Older Entries »