Druga już konferencja
33rd Degree w Krakowie rozpoczęła się 19 marca 2012
Plan trzech dni wyglądał następująco ( wyróżnione opcjonalne sesje, w których uczestniczyłem):
19 March, Monday
20 March, Tuesday
21 March, Wednesday
Na konferencji pojawiło się wiele znakomitości, takich jak Uncle Bob, czy Venkat Subramaniam.
Czasem trudno było wybrać ścieżkę spośród tak wielu interesujących pokrywających się wykładów. Poniżej przedstawiam sprawozdanie z wykładów, w kórych miałem okazję uczestniczyć.
Raffi pracuje jako Platform Services Director w Twitter. Opowiedział o migracji z Ruby na JVM w Twitterze. Dlaczego była potrzebna, jakie były ograniczenia istniejącej platformy i co nowego zyskała w połączeniu z Java?
Twitter codziennie odbiera od 100 miliona użytkowników ok. 250 milionów tweetów.
Każdy tweet jest duplikowany do followerów co daje średnio 2.5 E9 doręczeń na dobe.
Ruby on Rails charakteryzuje sie tym, że używa interpreterów opartych na jęz. C, jest jęz. dynamicznym, nie jest tak szybki jak jęz. kompilowane (np Java). Zaletą jego jest to, że jest ekspresywny, pisze się w nim łatwo i przyjemnie.
80% serwisów Twittera jest napisanych w Ruby, komunikują się one na końcu z Javą. Do komunikacji uzywany jest szybki protokół
SPDY (czyt. Speedy).
Jednym ze sposobów usprawnienia Ruby było napisanie szybszego garbage collector'a -
Kiji.
Chociaż obecnie istnieje implementacja Ruby na platformie JVM (JRuby) to w roku 2008, kiedy w Twiterze zaczęto migrować Ruby na platformę JVM, JRuby było jeszcze zbyt mało rozwinięte, dlatego zdecydowano sie na własne rozwiązania.
Java nie jest jęz. zbyt ekspresywnym, więc na celowniku znalazła sie Scala. Jest szybka, statycznie typowana, jest ekspresyjnym jęz. funkcyjnym, ma wsparcie dla współbieżności (w przeciwieństwie do Ruby 1.8).
Zalety JVM:
- zdolność radzenia sobie z obciążeniem serwera
- elastyczność językowa, dobre wsparcie dla innych języków
- prawdziwy model wielowątkowy
Developerzy Tweetera opracowali
Finagle - asynchroniczny RPC (Remote Procedure Call), opracowali wlasny JVM, stuningowali JVM garbage collector ściśle zintegrowany z Finagle.
Konkluzja z prezentacji brzmi: przerzucenie się na JVM nie oznacza, że Ruby to pomyłka.
Przy projektowaniu systemów nie należy od razu tworzyc systemu, kóry poradzi sobie ze wszystkim, bedzie skalowalny, wydajny i szybki. Należy raczej projektować system tak, by łatwo było go zmienić, ale nie wprowadzać od początku nieuzasadnionego skomplikowania. Historia Twittera obrazuje, że gdy zachodzi potrzeba, wtedy należy przebudować system, tak jak gdy zintegrowano Ruby ze Scala.
Ken opowiedział o przyczynach skomplikowania. Rozróżnił skomplikowanie systemów na tzw. konieczne, wynikające z tego, że czegoś nie da sie juz zrobić prościej i przypadkowe, wynikające, czy to z niewiedzy, czy z niedbalstwa, czy z przesadnego dbania np. o skalowalność systemu już na samym początku jego istnienia, gdy jeszcze nie wystąpiły takie problemy.
Co oznacza, że coś jest nieskomplikowane? To znaczy, że coś jest:
- proste
- wygodne
- znajome
- przyjazne dla nowicjusza
To nie pojedyncze elementy systemu sa skomplikowane, tylko te same elementy współgrające z innymi elementami. Czynniki sprzyjające skomplikowaniu to:
- zespół: jego rozmiar, doświadczenie, często mówi sie tu o modelu
Dreyfusa, w którym wyróznia się następujące poziomy doświadczenia: nowicjusz, zaawansowany nowicjusz, kompetentny, profesjonalista, ekspert
- przesadna troska o wydajność, skalowalność zanim te problemy jeszcze wystąpiły
Tuningować powinniśmy system dopiero, gry wystąpią problemy z wydajnością a nie na zapas.
- użycie technologii przerasających potrzeby, jak gdyby użyć rakiety do wypadu na zakupy
- utknięcie w tzw. 'dobrych praktykach' z pominięciem zdrowego rozsądku i aplikowaniem tych dobrych praktyk wszędzie niezależnie od kontekstu. Dobrze zostało to opisane w książce
Hackers & Painters
Dobre praktyki sa dobre dla zaawansowanych nowicjuszy, ale odstraszają ekspertów.
- niejasne wymagania, prowadzą do przypadkowego skomplikowania systemu.
Venkat Subramaniam - Pointy haired bosses and pragmatic programmers: Facts and Fallacies of Software Development
Venkat był moim zdaniem najbardziej energetyzującym mówcą. Na jego prezentacji nie sposób było się nudzić. Imponowała prędkośc z jaką poruszał się po omawianych tematach, odpowiadał na pytania, żąglował narzędziami. Cały czas podtrzymywał zainteresowanie swoją ekspresją i żartobliwymi wstawkami. Tytułowy boss to ten drzemiący w nas samych. Kompetentni pasjonaci prowadzą firmę ku zwycięstwu. Problem w tym, aby takiego indywidualiste w sobie obudzić i utrzymać zamiast ulegania konformizmom.
Doświadczenia wskazują, że w grupie ludzie starają się być zgodni z ogółem, dostosowują do większości i za nią podążają. Rzadko kiedy trafia się indywidualista, kóry podąża swoją drogą. Jeśli już dostosowujemy się do większości, dlaczego nie wybrać tych najinteligentniejszych, najbystrzejszych.
Możnaby powiedzieć, że Venkat rozprawiał o rzeczach oczywistych, ale robił to w taki sposób, że niesposób było się nudzić. Przy okazji tez pojawiło się pare wzmianek literatury godnej uwagi:
Venkat mowił o tym, że systemy stają się skomplikowane, dlatego, że zmieniamy je nieustannie, nawet jeśli nie potrzeba - standaryzacja przed innowacją. Powinno być natomiast odwrotnie, najpierw robimy coś innowacyjnie, dopiero standaryzujemy takie rozwiązanie, czyli znajdujemy dla niego wiele zastosowań.
Wspomniał też, że "mniej znaczy więcej" - tak jest np. z nowymi językami programowania. Porównał je pod kątem dyanamiczności i mocnego typowania. Powstała macierz:
Niektóre z nich dają swobodę pisania, są bardziej ekspresyjne od innych. Są tylko narzędziami do osiągnięcia celu. W zależności od danej potrzeby użyjemy jednego bądź innego.
Nie bójmy się eksperymentować i podejmować nowych rozwiązań w myśl:
"A professional who doesn't learn to fail, fails to learn"
Frederic mówił o Continuous Delivery. Podkreślił jego zalety takie jak:
- zawsze ostatnia wersja na produkcji, nie trzeba wspierać wielu wersji, legacy kodu.
- szybki feedback użytkowników
- użytkownicy są najlepszymi beta testerami
Pokazał przy tym narzędzie od jfrog: Artifactory
Zapewnia ono śledzenie binarnych wersji komponentów i ich źródeł. Dzięki pluginowi dla Jenkinsa, Bamboo i TeamCity możliwa jest integracja Artifactory z narzędziami do Continuous Integration.
Pojawiło się tez pojęcie Agile Lifecycle Managment (ALM), opisane w książce Agile ALM autorstwa Michael'a Hüttermann'a.
Artifactory dobrze wpisuje sie w ten cykl życia.
Sylvain Lebresne - The Apache Cassandra storage engine
Sylvain pracuje w Datastax, gdzie zajmuje się Cassandrą.
Cassandra to baza danych:
- rozproszona, brak struktury master-slave
- replikowalna
- skalowalna
- odporna na błędy, brak jednego słabego punktu (SPOF - single point of failure)
Model danych:
- no SQL
- klucz-wartość
- zainspirowana przez Google BigTable
- oparta na rodzinach kolumn (rodzina kolumn jest analogiczna z tabelą w bazie SQL)
Kluczem jest UUID (universally unique identifier), analogicznie do numeryczych kluczy w SQL, natomiast w rozproszonych bazach trudno jest inkrementowac klucz, stąd takie rozwiązanie.
Każdy wiersz (rodzina kolumn) może mieć różną liczbę kolumn. Kolumny są posortowane na podstawie nazwy klucza. Limitem jest 2 miliardy kolumn w jednej rodzinie kolumn.
Mechanizm zapisu/odczytu danych:
Zapis jest trudniejszy do skalowania niż odczyt. Odczytywane dane mogą być cachowane.
Zapis powoduje losowe operacje wejścia/wyjścia na dysku, dlatego zapis jest wolny.
Zapis:
Przy zapisie wiersza najpierw trafia on do pamieci, tzw. Memtable, jednoczesnie na dysku zapisuje sie commit log, na wypadek gdyby nagle node bazy padł, wtedy przy restarcie z commit loga mozna odtworzyc ostatnio wykonywane operacje. Periodycznie dane z Memtable sa zapisywane na dysku jako SSTable. Zapis jest sekwencyjny. Casandra nie rozróżnia zapisu od updatu. Przy updacie jest zapisywany nowy wiersz z nowymi polami. Periodycznie robione jest tzw. kompaktowanie, które zbiera wszystkie wiersze z tym samym UUID i merguje w jeden wiersz. Kompaktowanie ma na celu zmniejszenie liczny SSSTable, w ten sposób search jest szybszy.
Kazdy wiesz ma swoj czas zycia. Jesli czas ten minął to przy kompaktowaniu wiersz taki jest usuwany z bazy.
Odczyt:
Przy odczycie nieskompaktowanych wierszy robiony jest merge i brane najaktualniejesze pola.
Optymalizacje Cassandry otrzymuje się przez:
- cache wierszy
- cache kluczy
- indexy na kolumnach i wierszach
Spójność danych reguluje się przez określenie przy zapisie ile nodów musi zwrócić acknowledge.
Cassandra nie ma wsparcia dla tranzakcji, ale można je dodać dodatkowym narzędziem takim jak Zookeeper.
Wojciech Seliga - "Every Rose Has Its Thorn": Taming automated tests beast.
Trzymanie wszystkich testów w jednym module i ich odpalanie przy każdym komicie nie jest dobrym rozwiązaniem i konsumującym dużo czasu.
Rozwiązania pozwalające skrócić czas testowania:
- setup testów z wykorzystaniem serwisów REST zmiast XMLi, np. użycie własnej annotacji @Category zamiast @Ignore pozwala pamiętać o testach pominiętych, dzięki czemu nie są one zapomniane zaśmiecając kod i powodując niepotrzebny nakład czasu przy kompilacji.
- testowanie tylko zależnych testów, np. jeśli wprowdzaliśmy zmiany w module A testowanym przez TA a TB i TC zaleza od A, to testujemy tylko te moduly a nie uruchamiamy wszystkie testy.
- pojedynczy setup dla kilku testów
- podzielenie codebase na mniejsze unity.
Panel dyskusyjny na temat Spring Cloud Foundry, planów co do jego przyszłości. Uczestnicy zastanawiali się czy SpringSource przyjmie politykę jak Google App Engine i będzie zmuszać użytkowników do periodycznych upgradów software'u do nowych wersji technologii, czy może bedzie też wspierać kilka wersji (MongoDB, Cassandra). Być może SpringSource powinien wystawić deweloperską chmure CloudFoundry na której będą do wyboru wszystkie technologie ze stosu Spring (aktualnienie nie wszystkie są wspierane w chmurze produkcyjnej). SpringSource w połowie roku 2012 zacznie pobierać za CloudFoundry opłaty.
Barry O'Reilly - Agile, Lean and Startups practice & principles to create the ultimate value creation machine
Barry podzielił sie swoim doświadczeniem i narzędziami związanymi z agile, lean i startup.
Jednym z takich narzędzi jest Business Model Canvas, diagram pozwalający na jednej stronie umieścić do kogo skierowany jest nasz business, jak zamierzamy z niego zarabiać, jakimi kanałami dostępu do odbiorców będziemy sie posługiwać itd. Formularz taki można też łatwo pokazać drugiej osobie (klientowi, inwestorowi?) i szybko wyjaśnić o co nam chodzi.
Następnie Barry wyjaśnił jak się tworzy biznes model a potem waliduje z grupą docelową.
Pierwszym etapem jest burza mózgow i ustalenie:
- kim są ludzie związani z businessem (żeby lepiej ich sobie zwizualizować rysujemy te osoby, jak wyglądają, czym się zajmują, gdzie mieszkają itd..)
- uliczne ankiety z potencjalnymi użytkownikami, jakie są ich oczekiwania, jak używaliby naszego systemu?
- ankiety online
Trudno jest stworzyć system który będzie kierowany do wszystkich, dlatego trzeba się ograniczyć do pewnej grupy odbiorców.
Kolejnym etapem jest walidacja produktu. Śledzimy statystyki z użyciem Google Analytics i analizowanie gdzie użytkownicy spędzają najwięcej czasu, gdzie spotykają utrudnienia, jak nawiguja po naszej stronie. Informacje te posłuża do usprawnienia systemu.
Przydatną technika jest Value Stream Mapping - rysujemy proces w formie sekwencyjnego diagramu i analizujemy punkty które zajmują najwięcej czasu, aby je wyeliminować/usprawnić. Patrzymy też na intersekcje z innymi systemami, jesli np. nasz serwis ma odsyłacze gdzieś na zewnątrz, przykład: używamy zewnetrznego serwisu do obsługi płatności online.
Im szybciej dostaniemy feedback tym lepiej.
James pracuje w ThoughtWorks. ThoughtWorks wydaje regularnie darmowy magazyn online - Technology Radar w którym podsumowuje zmiany trendów i technologii.
W ostatnim marcowym numerze pojawił się artykuł o Micro Services, który był przedmiotem tego wykładu.
Micro services są alternatywą dla tradycyjnych serwisów, sa to proste, samodzielne aplikacje instalowane poza kontenerem aplikacji. Każdy serwis posiada wbudowany lekki serwer, np Jetty i komunikuje sie z pozostałymi serwisami po HTTP na różnych portach.
Serwisy są odpowiedzią na skomplikowanie aplikacji i szybko zmieniające sie wymagania. Dekompozycja na małe moduły, które można szybko napisać od nowa zamiast zmieniać istrniejący, silnie zależny od siebie kod to interesujące podejście wpisujace sie dobrze w techniki Continuous Deployment.
Organizacja drużyny projektowej wokół niezależnych modułów (Conway's Law) pozwala też lepiej nimi zarządzać i szacować nakład pracy.
James podkreślił w jaki sposób czasami uproszczona architektura ukrywa w sobie skomlikowanie, np. zmiana architektury pear-to-pear w architekture z użyciem ESB (Enterprise Serial Bus) czyli szyny danych. W rzeczywistości diagram systemu jest prostszy ale skomplikowanie nadal istnieje, tym razem wewnątrz szyny.
W książce REST in Practice opisano jak efektywnie zaimplementować coś w REST, co zwykle byłoby robione z ESB.
Przydatny standard to
RFC 5023, czyli
The Atom Publishing Protocol.
Charakterystyka mikroserwisów:
- małe, wystarczajaco małe by można je było w każdej chwili wyrzucic i napisać od nowa
- samodzielne
- nie działaja w kontenerze, są instalowane jako serwisy unixowe/linuxowe, np zawierają wbudowany serwer Jetty - ma to zalety w testowaniu (inproctester) i ułatwia deployment
- spakowane jako pojedynczy wykonywalny jar zawierajacy konfigurację, standardowe skrypty unixowe rc.d
- umieszczone w różnych repozytoriach VCS (version control systems) dla zapewnienia separacji
- Domain Driven Design
- wykorzystanie
Puppet do przygotowania serwisów do użycia
95% kodu Java jest popsute dla współbieżności i nawet o tym nie wiemy. Programowanie współbieżne jest jak spacer z teściową - ona wie kiedy się wygłupiliśmy ale nie powie nam o tym, będzie się po cichu naśmiewać. Zamiast cierpieć przy wielowątkowości w Javie z całym nadmiarowym kodem dla synchronizacji Venkat pokazał jak wykorzystać biblitekę clojure.jar wprowadzając tranzakcje.
Tutaj przedstawiam ten wyekstraktowany przykład uruchamiany na JDK 7 jako projekt Maven.
W przykłądzie wykorzystany jest prosty model biznesowy wyciągu z konta bankowego wykonywanego jednocześnie przez 2 metody - 'deposit' i 'withdraw', każda otoczona tranzakcją. Następnie metoda 'transfer' otacza te 2 metody jeszcze jedną zewnętrzną tranzakcją. Zasada jest taka, że jeśli jakakolwiek z tych metod zwróci wyjątek, zewnętrzna tranzakcja nie powinna się powieść. Np:
z konta = $2000, przelewamy $5000 na inne konto, tranzakcja powinna być anulowana.
To były praktyczne warsztaty poprowadzone przez pracownika z ThoughtWorks z Hamburga. przy okazji - ThoughtWorks rekrutuje.
Java 7 wprowadza nowe API do wielowątkowości. W czasie tej sesji staraliśmy się porównać szybkość działania sekwencyjnego i współbieżnego dla prostego algorytmu sortowania.
Kody do testów dostarczone przez Wolfa wrzuciłem na githuba razem z prezentacją z warsztatu. Większość czasu zajęło nam napisanie algorytmu sortowania, tak że na zabawę API do współbieżności zostało już niewiele czasu.
Aktualnie istnieje ok. 2000 jęz. programowania na platformę JVM. Java integruje w pewien sposób je wszystkie.
Wśród punktów integracji języków można wyróżnić:
- bazę danych
- serwisy (przez JSON, XML)
- język, czyli w kodzie jednego języka używamy konstrukcji wywołujących kod z innego języka.
Podział jęz. ze względu na liczbe. DSL - doman-specific languages
Poniżej podaje przykładowe api użyte na prezentacji przy integracji języków. W wolnej chwili spróbuje umieścic jakieś przykłady użycia w kodzie.
Java code:
class JavaClass{
public void people(Collection people){
// do sth
}
public void yield(){
// do sth
}
}
Scala -> Java:
val inst = new JavaClass
val names = List("Jack", "Jill")
inst.people(names)
inst.'yield'() // escape keywords
Groovy -> Java
def inst = new JavaClass()
def names = ["Jack","Jill"]
inst.people(names) // Groovy uzywa kolekcji Java, bez problemu konwertuje
inst.def() // Groovy rozpoznaje kontekst wiec wie ze to nie slowo kluczowe
JRuby -> Java
require 'java'
java_import 'JavaClass'
inst = JavaClass.new
names = %w{Jack Jill}
inst.people(names) // JRuby konwertuje bez problemu bo uzywa kolekcji Java
Ken Sipe - MongoDB: Scaling Web Application
Na youtube jest dość śmieszny filmik przedstawiający dyskusje za i przeciw tradycyjnym bazom SQL vs. NO SQL.
MongoDB to baza dokumentowa, struktura dokumentów w postaci JSON, umożliwia auto-sharding i map/reduce. Analogią do kolumny w tradycyjnych bazach SQL jest kolekcja, a analogią wiersza - dokument.
CRUD:
C: db.user.insert({"username":"ken"})
jeśli kolekcja 'user' nie istniała wcześniej, zostanie teraz stworzona
R: user = db.user.findOne({"username":"ken"})
U: user.city = "St. Louis"
jeśli 'city' nie istniało wcześniej zostanie stworzone w kolekcji 'user'
db.user.save(user)
D: db.user.remove({"username":"ken"})
dodanie indexu i sprawdzenie czy istnieje:
db.user.ensureIndex("username":1)
db.user.hasIndexKeys()
Użyteczne polecenia MongoDB:
show dbs
use <database name>
db.user.save(user)
db.user.findOne(...)
printjson(user)
db.user.find(...).explain
db.user.ensureIndex({"username" : 1})
db.shapes.ensureIndex({radius:1},{sparse:true})
Uncle Bob zaprezentował oczywiste rzeczy. Przytocze killka:
- produktywnośc obniża sie z czasem jak kod staje się bardziej chaotyczny
- powinniśmy postawić sobie zadanie, że za każdym razem gdy czeckoutujemy kod z repo będziemy checkinować kod lepszej jakości niż wycheckoutowany.
- zalety TDD w pisaniu czystego kodu: mamy formalną dokumentację, kod jest niezależny od siebie (decoupling), refaktorujemy kod, prawie nie musimy debugować.
- dlaczego nie porzadkujemy swojego kodu? Bo się obawiamy że zepsujemy coś działającego. Dlaczego sie boimy? Bo nie mamy testów, żeby szybko zweryfikować, czy coś popsuliśmy.
- panuje mit, że piszac testy piszemy wszystko 2 razy. Kontrargument? Księgowi rachunki wg. zasady
dwustronnego zapisu prowadzą 2 rachunki aby na koniec porównać sumę z obydwu, dlaczego programiści nie mieliby tak samo robić z testami?
Praktyki jak pisać lepszy kod:
1. Mniej znaczy więcej (mniejszy codebase, mniej templatów, reużywalny kod)
2. Krótkie metody
3. Kompozycja zamiast dziedziczenia
4. Decoupling (TDD pomaga przy tym)
5. Ciągła integracja (CI)
6. Ciągły deployment (CD), nie czekaj na perfekcyjny kod, dostarczaj małymi partiami
7. Review kodu (narzędzia jak Crucible)
8. Metryki kodu (Cobertura, Emma, PMD, FindBugs), pokazuj ludziom diagramy z tych metryk, nie liczby, ludzie lubią obrazki
9. Minimalisuj przypadkowe skomplikowanie
10. Potrzeba zamiast ceremoniału i dobrych praktyk, np użycie bardziej eksppresyjnych języków kosztem statycznego typowania.
11. Nie pracujemy sami, ale z ludzmi - jak przekazujemy więdzę i wartości w zespole? Np. opracowanie podręcznika developera, w którym specyfikujemy ja postawić środowisko developerskie, jak szybko zacząć z kodem.
Przedstawił kilka inspirujących pomysłów i linków jak tworzyć innowacyjne rzeczy, mogące zmienić świat.
Książki:
Techniki pomagające w zmianie:
1. Metoda Mojito - użyj dostępnych ale nudnch składników, które razem stworzą interesujący system
3. Teoria
Dyfuzji Innowacji wyjaśniająca w jaki sposób nowe idee i technologie rozprzestrzeniają sie w społeczności.
4. Zastanów sie nad środowiskiem jakie chcesz zmienić, pokoje, biuro, np zacznij umieszać ciekawe plakaty, wlepki stymulujące myślenie.
Ostania już prezentacja, która właściwie nie wniosła nic nowego a jedynie udowodniła po raz kolejny, że Uncle Bob jest doskonałym showmanem. Po raz kolejny rozprawiał nad tym, jak tworzyć czysty kod stosując TDD (gdyby to było takie proste w realnych projektach) i jak być profesjonalistą, który potrafi sprzeciwić się nieosiągalnym terminom w myśl dostarczania rozwiązań wysokiej jakości. Jeśli nie potrafimy zmienić mentalności ludzi w naszej pracy powinniśmy albo zmienić organizację (w sensie organizaje pracy), albo zmienić organizację ( w sensie iść do innej firmy :)).
Z dyskusji z Wujkiem po prezentacji dowiedziałem się, że aby zacząć realnie stosować TDD ponoć wystarczy popracować w ten sposób ok. tygodnia (hm.. czyżby?).
Tym sposobem dobiegł końca 3-dniowy cykl wykładów i warsztatów. Kolejny raz Grzesiek Duda wraz koorganizatorami dowiódł, że warto było wybrać się na 33rd Degree, chociaż może niektóre wykłady były bardziej popisówką aktorską prowadzących, ale nawet to pozwoliło zobaczyć jak można prowadzić prezentację trzymającą w napięciu i bawiącą publikę zamiast niejednokrotnie usypiających wykładów (przeciętne wykłady na studiach).
Duży plus i podziękowania za ogarnięcie logistyczne całości. Można było skorzystać z płatnych co prawda, ale za to niedaleko zlokalizowanych obiadów, a przez całe dni dostępne były darmowe przegryzaki przed salami konferencyjnymi. Tym razem, w porównaniu z ubiegłoroczną konferencją, zdaje się że nawet kolejki przed toaletami były krótsze.
Jak w ubiegłym roku zagościł również kiosk z ksiązkami O'Reilly, które można było kupic za 60% ceny.
Ogólnie na duży plus.
Inne relacje z tego wydarzenia:
http://art-of-software.blogspot.com/2012/03/prezentacje-na-33rd-degree.html
http://jlaskowski.blogspot.com/2012/03/po-33rd-degree-2012-w-krakowie-nie.html