środa, 20 maja 2009

Dziś

Dostarczyłem wczoraj tekst zdefiniowany w poście "Personal Development Planning". Piszę to, żeby ewentualny czytelnik nie doszukiwał się informacji na ten temat.

Pracuję dziś trochę nad PKgui (wbudowuję wsparcie dla różnych celów rysowania do komponentów coraz wyżej w hierarchii), ale głównie uczę się algorytmów i struktur danych na egzamin. Ciekawe to...

Muszę pomyśleć nad taką strukturą GUI, żeby warstwy nie używały komponentów z warstw najniższych. Wtedy będzie można wprowadzać do GUI dużo więcej zmian na różnych poziomach. Nie jest to jednak takie proste... Jakieś sugestie?

Mój komentarz na JoeMonsterze dostał wczoraj 9 "OK".

poniedziałek, 18 maja 2009

Ale ja nie chcę...

http://www.engrish.com/2009/03/do-must-let/

Ja nie chcę być w małej zabawce, w której nie można dotykać ognia, gdyż nie zadziałałby wtedy ultrafioletowy kaloryfer, tym bardziej że muszę pozwolić dziecku bawić się pod dorosłym.

Polecam tę stronę wszystkim, którzy uważają, że ich angielski jest słaby.

sobota, 16 maja 2009

Ten nasz projekt grupowy

