Sprzed prawie czterech lat pochodzi pewien niewielki (~2KLOC) projekt uczelniany, na który natknąłem się kilka dni temu w swoich przepastnych archiwach i postanowiłem upublicznić. Jest to implementacja prostego (acz zupełnie funkcjonalnego) serwera FTP, napisana w czystym C pod systemy POSIX-owe. Nie spodziewam się bynajmniej, aby mogła znaleźć rzeczywiste zastosowanie jako kawałek oprogramowania. Jest ona jednak całkiem interesująca jako kawałek kodu.
Wielu znany jest zapewne “syndrom następnego pół roku”. Polega on na tym, że gdy po pół roku (plus/minus kilka miesięcy) spoglądamy na stworzony przez siebie kod, widzimy go tak, jakby napisał go ktoś zupełnie inny. Zazwyczaj wręcz trudno nam się w nim połapać i szybko dochodzimy do wniosku, że teraz napisalibyśmy go zdecydowanie lepiej. Nasz twór traktujemy więc jako bezwarto… ekhm… legacy code (;]), i uważamy to za naturalną kolej rzeczy.
Jednak moje niedawne znalezisku okazało się pod tym względem sporym zaskoczeniem. Nietypowe jest bowiem to, jak przetrwało ono próbę czasu. Na jego podstawie muszę dojść do lekko szokującego wniosku, iż Xion2007 potrafił – o zgrozo – pisać dobry kod. Robił to wprawdzie ostrożnie i raczej niepewnie (czego dowodem była przesadna ilość komentarzy), ale koniec końców udawało mu się to całkiem nieźle. Wysyłając mu wiadomość z przyszłości, mógłbym wprawdzie wspomnieć o zaletach podziału kodu na pliki krótsze niż 800-linijkowe, lecz poza tym do niewielu rzeczy mógłbym się przyczepić. To zupełnie akceptowalny, czytelny i przejrzysty kod w C…
Madness!
Przyznam, iż jestem trochę zaskoczony. Okazuje się bowiem, że niekiedy zupełnie nie udaje mi się skomunikować tego, co mam w rzeczywistości na myśli. A wydawać by się mogło, że przynajmniej te 500+ notek na blogu powinno dość skutecznie nauczyć mnie, jak klarownie formułować swoje stwierdzenia i opinie. Teoretycznie niby też wiem, że zrozumienie jest często podwójną iluzją, więc z dwóch wyjaśnień należy zawsze wybierać te łatwiejsze i bardziej bezpośrednie – także wtedy, gdy trzeba je dopiero znaleźć. To wszystko wydaje się oczywiste, dopóki – jak się przekonałem – nie okaże się trudne w praktycznym stosowaniu.
O co mi w tym miejscu chodzi? Ano o to, iż niesłusznie zostałem uznany przez kilka osób za – nieco wyolbrzymiając – hejtera JavaScriptu. Tak została przez niektórych odebrana moja niedawna publikacja slajdów z prezentacji pod tytułem The Beauty and the JavaScript; tytułem, który rzeczywiście może dawać co nieco do myślenia ;) I chociaż mógłbym uznać, że wchodzi tu w grę głównie kwestia oceny wykładu po samych slajdach, to jakoś wydaje mi się, że wypadałoby tu dokonać małego sprostowania. Dzięki temu mógłbym też napisać, jak to właściwie jest z tą moją opinią o JavaScripcie, który przecież już od dłuższego czasu jest sam w sobie bardzo nośnym tematem.
Spieszę więc z wyjaśnieniem, że w kwestii JavaScriptu mam raczej osobliwą opinię. Otóż przede wszystkim jest mi go… żal.
W językach ze skrzywieniem obiektowym klas używa się często i gęsto. Nieco inaczej jest z innym, o wiele mniej znanym pojęciem: metaklasami. Przedrostek meta- sugeruje tu od razu nieco wyższy poziom abstrakcji, co jest generalnie słusznym podejrzeniem. Dokładne znaczenie kryjące się za tym terminem w pewnym stopniu zależy od języka programowania, lecz w każdym przypadku chodzi o narzędzie związane z manipulowaniem samymi klasami. Zupełnie intuicyjnie jest to więc “jeden poziom meta więcej” :)
Jako nieco bardziej zaawansowana funkcjonalność, metaklas nie wykorzystuje się codziennie. Tym bardziej jednak warto wiedzieć przynajmniej z grubsza, jak działają, aby poprawnie rozpoznawać sytuacje, w których są one użyteczne. I dlatego właśnie dzisiaj przyjrzymy się metaklasom w trzech wariantach, specyficznych dla popularnych języków programowania.
Pierwszy z nich dotyczy systemów refleksji, czyli przydatnego mechanizmu językowego, pozwalającego programowi na wgląd w swoją wewnętrzną strukturę. W językach obiektowych oznacza to przede wszystkim możliwość posługiwania się klasami na bardziej dynamicznym poziomie. Są one wtedy reprezentowane przez obiekty, i właśnie te reprezentacje – używane poprzez moduły refleksji – nazywa się czasem metaklasami.
W wielu językach wyglądają one podobnie. Java ma na przykład klasę java.lang.Class
, zaś C# – System.Type
. Zyskując dostęp do instancji tychże klas (np. poprzez Class.forName
albo Type.GetType
) otrzymujemy możliwość wykonywania operacji na klasach, które one reprezentują. I tak możliwe jest chociażby tworzenie ich obiektów, wywoływanie metod, dostęp do pól. Dzięki temu możemy na przykład w (miarę) łatwy sposób zaimplementować proste rozwiązania wspierające pluginy, tj. dynamicznie ładowane wtyczki do naszych aplikacji.
Drugie znaczenie pojęcia metaklasy opisuje referencje do klas. Ideą jest tu traktowanie klas jako wartości pierwszego rodzaju (first-class value), które można przypisywać do zmiennych i w uogólniony sposób przekazywać między różnymi miejscami w kodzie. Specjalne zmienne, do których możemy “przypisywać” klasy są w co najmniej jednym języku nazywane właśnie metaklasami.
Przydatność tego typu rozwiązania zależy głównie od tego, jak wielkimi jesteśmy fanami wzorców typu fabryka abstrakcyjna :) Być może podstawową funkcjonalnością takich metaklas jest bowiem abstrakcja procesu tworzenia (lub ogólniej: pozyskiwania z zewnątrz) nowych obiektów. Pozostałe przypadki użycia metaklas są pokrywane zwykle przez szablony (C++), typy generyczne (C#, Java, itp.) lub podobne mechanizmy tworzenia kodu, który w pewien określony sposób jest niezależny od dokładnego typu obiektów, którymi operuje.
Czas wreszcie na trzeci wariant metaklas. Jest on zdecydowanie najciekawszy, ale też najbardziej skomplikowany i w pewien sposób wysublimowany – mimo swojej niewątpliwej użyteczności. Mam tutaj na myśli metaklasy w Pythonie.
Zamieszczam slajdy z prezentacji, którą wygłosiłem dzisiaj w ramach Polidea Talks. Dotyczy ona androidowego wynalazku znanego jako Cloud to Device Messaging (C2DM) i będącego odpowiednikiem apple’owych Push Notifications z systemów iOS i OSX. Dla nie do końca zorientowanych spieszę z wyjaśnieniem, iż jest po prostu dość sprytny sposób na to, by urządzenie mobilne mogło “natychmiast” otrzymywać informacje ze zdalnego serwera – bez konieczności regularnej synchronizacji, która zużywa baterię i nie tylko.
Push! - Instant notifications on Android through C2DM (591.7 KiB, 1,974 downloads)
Slajdy są tym razem w klasycznym PDF-ie. Chwilowo nie mam żadnej lepszej alternatywy dla starego, dobrego PowerPointa :)
Branża IT oraz nauka zwana informatyką liczą sobie już ładnych kilkadziesiąt i wygląda na to, że dziedzina ta zaczyna w pewnym sensie “dorastać”. W dość nieprzyjemnym sensie, muszę dodać. Jej znani pionierzy zaczynają bowiem nas opuszczać, czego dobitym dowodem jest zeszły miesiąc, gdy kilku z nich pożegnaliśmy w ciągu stosunkowo krótkiego czasu.
Ponieważ dzisiejszy dzień jest dobrą okazją do takich wspomnień, pozwolę sobie zwrócić uwagę na jednego z nich. Tego, który bez wątpienia miał największy wpływ na to, w jaki sposób programujemy komputery i jak obecnie wygląda przemysł software‘owy.
Mam tu na myśli oczywiście Dennisa Ritchie.
Wpływ Ritchiego na kształt informatyki jest trudny do przeceniania, bowiem miał on ogromny udział w początkach rozwoju dwóch jej ważnych aspektów: języków programowania i systemów operacyjnych. Jego zasługi w pierwszej z tych dziedzin wyrażają się głównie w stworzeniu języka C – prawdopodobnie najszerzej wykorzystywanego języka programowania w historii IT. Nawet jeśli sami nigdy w C nie programowaliśmy, to istnieje bardzo duża szansa, że nasz ulubiony język programowania ma z C wiele wspólnego: począwszy od bezpośredniej historii (C++, Objective-C), poprzez składnię (C#, Java, JavaScript, D, Scala, Go, itp.) aż po kluczowe narzędzia w rodzaju interpreterów napisanych w C (Python, Ruby, Perl, PHP). W rzeczywistości trudno jest wskazać język, który nie miałby czegokolwiek wspólnego z C – z ważniejszych należą do nich chyba tylko wczesne warianty Lispa (którego twórca, notabene, również zmarł w zeszłym miesiącu…). Niełatwo jest więc przesadzić, mówiąc o decydującym wpływie Ritchie’ego na kształt narzędzi używanych obecnie przez programistów na całym świecie.
Podobnie jest zresztą z oprogramowaniem w ogóle. System UNIX – którego Ritchie był jednym z kluczowych twórców – w niezliczonych odmianach i pochodnych działa na sporej części istniejących komputerów i wyrobów komputeropodobnych. Dotyczy to zarówno superkomputerów, wielkich serwerowni (żeby nie użyć słowa na ‘ch’ ;]) oraz małych serwerów, ale też domowych PC-tów i laptopów, a nawet urządzeń mobilnych: telefonów i tabletów. Większość (albo przynajmniej duża część) z nich operuje pod kontrolą systemów wywodzących się z UNIX-a i używa przynajmniej części związanego z nim stosu oprogramowania, którego prawdopodobnie najważniejszym komponentem jest… dokładnie tak – kompilator C.
Nie ma oczywiście żadnej pojedynczej osoby, której moglibyśmy zawdzięczać obecną postać technologii obliczeniowych i informacyjnych. Jednak Dennis Ritchie jest bez wątpienia człowiekiem, bez którego wyglądałaby ona dzisiaj zupełnie inaczej. Dlatego też warto o nim pamiętać – nawet jeśli wskaźniki z C czy uniksowy terminal są dla nas strasznymi rzeczami, z którymi nie chcemy mieć nic wspólnego :)
(…) są dwa style pisania – pierwszy to: “popatrzcie jaki ja jestem mądry” – a drugi to: “popatrzcie jakie to proste”.
Jerzy Grębosz, Symfonia C++
Autor tego stwierdzenia miał na myśli przede wszystkim pisanie technicznej prozy, a więc wszelkiego rodzaju artykułów, książek, kursów i tutoriali (i blogów? ;]). Po namyśle stwierdzam jednak, że równie dobrze nadaje się ono i do poezji – czyli kodu. Podobnie bowiem przedstawia się kwestia wyższości drugiego stylu nad pierwszym, w większości przypadków.
“Większość” nie oznacza aczkolwiek “wszystkich”. Czasami górę biorą na przykład kwestie wydajnościowe, które niekiedy uzasadniają wyprodukowanie kodu wyglądającego jak przemyślnie zaszyfrowane zaklęcie. Klasycznym przykładem jest procedura szybkiego obliczania , wyciągnięta wprost ze źródeł Quake‘a III:
Funkcja ta (której autorstwo niesłusznie przypisuje się czasem Johnowi Carmackowi) doskonale pokazuje, jak ważna jest czytelność i zrozumiałość kodu. Robi to w najlepszy możliwy sposób, tj. nie posiadając żadnej z tych dwóch cech :) W zamian oferuje znacznie ważniejszą w swoim zastosowaniu jakość – czyli wydajność.
Obliczanie odwrotności pierwiastka kwadratowego to jedna z najczęściej używanych operacji w grafice 3D – zawiera ją np. każda normalizacja wektora. Sensowne jest więc jak największe zoptymalizowanie tej funkcji. Będzie ona przecież wywoływana setki czy tysiące razy podczas renderowania pojedynczej klatki.
W sumie daje to kilkadziesiąt tysięcy wywołań na sekundę, a to dość unikatowa perspektywa jeśli chodzi o wartościowanie szybkości, czytelności, elastyczności – i tak dalej. I właśnie dlatego wspominam o niej jako o oczywistym wyjątku. Parafrazując popularną ostatnio proporcję: w 99% przypadków podobny kompromis nie będzie musiał dotyczyć nawet 1% kodu :)
O wiele bardziej typową sytuacją jest bowiem zdecydowana wyższość klarowności, czystości i zrozumiałości. To jest właśnie ów drugi styl: “zobaczcie jakie to proste”. Bierze on pod uwagę oczywisty w gruncie rzeczy fakt, iż głównym odbiorcą kodu jest człowiek, a nie komputer. Jeśli przyszły czytelnik potrafi z łatwością zrozumieć intencje autora – bo są one wyrażone przejrzyście i jednoznacznie – to niemal równie łatwo przyjdzie mu modyfikacja, rozszerzanie i poprawianie programu. Nie wspominając już nawet o tym, że program, który daje się łatwo “wytłumaczyć” samym kodem z definicji nie może być zanadto skomplikowany. Syntaktyczna prostota przekłada się więc na semantyczną, która z kolei dobrze koreluje z innymi pożądanymi właściwościami – jak choćby niezawodnością.
Nie mam już wiele wspólnego ze światkiem World of Warcraft, ale akurat wieści o nowych dodatkach potrafią jeszcze wzbudzić we mnie zainteresowanie. Tak jest też z ogłoszonym (przed)wczoraj – zależnie od strefy czasowej – dodatkiem numer cztery, noszącym nazwę Mists of Pandaria.
Z pozoru nie zaskakuje on niczym nadzwyczajnym, jako że pod względem rozszerzeń WoW stał się już podobny do The Sims: ta sama idea z nowymi dekoracjami. Mamy więc tutaj wyższy limit poziomu postaci (90), nowy kontynent (Pandaria), nową rasę i klasę, świeżą dostawę instancji i raidów – i tak dalej. Krótko mówiąc: standard. W takiej sytuacji naturalnie jest poszukiwanie rozwiązań, które nie wpadają tak łatwo w dobrze znane szuflady i pozwalają domyślać się, w jakim kierunku gra będzie dalej podążać.
A według mnie jest on dość oczywisty. Otóż Blizzard chce dokonać czegoś, co jest “niemożliwe”, a zarazem absolutnie konieczne, biorąc pod uwagę obecne trendy w komputerowej rozrywce. Wyzwanie jest koncepcyjnie aż nazbyt proste, ale jego realizacja – jeśli w ogóle możliwa – wymaga balansowania na bardzo, bardzo cienkiej linie.
Co należy zrobić? Bagatela: połączyć Diablo z FarmVille – w przenośni, rzecz jasna.