Ten wpis powstaje z myślą o zadaniu na Career Management Skills, wartym 30% końcowej oceny, a mianowicie "Learning Journal". Wpis zawiera opis projektu grupowego, który mieliśmy w tym roku. Jest wiele rzeczy, które są warte przytoczenia, najważniejsze jednak aby praca była w kolejności chronologicznej i zawierała wgląd w to, co się działo w głowach i co można by było zrobić inaczej. Opiszę kilka dni lub wydarzeń w drugim półroczu projektu na podstawie emaili, które wciąż jeszcze rezydują w mojej skrzynce pocztowej. Wprowadzenia do projektu należy szukać kilka postów wcześniej pod nazwą Personal Development Planning.
1 Maj 2009 Oddanie Raportów.
Od kilku dni pisaliśmy raporty. Każdy miał do napisania 9 stron raportu grupowego i 5 stron indywidualnego, razem około 5000 słów i kilka obrazków. Przygotowania do wydarzeń dzisiejszego dnia polegały na wysłaniu do siebie kilku maili w sprawach organizacyjnych, które jasno stwierdzały, co powinno być gotowe na wczoraj, a co robimy dziś. Ja byłem odpowiedzialny za tabelkę z rozkładem zadań składających się na ten projekt i przykładowy kod z wyjaśnieniem. Dzisiejszy dzień to była istna gonitwa. Okazało się, że Mat i Mark nie mają jeszcze dokończonych swoich części raportu. Sam dokończyłem swoje rano, ale przynajmniej miałem je gotowe zanim przyszedłem. Dodatkowo Mark próbował jeszcze zmieniać coś w kodzie, przy czym wytknąłem mu, że nie jest to najlepszy moment, ale widocznie wierzył w siebie, bo pisał dalej. W czasie gdy pisali, miałem czas napisać jeszcze manual do programu. Adrian napisał wcześniej manual do strony internetowej. Postawa drużyny uniemożliwiła zrobienie przyzwoitego raportu, gdyż całość została złożona na ostatnią chwilę, więc nie została przeczytana. Gdybym miał czas to zrobić, nie podpisałbym się pod tym tekstem, nie wprowadzając kilku istotnych poprawek. Kilka sztandarowych błędów w raporcie:
- Adrian w swoim raporcie indywidualnym napisał "meats" zamiast "mates".
- W mojej sekcji "breakdown of tasks" obliczona liczba godzin przeznaczonych na projekt nie zgadza się z sumą liczb godzin przeznaczonych przez poszczególnych członków drużyny.
- Sekcja "group marking" zawiera tylko i wyłącznie procent wkładu w projekt przez każdą osobę, bez żadnego komentarza i zajmuje całą stronę, której reszta jest pusta.
- Adrian zrobił mnóstwo błędów gramatycznych, które nie zostały poprawione. Mimo to, że Matthew zadeklarował, że przeczyta i poprawi teksty nieanglików, nie zrobił tego, prawdopodobnie z braku czasu.
- Ogólny chaos, brak tytułów sekcji, numeracji, niejasne, powtarzające się teksty.
- Zapomnieliśmy dodać do raportu manual, który napisałem.
Ogólnie rzecz biorąc, schrzaniliśmy ten raport. Jestem zadowolony ze swojego raportu indywidualnego, ale większość oceny dostanę za cały projekt, z czego większość jest przyznawana na podstawie grupowego raportu. Po dostarczeniu raportu poszliśmy na piwo i rozeszliśmy się do domów.
Wieczorem wysłaliśmy kod źródłowy naszego programu. Oczywiście musiałem dodać kilka rzeczy potrzebnych do uruchomienia aplikacji, bo Mark, który zadeklarował, że to zrobi nie pomyślał o tym. Wysłaliśmy również kod php naszej strony. Nie wiem, czy beze mnie grupa wysłałaby to, ale lobbowałem za tym i przekonałem Adriana, żeby wysłał także oświadczenie, że tego kodu (php) nie da się uruchomić bez wielkiego trudu, a strona nie została opublikowana. Ustalaniem takich spraw powinien się zająć menedżer, ale widocznie robił coś innego o tej porze. Ten dzień był niezapomnianym przeżyciem. Nie podoba mi się postawa Mata, który od tygodnia nalegał na skoncentrowanie się na raportach, zamiast na kodzie, a tak naprawdę nic w tej sprawie nie robił, zostawiając wszystko na ostatnią chwilę. Ja też zostawiłem raporty na koniec. Ja zrobiłem tak samo ale miałem swoją część raportu gotową kilka godzin wcześniej i nie ukrywałem swoich intencji.
7 Maj 2009 Przygotowania do prezentacji.
Nie ukrywam, że nie udało mi się zorganizować dla siebie czasu na to, aby przyjść dziś na uczelnię i przygotować z kolegami jutrzejszą prezentację efektów całego roku pracy nad naszym projektem. Naraziłem w ten sposób projekt na katastrofę, tak samo jak inni, którzy też nie przyszli. Inni też nie byli bez winy. Mark wysłał dziś maila do drużyny z zapytaniem, co robić, kiedy się spotkać. Adrian zadzwonił do mnie wczoraj aby poprosić mnie o przyjście dziś na uczelnię. Odmówiłem gdyż mam do zrobienia bardzo dużą część kompilatora na Language Engineering. Powinienem był zrobić go podczas długiej (miesięcznej) przerwy wielkanocnej, zamiast tworzyć PKgui. Mógłbym kontynuoać swój projekt teraz, gdybym miał gotowy kompilator.
Odpowiedziałem Markowi na maila, poruszając przy okazji kwestię laptopa, na którym będziemy robić prezentację. Nasz menedżer Matthew nie odpowiedział na mojego poprzedniego maila wysłanego dwa dni wcześniej w tej sprawie. (wpisane następnego dnia) Dowiedziałem się, że nasz menedżer przeczytał mojego maila i w ten sposób dowiedział się, że prezentacja nie może być uruchomiona na jego laptopie, gdyż ma Linuxa, a skonfigurowanie na nim bazy danych MySQL nie jest realistyczne, gdyż Adrian, który jest za to odpowiedzialny musiał spędzić dni na tym, żeby postawić ją na Windowsie. Jest to oczywiście błąd menedżera, bo gdyby laptop Adriana popsuł się drugi raz, musielibyśmy załatwić jakiś inny, na co nie ma czasu. Pomimo problemów "proceduralnych" udało nam się umówić na następny dzień na przygotowanie prezentacji. Muszę przyznać, że nie sprawdziłem dzisiaj skrzynki mailowej, przez co też naraziłem się na nieporozumienie, jednak dowiedziałem się o naszym spotkaniu rozmawiając przez telefon z Adrianem.
8 Maj 2009
Z rana poszedłem na uniwersytet, aby dopracować z kolegami ostatnie szczegóły projektu przed prezentacją. Szkoda, że nie zrobiliśmy tego wcześniej, przed wysłaniem kodu do oceny. Matthew zapewnił mnie że to jest dozwolone i nie mam powodu, żeby mu nie wierzyć, jednak takie dopisywanie czegoś na ostatnią chwilę nie jest mądre, bo może się nie udać to zrobić na czas tak, żeby działało. Sam zrobiłem błąd nie pracując nad projektem w poprzednich dniach, jednak wynikało to z innych prac do zrobienia. Nie przewidziałem podczas przerwy świątecznej, jaka gonitwa czeka mnie po niej... A właściwie to przewidziałem, jednak nie mogłem się zmobilizować, aby ją zacząć wcześniej. Odpoczywałem w Polsce i nic mi się nie chciało, spędziłem tylko około 20 godzin nad naszym projektem, co i tak uważałem za sukces. Nie powinniśmy byli olać kilka pierwszych tygodni na początku roku. Dziś pracowaliśmy od około 10tej do naszej prezentacji o 15.50, aby zrobić to, co chcieliśmy zrobić i przećwiczyć prezentację. Zrobiliśmy co w naszej mocy, aby zwrócić uwagę na to, co działa i z czego jesteśmy dumni i odwrócić uwagę od błędów, które dawały się we znaki podczas używania programu. Nie dołączył do nas rano Mark, za co jestem mu raczej wdzięczny, gdyż gdyby on zaczął wprowadzać zmiany do kodu dzisiaj, popsułby program, gdyż jego kod jest bardzo skomplikowany. Nie mam mu tego za złe, po prostu taka jest specyfika modułów, które stworzył. Mam mu natomiast troszeczkę za złe, że nie ubrał się wystarczająco oficjalnie na prezentację. Prezentacja przebiegła ogólnie bardzo dobrze. Matthew wykonał świetną robotę, wprowadzając oceniających do świata grafiki wektorowej i zakreślając perspektywy biznesowe naszego projektu. Największe pretensje mam do siebie, gdyż demonstracja programu w moim wykonaniu była nieco pozbawiona płynności, choć z drugiej strony cieszę się, że udało mi się podkreślić dobre cechy programu i uniknąć pokazywania błędów, co nie było łatwe. Nieco mniejsze pretensje mam do naszego menedżera, który mówił rzeczy, które nie były całkowicie zgodne z rzeczywistością na temat jednej rzeczy, którą ja zrobiłem (RoundPopupMenu). Nie udawał, po prostu pomylił się. Mam pretensje, ponieważ gdyby oceniający (3 wykładowców) zadali pewnie uszczegóławiające pytania na ten temat, okazałoby się, że prezentujący mija się z prawdą, co popsułoby ogólne wrażenie.

Ostatecznie moja rola w projekcie ukształtowała się jako rola programisty, ale też trochę menedżera. Nie chcę kreować się na jakiegoś bohatera, ale było wiele rzeczy, które powinien zrobić Matthew a zrobiłem ja. Można powiedzieć, że trochę próbowałem narzucić zaangażowanie innym członkom drużyny, jak również zorganizować lepiej nasze wysiłki. Niestety nie przyniosło to moim zdaniem wystarczających rezultatów.
Myślę, że nauczyłem się, jak NIE być menedżerem projektu (ja nim nie byłem, tak dla ścisłości). Bycie menedżerem wymaga bowiem przyjęcia na siebie dużo odpowiedzialności za powodzenie całości. Mówiąc bardziej szczegółowo, menedżer musi dbać o to, żeby członkowie drużyny właściwie się komunikowali, kiedy trzeba zrobić coś, co jest wymagane żeby projekt się udał. Kiedy na przykład kawałek kodu źródłowego, który musi mieć wysoką jakość, bo będzie potrzebny w przyszłości jest nie najlepszy, menedżer powinien interweniować, niezależnie od obaw o zniechęcenie do siebie ludzi. Kiedy moduł ma mieć taką budowę, żeby można było bezpiecznie wywoływać dowolne jego publiczne funkcje, a nie ma, menedżer powinien zainterweniować. Powinien sprawdzić, co zniechęca programistę do pisania właściwie. Problemem mogą być na przykład wymagania innego programisty, który używa tego modułu. Wtedy menedżer powinien porozmawiać z oboma. Nasz menedżer nie wykonywał tych zadań należycie. Największym jego problemem było to, że nie wymuszał stosowania odpowiednich technik inżynierii oprogramowania, na przykład automatycznych testów, zapisywania błędów, czy stosowania komentarzy dokumentujących. Tego nie da się nadrobić pod koniec projektu, więc powinien był wykazać inicjatywę na początku. Nie zrobił tego. Każdy pisał, jak chciał i efekt był oczywisty. Muszę dodać, że mój kod był pod tym względem nieco lepszy od innych ze względu na nieco większą staranność w pisaniu komentarzy.
Nauczyłem się też, jak współpracować w drużynie. Poświęcę tej sekcji trochę czasu, gdyż Tracy (nasz wykładowca) podkreślała istotność takich rzeczy. Nauczyłem się nieufności do ludzi, gdyż miało być nas pięciu ale piąty, Guy, mimo składanych deklaracji nie włączył się w proces implementacji projektu. Spowodowało to niezdolność dokończenia produktu mimo najszczerszych chęci. Projekt był ambitny dla czterech, nie mówiąc już o pięciu. Nauczyłem się również komunikacji. Wiem już kiedy wykazać inicjatywę, pisząc maila, bo upewniłem się, że nie warto czekać aż inni wpadną na ten pomysł. Na początku projektu mogłem wydawać się nieco nieuprzejmy. Teraz nie wydaję się nieuprzejmy, tylko lekko wkurzający, ale trzymający rękę na pulsie. :)

Refleksje o PKgui

Ten post jest długi. Zawiera wyrywkową historie mojego projektu, który tworzę po godzinach od blisko 3 lat. Piszę ten post z myślą o pracy pisemnej, którą muszę oddać. Projekt został rozpoczęty gdy nauczyłem się C++, zafascynowałem się programowaniem w nim i, nie mając pojęcia o czasie jaki zajmuje napisanie czegoś dużego, stwierdziłem, że napiszę moduł do mojego programu, który zajmie się interfejsem użytkownika. Inną, jakże istotną przyczyną utworzenia własnej biblioteki była chęć nauczenia się przyzwoitego programowania (co osiągnąłem) i fatalne problemy z konfiguracją gotowych bibliotek GUI. Później dowiedziałem się, dlaczego programiści C++ przechodzą piekiełko konfiguracji takich bibliotek zamiast stworzyć samemu komponenty potrzebne do programu, nawet jeśli to tylko mały podzbiór komponentów dostępnych w wybranej bibliotece - po prostu tworzenie i tak zajmuje dużo więcej czasu.
Cała ta biblioteka przechodziła wiele przemian w samym projekcie, nie mówiąc już o implementacji szczegółów. Początkowo szacowany czas zwiększał się z jednego miesiąca, poprzez 3, 6 i 12 miesięcy aż doszedłem do wniosku, że, wzorując się na niektórych deweloperach, skończę jak będzie gotowe. Zabrakło na początku jednoznacznej specyfikacji tego, co będzie, a czego nie będzie w projekcie. Ciągle wydawało mi się, że jak dołożę jeszcze jedną rzecz, to będzie lepiej, a ponieważ obecny projekt nie ułatwia takiego rozszerzenia, powinno się go nieco przeprojektować, bo to wstyd pokazywać taki kod komukolwiek. W dużej części była to prawda, ponieważ dopiero uczyłem się programować i projektować i duże części kodu rzeczywiście były nieczytelne, skopiowane, nieudokumentowane i zbyt skomplikowane. Często powodem było niewłaściwe użycie technik, takich jak szablony, przeładowanie funkcji czy polimorfizm. Było kilka rzeczy, z których byłem w pewnym sensie dumny, a które później okazały się beznadziejne w użyciu.
Sztandarowym przykładem czegoś, nad czym zmarnowałem dużo czasu jest właściwość biblioteki, dzięki której można wywoływać tę samą funkcję dla wielu widżetów na raz (widżet - element interfejsu, np napis albo przycisk). To umożliwiałoby np. zmianę stylu interfejsu. Próbowałem różnych rozwiązań. Idealne rozwiązanie byłoby nieintruzywne, tzn unikałoby zmieniania czegokolwiek w widżetach kiedy trzeba wywołać dla wielu z nich funkcję, która nie była jeszcze tak wywoływana. Sprawę komplikuje jednak fakt, że aby wywołać funkcję dla hierarchii widżetów (każdy widżet ma dzieci, one mają swoje dzieci itd), trzeba znać dzieci widżeta, czyli pobrać od niego dane. Idealne rozwiązanie byłoby też ogólne, tzn takie, żeby nie trzeba było definiować żadnych specjalnych komponentów dla każdej funkcji, którą chcemy wywołać. Ostatecznie rozwiązanie używa zewnętrznej biblioteki zwanej Loki. Ostatecznie ten mechanizm nie jest tak często używany, chyba że użytkownik programu zapragnie zmienić styl (skórkę) interfejsu. Na początkowe, częściowo intruzywne rozwiązania zmarnowałem dużo czasu, zanim zdałem sobie sprawę do czego tak naprawdę jest a do czego nie jest przewidziany język C++, którego używam. Pewnych rzeczy po prostu nie da się łatwo zrobić i dlatego tak błądziłem. Tak, żeby dodać smaczku do tej historii dodam, że obecnie rozważam całkowite porzucenie tego rozwiązania, bo ono używa biblioteki Loki, która ma różne niepożądane efekty uboczne, głównie zwiększenie czasu kompilacji i rozmiaru wynikowego kodu z powodu polegania na szablonach.
Krótkie omówienie tego, czego się nauczyłem dzięki temu projektowi.
Nauczyłem się technik inżynierii oprogramowania, hamowania swoich ambicji i planowania zadań. Nauczyłem się, ile jestem w stanie stworzyć w normalnych okolicznościach i jak wygląda praca po godzinach. Nauczyłem się, ile problemów mogą stworzyć niespodziewane szczegóły techniczne i jak ważne jest, żeby nie zapomnieć o tym, co się zrobiło. Najlepiej dokumentować wszystko, co się tworzy. Mogą to być komentarze w kodzie, ale nie stracą one na wartości jeżeli znajdą się na przykład na blogu. Na podstawie rozwiązań użytych w PKgui można by napisać co najmniej kilka ciekawych artykułów i żałuję, że ich nie napisałem. Stworzenie tego projektu wymagało też wielokrotnego zwracania się o pomoc na forum, dzięki czemu nauczyłem się skutecznie pytać, co przydaje mi się nie tylko na forum.
Mógłbym spędzić czas nad czymś bardziej wartościowym, np. nad wymyślaniem algorytmów ewolucyjnych, nauką na uniwersytecie w celu otrzymania lepszych ocen, czy projektem prowadzonym z kolegami, który dałby dużo więcej, bo mielibyśmy gotowy produkt, który można by było np. sprzedać.
Czy zmarnowałem czas, pisząc to GUI? Zupełnie naturalną reakcją byłoby powiedzenie, że nie żałuję bo się dużo nauczyłem, bla bla terefere. Jednak nie mam w zwyczaju tak się nad sobą rozczulać, więc nie będę, tym bardziej, że ten projekt nie był żadnym traumatycznym przeżyciem, o którym można by zrobić stereotypowy rozczulający materiał dla na staczającym się ostatnio TVN24. Żałuję, że nie wykorzystałem tego czasu inaczej, jestem natomiast zadowolony z ilości i jakości kodu, którym teraz dysponuję i nie mogę się doczekać dokończenia projektu, pokazania kodu światu, przyjęcia komentarzy, jakiekolwiek one nie będą i rozpoczęcia pracy nad czymś innym, co będzie wydawać się mniej trywialne i da bardziej "namacalne" efekty działania. Ciekawą ideę opisałem w swoim raporcie na temat rozwoju kariery, który oddałem na Career Management Skills, jednak nie będę jej tu opisywał, bo ten post i tak już jest długi. Ten paragraf uzasadnia wniosek z całego projektu: Nie angażować się w coś, co nie jest zupełnie ulubionym zajęciem, czymś, o czym się marzy.

piątek, 15 maja 2009

OpenGL w moim GUI

Cześć (Oddaję Tobie), czytelniku,

Pierwszy paragraf tak dla wyjaśnienia:
Jakieś dwa miesiące temu postanowiłem wprowadzić przyspieszenie sprzętowe i kompatybilność z OpenGL do mojej biblioteki GUI. Zrobiłem już Wysokopoziomowy interfejs rysujący i blitujący, który będzie wykorzystany w reszcie systemu GUI. Ten zestaw klas i funkcji deleguje żądania rysowania do kontekstu SDL (który jest tak naprawdę opakowaniem jakiegoś kontekstu odpowiedniego dla platformy, np. WinGDI) lub do OpenGL. Właściwymi miejscami do implementacji rysowania po ekranie bezpośrednio przez OpenGL lub SDL są klasy dziedziczące po PKgraphics_provider. PKgraphical_data zaś to klasa, która przechowuje bieżący obiekt PKgraphics_provider i umożliwia używanie zasobów, które muszą być wytworzone przy pomocy obiektu PKgraphics_provider, czyli zestawów tekstur klasy PKtexture_unit.
Mam już działające obiekty PKtexture_unit z wieloma teksturami (dla OpenGL) lub powierzchniami (dla SDL) wewnątrz. Powierzchnie graficzne, z których zostały stworzone tekstury są przywiązane do tych obiektów PKtexture_unit.
A teraz do rzeczy. Otóż z wprowadzenia do GUI tych machinacji wyniknął problem, mianowicie współdzielenie powierzchni (graficznych) przez różne obiekty w GUI nie wystarczy, bo są jeszcze obiekty PKtexture_unit, które nie są współdzielone (do samego współdzielenia obiektów używam inteligentnego wskaźnika). Wynika z tego fakt, że jeśli będzie 10 widżetów (np. przycisków) z tą samą teksturą, to w karcie graficznej będzie 10 kopii tej tekstury. To jest duży problem, zwłaszcza że GUI bywają bogate w widżety. Właśnie wymyśliłem rozwiązanie: flaga "immutable" w obiektach PKsurface, przechowujących powierzchnie graficzne. Jaki to ma związek? Rozumowanie jest proste: jeśli mam pewność, że powierzchnia nie będzie zmieniana, to mogę tworzyć z niej wiele obiektów PKtexture_unit i wszystkie będą takie same. A jeżeli wszystkie byłyby takie same, to można zamiast tego zrobić jeden i go współdzielić. To rozwiązanie jest dla mnie bardzo atrakcyjne, bo kod który teraz mam umożliwia bardzo łatwe zablokowanie wszelkich zmian w danej powierzchni, jeżeli jest w niej taka flaga. Wprowadza to jednak poważny problem: powierzchnia będzie niezmienna :) W takim razie powierzchnia jest właściwie "wymieniana" na teksturę. Można sobie wyobrazić funkcjonalność, która "oddaje" nam powierzchnię, gdy tekstura jest zwalniana. Idealne rozwiązanie polegałoby na wprowadzaniu wszystkich zmian powierzchni w teksturze, ale to oznaczałoby zmienianie dużej ilości kodu.
Muszę przyznać, ciekawi mnie, jak rozwiązano ten problem w innych GUI.
Po co piszę to na blogu? Po to, żeby uświadomić sobie, co tak naprawdę robię. Po krótkim przemyśleniu sprawy doszedłem do wniosku, że flaga "immutable" powinna być tam niezależnie od tego, czy obiekty PKtexture_unit są współdzielone, więc... kod, który teraz mam jest błędny. Kolejny wniosek to taki, że jeśli lepiej by było w ogóle nie "zaprzyjaźniać" powierzchni z teksturami. Istnienie powierzchni ma o tyle sens, że do niej można wczytać obrazek z pliku, albo można na niej coś łatwo narysować. Po przekształceniu w teksturę można ją natomiast wyrzucić. Po co zaśmiecać pamięć. Utrzymywanie powierzchni zaprzyjaźnionej z teksturą chyba ma sens tylko jeśli implementacja "odbija" na teksturze wszelkie zmiany popełnione na powierzchni. Wtedy jednak bardziej stosowna byłaby tekstura schowana w powierzchni, a nie odwrotnie.
Jeszcze inną sprawą jest to, że powierzchnia jest potrzebna np. do przeskalowania GUI. Sama tekstura nie wystarczy, bo powierzchnia może być np. złożona z wielu małych, co wymusza zupełnie inny algorytm skalowania niż rozciąganie. Skomplikowana sprawa.