czwartek, 3 grudnia 2009

środa, 28 października 2009

ASD Polemic

This post is a polemic with
this. This is why it's in English.

Just to provide enough context, I'll quote a lecture slide (I hate you for not doing this in your post; I've wasted so much time trying to figure out what do you mean, e.g. what is the factory supposed to create or where is your point of view in the system that you develop).
The lecture slide says:
"
In some situations, using the new keyword to construct
new objects of a given class is NONO
Connection con = new Connection(db);
This suffers from tight coupling. If, later on, you want
to issue connections from a pre-existing pool of
objects, rather than creating a new one every time, this
code prevents you. Instead, use a 'factory' approach:
Connection con = Connection.get(db);
"
First lets make things clear.
First of all note that this example is there to making people aware that there exists a thing called a factory method and that it may help when sharing objects. When an noob reader reads this slide, he grasps those two ideas and everything's OK, because those general ideas are OK. On the other hand, when someone who really knows something about those things read this, he will almost certainly say "ugh!", because it is not a good example of factory. This is a bit useless pattern called factory method, because:
1. This method is defined when the Connection class gets written, noone can change it later
2. Noone can create objects of the subclasses of Connection (assuming constructors are private).
3. It may give you the same object many times when you don't want that.
4. It is a static method so it in general cannot rely on having any information about context in which it is called.

The example on the slide is really bad because a method of class A creates objects of class A, which makes the problems 1 and 2 very true, so it is even worse than using the constructor directly. If it was another class, which would allow this method to be non-static, you could probably inherit from it, redefine the method and get the desired behaviour.
ASIDE: Note that I do not say "using new operator", but "using constructor" to demonstrate how much I dislike the fact that the lectures are so Java-oriented.

What overcomes all those problems is the abstract factory pattern.

After a tough but thorough analysis of your stream of conciousness I arrived at a conclusion that you are actually arguing agains the above constraints of the factory method pattern.
You correctly argue with the problems 1 and 3 in about half of your post, starting with:
"For example, say you have a database connection object and you want to set up a pool of X objects that you want to reuse. Rather than use the factory method, you could edit the Connection object such that is composed of e.g. a DatabaseSocket which interfaces with the database directly. Connection's constructor grabs a DatabaseSocket from the pool, and existing methods on the Connection object forward themselves to the DatabaseSocket. (delegation!)"
You basically found an example in which you need to modify the way Connection is defined with (pardon my English (as French say) if it's not a comprehensible sentence). Additionally, you could probably have "interface Connection" and a subclass of it defined to solve your specific problem with multithreading. This would overcome problem 3.
You argue with the problem 4 in:
"Consider the case where there is contention for a limited resource. With a factory method that directly hands you an object, the onus is usually on you to properly handle sharing and locking for that object."
A proper object oriented factory could handle that because you would define the way of creating objects and you could use available information about how to share and lock particular objects. You would just give that knowledge as an argument to the constructor of the factory. Now I should describe the abstract factory design pattern but other people have done it before, so I will not repeat the effort. You can find it on Wikipedia.

"'do you want a brand new object of your very own, or are you happy being given an object to achieve what you want?' If you're doing anything with mutable state outside your program logic, you probably don't need to track any extra data outside of whatever exists externally, and you should ask whatever subsystem you are dealing with for appropriate objects to this effect. However, if you want additional data with your ice-cream sundae, the former is actually a sensible thing to do, and doesn't preclude you from changing the implementation of the created class so that it grabs the 'real' object elsewhere behind the scenes."
Very true. However, note that with the abstract factory you can pretty much have the advantages of both things, so if any one of the above solutions is too limited, there is another way!
To conclude, you are generally right, but you are a bit cherry-picking a particular example from the slide and you are missing the point a bit, as you praise a normal idea agains a bad one, when there is a really good one (the abstract factory), that solves what the bad one was supposed to solve.

---
Different issue:
"Inheritance has its uses, but you need to be careful about what it really means. It's not about extending functionality as much as it is about telling people "Hey, I have a cool object here with special features I can use, but since it behaves exactly like this more basic object, you guys get to play with the same instance as me!"."
So you are talking about extending the inheritance hierarchy upwards (introducing another subclass such that "you guys" (i.e. another code) can start using the object). This is one way of taking advantage of inheritance and it is a very good one because we build up the hierarchy after we actually have an implementation of a base class. Therefore we know what polimorphic methods will be needed and what are necessary generality constrains of the base class to make the implementation feasible. This usually leads to introducing something that Java calls an interface. Note, however, that if a class is really designed to extend it (e.g. because it is part of a framework), then extending functionality can be a good idea as well. It is really important, however, to distinguish between extending existing functionality and/or data (not a good idea in most cases) and implementing interface.
The main problem of inheritance is CONFUSION, MISUSE and MIXING of those two ideas. Using any one of them is not a problem. The whole idea of inheritance is also not a big problem, on the contrary to what Ian tries to squash into students' minds (Yes, I know that inheritance is sometimes inflexible because you cannot add methods to base classes, but this is not the argument that Ian uses. At least he stresses it an order of magnitude weaker than all the other arguments).

The lecture slide says:
"The extends word wrongly suggests "add more fields
to" or "reuse the implementation of""

I think that there is a big problem with naming, because "inheritance" really does not describe a result of using a programming concept, but way of implementing both of the two concepts described above by a programming language. That's why in C++, which is quite old now, there is syntactically just one way of inheriting (the ":" operator; OK, you can write "private", "protected" or "virtual" after it but nobody uses the first two and the third is broken). In Java, which is a bit younger, there is a separation of extending classes and implementing interfaces. There is a problem with the extending mechanism, particularly with the illusion of being able to extend anything and override every method of it, but the "extends" keyword is a good word. It reminds the writer that it whatever is extended should really be extendable. In my opinion it is more like telling the coder: "You are going to EXTEND something. Are you sure?" rather than "You are writing 'extends', so whatever you are trying to extend must be designed for extending.". It's silly, why would anyone think something like this? There is the problem with how easy it is to write "extends" that compiles, not with the word itself. This is a problem with Java, not with extending.

Thanks for the paragraph about traits!

czwartek, 15 października 2009

PKreversed_set

Stwierdziłem, że wrzucę przydatny kawałek kodu, który zrobiłem kilka dni temu.
Problem: istnieje implementacja jakiegoś algorytmu w C++ i chcemy, żeby mógł działać też w odwrotnym kierunku, np od końca do początku. Algorytm jest skomplikowany i nie chce się pisać go ponownie. Rozwiązanie problemu metodą Copiego i Pasta + zastąpienie iteratorów iteratorami odwrotnymi nie jest atrakcyjne (bo powstają dwie kopie tego samego kodu do utrzymania itd). Moje rozwiązanie jest eleganckie:
- Zrobić z algorytmu szablon algorytmu, sparametryzowany typem kontenera.
- Zrobić opakowanie na kontener, którego funkcjonalność jest odbiciem lustrzanym funkcjonalności oryginalnego kontenera, np. end() jest zastąpione rend(), typ 'iterator' to tak naprawdę 'reverse_iterator' oryginału itd.
- Wywoływać algorytm raz dla oryginalnego kontenera a raz dla opakowania.

Kod zawiera odbicie lustrzane kontenera std::set.
Można go pobrać tu.

piątek, 9 października 2009

Tower Defense dla wielu graczy.

(już napisałem "w multiplayerze", ale zmieniłem, żeby nie zgrzytać spolszczonymi anglicyzmami)
Mamy taki przedmiot "Advanced Software Developement". Jedynym kryterium oceny końcowej jest projekt programistyczny do zrobienia w parach. Bardzo mi to odpowiada, para jest chyba najlepsza do tworzenia programów, bo całkiem sporo można razem zrobić, jest wzajemna motywacja, a jednocześnie nie rozmywa się odpowiedzialność, a wizja jest bardziej spójna (to taka dygresja). Do rzeczy: podczas naszej burzy mózgów dzisiaj, kiedy to powinno nam przyjść do głowy jak najwięcej pomysłów, a przyszły tylko 3, udało mi się przekonać kumpla do zrobienia gry w Javie, gry typu Tower Defence. Wyróżnianie się gry na tle zawartości zagraconego internetu ma być osiągnięte dzięki temu, że będzie w niej gra wieloosobowa (zmowu zmieniłem z "multiplayer") asymetryczna. Co to znaczy? Z grubsza tyle, że każdy gracz ma zupełnie inne zadania do wykonania: jeden gracz utrzymuje bazę i chroni ją przed atakami, budując ostrzeliwujące wieże, a drugi mówi oddziałom, jaką ścieżkę mają wybrać, wybiera typ żołnieża i rozkazuje mu zniszczyć wyżej wymienioną bazę.
Asymetryczna? Nie przekonałem kolegi do tego pomysłu, nalegał na zrobienie trybu gry, gdzie każdy gracz ma swoją bazę a drugi wysyła na niego odziały. Wymanewrowałem z tej niezręcznej sytuacji argumentując, że najpierw zrobimy tryb asymetryczny, a potem po prostu walniemy na mapę obiekty w trybie asymetrycznym oraz ich odbicie lustrzane, tworząc w zasadzie tryb symetryczny. To stwierdzenie to był jednak tylko sprytny wybieg. Idea jest taka, że jak kolega przekona się do trybu asymetrycznego, zapomni o swoich zmartwieniach. Skąd ta pewność?
Zacząłem dzisiaj analizować fakt, że gry TD są tak popularne; wciągają myślące osoby w wir zadania, a jednocześnie nie męczą. Są to tak naprawdę klasyczne strategie czasu rzeczywistego, ale niepełne, bez tworzenia oddziałów, złożonego dowodzenia i niszczenia nimi bazy wroga.
Przypomniawszy sobie kilka rozgrywek, stwierdziłem że wciąganie w grę polega na pozwoleniu graczowi skupić się na pojedynczym zadaniu, udoskonalać techniki jego wykonywania do granic możliwości. Gry TD to umożliwiają, a wypasione strategie w pudełkach po 100zł już często nie (choć jest to temat na inną dyskusję). Zaletą grania w TD jest więc łatwość, płynność. Dokładniej to analizując, stwierdziłem, że w grze TD można zobaczyć jak zmienienie czegoś w linii obrony wpływa na wynik rozgrywki, to "zobaczenie" jest niczym nieprzerywane, a do tego następstwo przyczynowo skutkowe jest rownoznaczne z bezpośrednim następstwem czasowym. To znaczy, że myśli z łatwością nadążają za tym, co widzimy, a jednocześnie to, co widzimy nadąża za myślami, zmieniając się od razu! Co więcej, dzięki powtarzającym się falom ataków, można z łatwością wyciągać wnioski nie tylko z pojedynczych ataków, ale z całych serii. Dzięki temu dodatkowo unika się losowości wyniku gry, widocznej w komejcyjnych strategiach, gdzie jeden lub dwa ataki decydują tak naprawdę o wyniku.
Ta magia gier TD jest zbyc cenna, żeby można było ją stracić. Niech w grze wieloosobowej jeden gracz gra tak, jak w jednoosobowej, a drugi w zupełnie nowy sposób, też zaprojektowany dla jednej osoby.

Sieci Neuronowe.

Jednak to napiszę. Podjąłem się niedawno nauki sieci neuronowych. Efekt można zobaczyć tu.
Wprowadzenie:
Jest prostokątny samochodzik i trasa, poza którą fizycznie nie da się wyjechać. Samochodzik może kontrolować swoje przyspieszenie oraz skręt kół. Jeżeli uda mu się przejechać przez całą trasę, ma najlepszy wynik, jeżeli nie ruszy się z miejsca lub cofnie, najgorszy. Przejazd zostaje przerwany jeśli samochodzik uderzy w granicę trasy (musi jechać wewnątrz).
Zadanie:
Zrobić program, który potrafi nauczyć samochodzik jechać po (prawie) dowolnej trasie.
Żeby była jasność:
- Nie programuję samochodziku samemu, używając własnej wiedzy o tym jak jeździć. Program ma sam zebrać tę wiedzę.
- Program nie zbiera wiedzy o konkretnej trasie, tylko ogólnie o tym, jak jechać.
Wykonanie:
Ewolucyjne wyznaczenie sieci neuronowej rozwiązującej problem, czyli sterującej samochodzikiem.
Dane wejściowe: bieżąca pozycja, prędkość, to, co "widzi" samochodzik (odległość od granic toru w różnych kierunkach).
Dane wyjściowe: przyspieszenie (4 wyjścia: duże przyspieszenie, mniejsze przysp., duże spowolnienie, mniejsze spowol.), skręt kół (podobne 4 wyjścia).
Algorytm ewolucyjny działa na populacji 50 "mózgów samochodzików". Są wybierane 3 losowe mózgi. Te, które jeszcze nie były sprawdzone w praktyce, są sprawdzanie: kierują przejazdem samochodziku na trasie. Są porównywane ich wyniki. Najgorszy mózg jest wywalany, pozostałe są krzyżowane dyskrenie i tak stworzony mózg jest włączany do populacji.

Filmik przedstawia kilkanaście spośród około pięciu tysięcy przejazdów treningowych wykonych przez program. Pokazane są tylko te, które poprawiają maksymalny wynik, osiągany przez samochodzik.
Program jest napisany w C++ z użyciem biblioteki PKgui.

czwartek, 13 sierpnia 2009

Witam

Od czasu ostatniego posta miałem dużo ciekawych pomysłów, jednak niewiele przeszło w fazę realizacji. Ale to wcale nie oznacza, że mało zrealizowałem - głównie tworzyłem PKgui (swoją bibliotekę interfejsu użytkownika). Czuję się jednak zobowiązany napisać tego posta. Głównym powodem jest stan wyżej wymienionej biblioteki - jej struktura, nazewnictwo i podstawowa, niskopoziomowa funkcjonalność jest już ustabilizowana. Wciąż brakuje bezbłędnej obsługi skupienia widgetów za pomocą klawisza TAB, kilku podstawowych klas widżetów, pełnej obsługi skórek i kilku innych rzeczy. Można natomiast z powodzeniem używać biblioteki do tworzenia prostych aplikacji - program PKCASim, czyli Piotr Klos's Cellular Automaton Simulator jest tego świetnym przykładem. Niestety program nie jest jeszcze dostępny, ale pierwsza wersja jest ukończona, więc niedługo go opublikuję.
Rzeczy, które zrobiłem od ostatniego posta dla PKgui:
- ukończenie rozszerzania bibliotegi o możliwość dołączania własnych kontekstów renderowania
- postawienie repozytorium na www.assembla.com, uregulowanie spraw licencyjnych, commit biblioteki
- ulepszenia w nazewnictwie, stosowaniu konwencji, dokumentacji (jest dostępna dokumentacja wygenerowana przez doxygen)
- usunięcie wielu błędów
- funkcjonalność:
-- bitmapowe czcionki, ich wczytywanie i używanie zamiennie z czcionkami TTF, modyfikacje, takie jak zamiana koloru obrazka na inny, a także mechanizm powiadamiania używających font obiektów o zmianach w foncie;
-- gradienty prostokątne w OpenGL
-- ulepszenie loga błędów, umożliwiające jego wyłączenie
-- poprawne skalowanie GUI, wraz ze wszystkimi widżetami
-- dodałem sposób na zarządzanie layoutem (rozkładem) widgetów w kompozycie
- zamiana wszystkich tabów na spacje
- zmiany umożliwiające kompilację najnowszym stabilnym GCC pod linuksem
W sumie dużo się tego nazbierało, ale mimo to GUI pozostaje trochę niedoszlifowane.
W tej chwili uczę się do poprawek i pracuję nad prostym programem, w którym samochodziki będą jeździć po torze myśląc wyewoluowaną siecią neuronową...

PS. Dla zainteresowanych: projekt PKgui ma repozytorium tutaj
http://code.assembla.com/pkgui/subversion/nodes
Niech Cię nie zwiedzie fakt, że wersji PKgui było tylko 42. Projekt dostał repozytorium dopiero ostatnio; gdyby miał od samego początku, wersji byłoby pewnie około 400. W zakładce "Wiki" jest opis projektu i podstawowe instrukcje kompilacji.

wtorek, 30 czerwca 2009

migawka moich zainteresowań

Tak sobie oglądałem nagranie z konferencji w Google na YouTubie
(www.youtube.com/watch?v=ifmZSC8ca6Q) i tą drogą odkryłem zespół Nine Inch Nails. Gorąco polecam. Oto link do aplikacji, za pomocą której można śledzić na bierząco wiadomości wysyłane przez fanów zespołu: http://access.nin.com/
Wykorzystują plugin Google Earth do przeglądarki internetowej, żeby pokazać, skąd pochodzi wiadomość i do różnych innych rzeczy.
To link do strony domowej zespołu: http://www.nin.com/
Rozdają swoją muzykę za darmo! Ściągnąłem w formacie .flac, odtwarzam Winampem i jestem bardzo zadowolony z jakości.

niedziela, 14 czerwca 2009

Bootstrapping automatycznego testowania GUI

Odpoczywam sobie właśnie w Polsce po sesji i myślę o tym, jak można by zabrać się za napisanie zestawu automatycznych testów do mojego systemu GUI. Chodzi konkretnie o to, żeby kod widżetów w trybie debug mógł sprawdzić, czy nadal jest rysowane to, co trzeba. Takie sprawdzanie byłoby bardzo przydatne, a wręcz niezbędne zwłaszcza wtedy, gdy zmieniane są szczegóły implementacji niskopoziomowych komponentów. Wcześniej, gdy struktura GUI ulegała dużym zmianom, robienie testów wymagałoby ciągłego ich zmieniania. Teraz problem nieistnienia zestawów testów daje się we znaki, a zmiany strukturalne GUI nie są znaczące.

Mimo to pisanie ręcznie testów sprawdzających dokładny wygląd GUI nie wydaje się najlepszym pomysłem. Jest to ogromny wysiłek, który mógłby być przeznaczony na coś dużo bardziej produktywnego. Ponadto koszt utrzymania takiego kodu jest ogromny przy najdrobniejszych zmianach wprowadzonych do podstawowych komponentów.

Dużo lepszym wyjściem jest pisanie testów sprawdzających po kilka najbardziej narażonych na niezgodności punktów - rogów, czubków itd. To jest do przyjęcia, jeśli chodzi o ilość potrzebnego wysiłku, jednak niedokładność jest oczywista. Taki kod nie zawsze wykryje, że coś się zmieniło, a o to przecież chodzi w automatycznym testowaniu.

Niezależnie od tego, co obejmują napisane testy, są one narażone na błędy w samych testach. Są możliwe do wykrycia i naprawienia, ale jednak dokładają roboty.

Wpadłem więc na pomysł, aby napisać te wyrywkowe testy, uruchomić je, sprawdzić wzrokowo, czy rysuje się to, co trzeba i zapisać obrazki z wizerunkami widżetów do plików.

Później automatyczny kod testujący mógłby sprawdzać zgodność tego, co się wyrysuje (za pomocą króciutkiego kodu) z tymi obrazkami. W ten sposób, praktycznie nie pisząc kodu do poszczególnych przypadków mam sprawdzanie dokładności rysowania GUI co do piksela, sprawdzanie zmian i automatyczne generowanie testów. Tak, mam automatyczne generowanie testów, bo po każdej poprawce będę mógł wywołać funkcję 'generate_tests', która utworzy mi obrazki ze wszystkimi widżetami. Nie będę musiał zmieniać setek linii kodu, najwyżej kilkanaście, ale tylko wtedy, gdy poprawka będzie usuwała błąd ujęty w zestawie napisanych testów. Ponadto testy obrazkowe są niewrażliwe na błędy w kodzie testującym, zamiast kodu testującego jest bowiem obrazek, skontrolowany wzrokowo wcześniej, podczas tworzenia widżeta (lub późniejszego naprawiania usterki).

Przedstawione rozwiązanie kusi swoją prostotą ale trzeba rozważyć jeszcze kilka rzeczy. Najważniejsze: ogólność. Dla wielu trybów rysowania może być wiele obrazków, które muszą zostać sprawdzone, żeby było pewne, że naprawdę wszystko jest tak, jak trzeba. Jako tryb rysowania można podać rysowanie z wygładzaniem krawędzi lub bez. To stawia pod znakiem zapytania całą metodę, ponieważ rozmiar tych obrazków na dysku może być potężny. Po przyjęciu stosowania odpowiednich, prostych tekstur i kompresowania do formatu PNG będzie znacznie mniejszy, jednak nadal będzie zależny od iloczynu wszystkich sposobów rysowania dla różnych trybów. Rozwiązaniem mogłoby być tworzenie obrazków tylko dla niektórych trybów przy cichym założeniu, że dla wszystkich innych możliwości wszystko będzie w porządku bo są już przetestowane we własnym podstawowym zestawie testów. Można też wybierać różne konfiguracje dla różnych widżetów.

Inny problem: Można zapytać, czy warto utrzymywać zestaw ręcznie napisanych testów dla danego komponentu po upewnieniu się, że rysuje się co do piksela. Napisane testy przechowują wiedzę o tym, co zostało przetestowane dokładnie, a co tylko wizualnie. Co ważniejsze są też kodem, który można łatwo przerobić i wykorzystać do przetestowania po poprawkach konkretnych wartości na rysunku komponentu. Testowanie po zmianach jest niezbędne, więc wydaje się oczywiste, że taki kod powinien być zachowany. Utrzymanie go nastręcza jednak dodatkowego wysiłku. Można go zachować i nie uruchamiać, żeby nie robić sobie kłopotów, jednak wtedy nie będzie gwarancji, że działa tak, jak należy. Wobec takiego stanu rzeczy najlepsze wydaje się zachowanie go i uruchamianie na żądanie wtedy, kiedy trzeba upewnić się, że nadal działa. To rozwiązanie problemu nadal nie jest jednak idealne, bo przy każdej zmianie będzie tworzyć pokusę, żeby nie działający kod testujący po prostu zignorować i wyrzucić, a test oprzeć na sprawdzaniu obrazka.

Jeszcze jedno pytanie wymaga odpowiedzi: Czy traktować obrazki jako testy poprawności, czy tylko jako testy zmian w wyświetlaniu, a do testowania poprawności utrzymywać testy napisane ręcznie. Sugestie mile widziane.

W tym poście trzeba jeszcze wyjaśnić skąd "bootstrapping" w tytule. Wikipedia wyjaśnia, co oznacza to słowo, a ja tylko dodam, że tutaj zostało użyte przez analogię do bootstrappingu kompilatorów. Tak, jak kompilator podzbioru reguł języka X zostaje użyty do napisania kompilatora języka X, tak częściowo przetestowane GUI Y zostaje użyte do wytworzenia pełnych testów do GUI Y.

ś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.

środa, 22 kwietnia 2009

Personal Development Planning

To jest post na temat PDP - Personal Development Planning, czyli Planowania Osobistego Rozwoju. Po co pisać posty na tak niedorzecznie nudne tematy? Wymagają na uczelni. Właściwie to nie wymagają pisania posta na blogu, ale każą napisać "Learning Journal", czyli "dziennik nauki". Co ciekawe, nie ma to być dziennik nauki użytecznej, akademickiej, czy takiej ZZZ, ale nauki o do niedawna kosmicznym tworze, zwanym samoświadomością. Dalej nazywam ja SŚ, nie z sympatii do organizacji o podobnym skrócie, ale z lenistwa do pisania o ludziach i psychologii. Co prawda pisać o SŚ można tylko w kontekście życia, w którym ją się stosuje, więc wymagają, żeby opisywać dowolne inne wydarzenia, ale tak naprawdę skupić się na skutkach dla rozwoju SŚ. Trochę już zajmuję się tym tematem i mam dla czytelnika dobrą radę: Nie czytaj tego! zajmij się czymś pożytecznym, a nie odkładaniem wszystkiego na później.
Mam na to zadanie od teraz około miesiąca, ale muszę zacząć najpóźniej teraz, bo ten utwór ma udokumentować postępy w rozwijaniu SŚ, które powinny być potwierdzone jakimiś dobrze opisanymi przykładami.

Pod wpływem niejasnych, niepraktycznych i tatusiowatych materiałów na stronach internetowych uniwersytetu postanowiłem ustalić sobie jasno i napisać zwięźle to, czego tam nie dopisali: czym jest w praktyce samoświadomość. Inaczej mówiąc, co konkretnie może zostać poprawione przez stosowanie PDP. Myślę, że jest kilka aspektów tego zjawiska, które muszą być poruszone w moim dzienniku:
- ogólna odpowiedzialność, czyli zdolność podejmowania wysiłku wtedy, kiedy to konieczne, bez pozytywnej motywacji;
- umiejętności organizacyjne: ustalanie czasu, kolejności prac, proporcji czasu na różne etapy zadania, dzielenie się zadaniem z innymi itp;
- zdolność efektywnej pracy w grupie, czyli wyniesienie się poza pierwotne instynkty i natychmiastowe emocje i obmyślanie nie tylko CO, ale też JAK to powiedzieć innym, żeby dobrze wykonać robotę;
(jestem pewien, że działalność głowy naszego państwa znacznie podniosła świadomość Polaków na ten temat);
- wiedza o swoich możliwościach, kwalifikacjach, zdrowiu, wpływie życia prywatnego na zawodowe itp;

Wymienię projekty, o których mam zamiar pisać w tym sosie i powody umieszczenia ich w dzienniku.

1. Projekt grupowy InVectorGadget, tworzony z kolegami od kilku miesięcy (teoretycznie od października) w ramach jednego z przedmiotów na uniwerku.
Powody:
- mój pierwszy, naprawdę grupowy projekt - mogę skomentować wzrost umiejętności pracy w grupie;
- mój pierwszy duży projekt nie tworzony z pobudek osobistych - potrzebne umiejętności motywacyjne;
- potrzebna umiejętność planowania długoterminowego;

2. Projekt osobisty PKGUI, tworzony od 2,5 roku, prawie dojrzały (chyba wrzucę go na SourceForge, może ktoś się zainteresuję, zanim będę miał wersję 1.0, choć wątpię).
- wiele się nauczyłem na temat organizacji czasu'
- projekt dał mi umiejętności programistyczne, poznałem więc znaczenie angażowania się w takie rzeczy dla własnego rozwoju;
- rezultat jest pod różnymi względami lepszy, niż to, co widzę w innych GUI, zatem zaraziłem się pasją do niego, mimo to, że nie mam tak naprawdę czasu na jego robienie; nauczyłem się, kiedy podejmować tego typu wyzwania, kiedy nie warto, a kiedy nie można;
- pomógł mi zdecydować, co będę robił w życiu; miał różny wpływ na moją motywację, umysłowe zmęczenie, dał więc wiedzę potrzebną do szacowania swoich (ale też cudzych) możliwości;

Smutne, że muszę spędzać czas na opisywaniu wpływu projektu na mnie zamiast zająć się nim samym i opublikować go. Dwu i pół letni PKGUI zawiera dużo ponad 2 MB kodu, dla porównania InVectorGadget, robiony 8 miesięcy przez 4 osoby ma ok 450 KB. Daje to pojęcie o tym, jakie znaczenie ma dla mnie PKGUI i jak daleko jestem od porzucenia tej idei.

Zakończę na dzisiaj pewnym spostrzeżeniem na temat przedmiotu, na którym wymagają takich rzeczy. Otóż, na Career Management Skills wymagają udowodnienia swoich postępów w kształtowaniu SŚ. Jest to bardzo prywatny temat, temat o którym nie porozmawiałbym pewnie z członkiem rodziny, bo zacząłby zadawać pytania, na które wolałbym nie odpowiadać. Aby udowodnić, że wyciągam wnioski muszę zaznaczyć, co poszło nie tak, komu mam to za złe, dlaczego, czemu się przejmuję niektórymi rzeczami, a innymi nie. Dyrektorka tego przedmiotu nie jest natomiast psycholożką, tylko doradcą do spraw kariery, nie sądzę, żeby obowiązywała ją jakaś oficjalna tajemnica lekarska. Czuję się z tym niekomfortowo. Stwierdziłem, że skoro i tak to mówię, komuś, komu nie chcę, to można by całkowicie ujawnić moje poglądy na tym blogu. Dodatkowo piszę po polsku, więc żadna osoba, którą te informacje będą dotyczyć nie obrazi się na mnie :) Jeśli natomiast któraś z nich czegoś się dowie, to po wakacjach, więc będziemy mieli czas na wyjaśnienie sobie wszystkiego.

wtorek, 21 kwietnia 2009

Sen

Tematem tego wpisu będzie mój wczorajszy sen. Jako że rzadko pamiętam swoje sny, tym razem jest to dla mnie ciekawe wydarzenie. Wczoraj obudziłem się około 7.00, po 6 godzinach snu przez hałasy w domu i mój umysł nadal przetwarzał urojone obrazy.

Śniła mi się moja była szkoła podstawowa. Szedłem sobie po ciemnym, podziemnym korytarzu, jak zwykle szybkim krokiem, wokoło wielki harmider. Przyśnił mi się sklepik szkolny w rogu tegoż korytarza, ten sam sprzedawca, te same czerwone półki i ta słodka bułka, której nigdy nie potrafiłem nazwać. Chciałem ją kupić, zapytałem się więc, jak się nazywa. Otrzymałem wyczerpującą odpowiedź, którą sprzedawca wygłosił z uśmiechem na ustach, lecz nie do końca w moim kierunku, a że wokół był duży harmider, znowu nie usłyszałem, jak się nazywa. Następnie wszedłem na ostatnie (drugie lub trzecie) piętro po schodach i spotkałem przechadzającego się na dyżurze wykładowcę z Uniwersytetu w Bristolu. Najlepsze miało jednak dopiero nastąpić.
Trafiłem przez przypadek do jakiejś klasy, częściowo wyludnionej, z kilkoma uczniami czekającymi w kolejce do biurka nauczycielki. Miałem takie poczucie, jakbym był tam przez pomyłkę, z błahego powodu, chcąc się może o coś zapytać. Nauczycielka z wyglądu była stereotypową podstarzałą babą, z ciemnymi włosami i brzydką mordą. Kiedy odszedł ostatni uczeń podszedłem do niej, a ona spojrzała do wielkiej puszki stojącej na stole. Spojrzałem tam również i zobaczyłem, jak w cienkiej warstwie sosu własnego pływają sobie kawałeczki warzyw, głównie kukurydza. Powiedziała oschle:
- Dzień dobry, no wreszcie!
Nie pamiętam, co jej odpowiedziałem, ale byłem zakłopotany, próbując wytłumaczyć, że ja to nie jestem uczniem tej klasy. Odparła mi niskim głosem i obojętnym tonem, pasującym do niej, ale nie do treści wypowiedzi:
- Co pan mi tu mówi, przecież tu jest wyraźnie napisane. - Powiedziała, wskazując palcem trzy ziarnka kukurydzy, unoszące się samotnie prze ciemnym, śliskim brzegu puszki.
Poczułem wstyd. Czułem, że robię się czerwony. Zacząłem panikować, że zapyta mnie o jakiś materiał. Patrzyła na mnie z obrzydzeniem. Zaczęła.
- Proszszsz. Podstawy współczesnej kosmologii.
Przez chwile gapiłem się do góry, próbując coś przyciągnąć do głowy, po chwili zaś spojrzałem na dziennik, który trzymała i zobaczyłem, jak wpisuje "ndst.".

poniedziałek, 20 kwietnia 2009

Paranoiczna Biblioteka Standardowa Java.

Nie mam ostatnio czasu na wpisy, choć jak nie ma czasu, to oznacza, że dzieje się najwięcej ciekawych rzeczy. Niestety, takie życie. Ostatnio przeglądam sobie kod źródłowy biblioteki stardardowej Javy i napotykam na różne kwiatki. Już dawno zdałem sobie sprawę, że moja decyzja o stworzeniu własnej biblioteki GUI była pójściem z motyką na słońce, a to, co wyczytuję w dziełach programistów z za oceanu ostatecznie już dobija mnie i rozgniata. Nie dość, że implementacja nie jest okomentowana i nie można tam nic wyczytać, w niemal każdej klasie spotyka się coś w stylu "this is a workaround...", to jeszcze autorzy sami do końca nie zdaje sobie sprawy, po co piszą to, co piszą.
Przeglądam sobie klasę ToolTipManager i w metodzie showTipWindow() widzę takie coś:

// Just to be paranoid
hideTipWindow();

Z tej okazji wszystkim programistom GUI życzę z całego serca pięknych partnerek, dbających paranoicznie o ich zdrowie psychiczne.

środa, 8 kwietnia 2009

Jacek Utko - TED talk

Poruszyła mnie i zainspirowała do działania konkluzja wystąpienia projektanta gazet, Jacka Utko na konferencj TED, dostępnego pod tym linkiem.
http://www.ted.com/index.php/talks/jacek_utko_asks_can_design_save_the_newspaper.html

"You can live in a small, poor country, like me, you can work in a small company, in a boring branch, you can have no budgets, no people, but you can put your work to the highest possible level. And everybody can do it. You just need an inspiration, vision and determination. And to remember that to be good is not enough."

Nic do dodania (poza lekką niezgodą z "small, poor country" :) ).

wtorek, 17 marca 2009

reszta językoprotokołu

To ciekawy temat. Miałem jeszcze wiele przemyśleń ale nie mogę ostatnio znaleźć czasu, żeby to wszystko napisać. Z drugiej strony zależy mi też na spisaniu tych rzeczy, bo to może się przydać, po pewnych modyfikacjach, jako pomysł na biznes. Jeżeli komuś spodobałby się pomysł, to zapraszam do dyskusji. Po to publikuję to na blogu, żeby zabrać jakieś opinie. Ale do rzeczy.
Zakładając, że problemy z doborem alfabetu liter i głosek zostały rozwiązane, należy jeszcze określić reguły tworzenia słów. Oczywiście każdemu, kto miał do czynienia z nauką obcego języka przyszłyby do głowy różne sposoby, np. tworzenie innego słowa przez dodanie końcówki do starego. To jednak tylko część historii, bo tradycyjne sposoby nie gwarantują spójności języka wystarczającej dla maszyn.

Trzeba by było zidentyfikować reguły tworzenia słów, które umożliwiałyby spójne utworzenie całego języka.
Pierwsza reguła: żeby nie było sytuacji takiej, że słowo tworzone dla jakiegoś znaczenia, na podstawie innych, istniejących słów może mieć nadane dwa różne ciągi znaków.
Na przykład w języku polskim mamy niejednoznaczne reguły tworzenia słów dla wynalazków przychodzących z zagranicy. Dla znaczenia 'komputer' można by utworzyć słowo "obliczacz", ale też można by wziąć słowo "computer" i spolszczyć je i mówić "komputer". Mamy więc dwie reguły, które prowadzą do nazwania tego samego znaczenia, co w jezykoprotokole spowodowałoby większą niedeterministyczność języka, a zatem zmieszanie i powolniejszą naukę u ludzi, i odcięłoby kolejny sposób automatyzacji rozwiązań w komputerach.
Zakładając, że udałoby się opracować dobre reguły tworzenia słów od istniejących, to które ma być tworzone od którego? Jeżeli przyjmiemy np. regułę tworzenia słowa o znaczeniu przeciwnym przez dodanie przedrostka 'mal', jak w Esperanto, to nadal jest problem, a mianowicie: czy mówić "zły" i "malzły", czy "dobry" i "maldobry". Trzeba by było np. przyjąć, że jest wybierane to ze znaczeń przeciwnych, które oznacza, że czegoś jest więcej, a jeśli to się nie nadaje, to wybieramy znaczenie uznawane za bardziej pozytywne (uzyskalibyśmy "dobry" i "maldobry"). Nie wierzę, że udałoby się wyodrębnić pozbawione uznaniowości reguły wybierania znaczeń. Obawiam się, że jest to zupełnie niemożliwe, ale można by pewnie podjąć próbę i objąć jasnymi regułami większość języka.
Druga reguła tworzenia języka brzmiałaby więc: dla każdego znaczenia powinno dać się jasno stwierdzić, czy przyporządkowane mu słowo będzie autonomiczne, czy utworzone od innych.

Można by iść w tych rozmyślaniach dalej w stronę opisania struktury procesu tworzenia słów. Gdyby wyobrazić sobie drzewo decyzyjne, które służyłoby na nadawania znaczeniom słów, można by określić, w jaki sposób to drzewo powinno być rozszerzane. Jeżeli ten proces miałby być zautomatyzowany (kusząca perspektywa), to pozostaje też pytanie, jakiego kształtu miałyby być dane wejściowe do tego drzewa. Oczywiście musiałyby to być znaczenia, ale jak byłyby opisane, i jak opisane byłyby relacje między nimi? Jeżeli w języku ludzkim (a do pewnego stopnia tak musiałoby być), to mamy problem jajka i kury, bo do ich opisania trzeba by było opracować sposób reprezentacji podobny do językoprotokołu.
A to na razie tylko słowotwórstwo...
Jeszcze gramatyka (w rozumieniu - "jak użyć razem kilka słów, żeby coś przekazać"). Pewnie musiałaby być podobna do gramatyk języków ludzkich, ale z drugiej strony oparta na znaczeniach. Znam kilka języków programowania, których gramatyki muszą być siłą rzeczy silnie powiązane ze znaczeniami i widzę, że podobieństwo do języka ludzkiego mogłoby być zupełnie nieosiągalne, w przeciwnym wypadku kod źródłowy wyglądałby jak tekst. Jak w językoprotokole poradzono by sobie z grupowaniem znaczeń nawiasami? Wyobrażam sobie, że można by wprowadzić krótkie spójniki o znaczeniu "począwszy od.." i "..skończywszy", więc nie byłoby to znowu takie nieintuicyjne, ale im więcej takich "nieludzkich" elementów, tym mniej atrakcyjny byłby język.

Gdyby nie głębokość powyższych trudności i duże prawdopodobieństwo podjęcia błędnej decyzji projektowej na początku, można by pokusić się o spisanie reguł i stworzenie internetowego systemu tworzenia tego języka, gdzie ludzie sami wkładaliby znaczenia i tworzyli słowa. Mogłoby się to komuś przydać z powodów wymienionych w poprzednim poście.
Może jak się trochę poduczę gramatyk...

wtorek, 10 marca 2009

językoprotokół człowiek-komputer

Uczyłem się metod modelowania danych i natknąłem się na "method of least squares". Pomyślałem sobie "a jak to nazywają Polacy". Otworzyłem więc miłościwie nam panującą Wikipedię i przez linka do polskiej wersji po lewej doszedłem do "metody najmniejszych kwadratów". Ucieszyłem się niezmiernie bo to jedno wyrażenie mniej do nauki. Fajnie by było, gdyby wszystkie wyrażenia i słowa dało się tak dosłownie przetłumaczyć. Potem jeszcze porozmyślałem o problemach w tłumaczeniach i stwierdziłem, że całe trudności wynikają z wieloznaczności i pokrywania się znaczeń słów. Tak doszedłem do wniosku, że bardzo przydałby się język, w którym każde słowo ma jedno znaczenie i każde znaczenie ma jedno słowo. Ale, czy taki język możnaby było utrzymać jako działający w społeczeństwach? Na pewno nie, bo ludzie uwielbiają wymyślać wiele znaczeń dla tego samego słowa, jeżeli więc jakieś jest używane, to prędzej czy później je zepsują. Na tym jest oparta na przykład cała poezja. Wiele znaczeń dla danego słowa oznacza duże prawdopodobieństwo wystąpienia kilku słów dla tego samego znaczenia, bez czego wiersze nie mogłyby być pisane. Pomyślałem nawet, że możnaby wprowadzić pewien standard, określający jakie słowa są oficjalnie używane w pismach urzędowych, czy publikacjach akademickich, jednak to nasuwa zbyt dużo skojarzeń z Orwellem i jego powieścią 1984, gdzie inna idea upraszczania języka (zwana newspeak), prowadząca do zmuszania ludzi do używania pewnych słów zamiast innych jest przykładem represji chorego systemu. Byłoby to istotnie ograniczenie wolności słowa.
Ten fakt zaprowadził mnie do konkluzji, że najlepiej byłoby wykorzystać tę ideę do stworzenia sposobu komunikacji z maszynami, który byłby również w rozsądnym stopniu wygodny dla ludzi.
Przykład 1.
Można by było wydawać głosem skomplikowane rozkazy robotom, które przecież stają się coraz bardziej inteligentne.
Przykład 2.
Zastosowanie bardziej na dzisiejsze czasy, to wykorzystanie w automatycznych translatorach. Przykład: ktoś znający taki język napisałby w nim tekst, następnie ten tekst można by było automatycznie przetłumaczyć na 180 języków (a właśnie, że nie byłoby dużo błędów!) i opublikować na stronie internetowej.
Przykład 3.
Można nawet wyobrazić sobie urządzenie, które służy do rozmowy dwóch ludzi o dowolnych językach. Jak by działało?
Mamu dwóch rozmówców: Pierwszy (P) i Drugi(D).
P coś mówi. Urządzenie wysłuchuje wypowiedziane zdanie i dla każdego słowa, które może mieć więcej niż jedno znaczenie pokazuje P wszystkie znaczenia i każe wybrać. Następnie korzystając z uzyskanych znaczeń tłumaczy zdanie na językoprotokół, z językoprotokołu tłumaczy na język Drugiego i mówi mu (lub pokazuje) rezultat. Analogicznie w drugą stronę. Wreszcie ludzie mogliby się porozumiewać!! Warto zauważyć, że to powyżej nie mogłoby zadziałać między dowolnymi językami, gdyby nie było sporządzonej listy znaczeń i powiązanych z nią przyporządkowań:
(słowo w języku P) - (znaczenia), oraz
(znaczenie) - (słowo w języku D). Oczywiście to wciąż dosyć idealistyczny schemat, według którego dla danego znaczenia wystarczyłoby wziąć dowolne słowo w języku D.
Zakładając jednak, że znaczenia są wystarczająco atomowe, dałoby się dojść dosyć blisko do tego ideału.

W powyższym przykładzie nr 3 istnienie wymawialnego przez ludzi językoprotokołu wydaje się niekonieczne - znaczenia możnaby na przykład reprezentować kolejnymi liczbami naturalnymi. Nie jest to jednak takie oczywiste, bo jak, nie oferując atrakcyjnego językoprotokołu, skłonić kogokolwiek do spisania wszystkich znaczeń słów, istniejących na Ziemi? I w jakim języku to zrobić? Jeżeli zrobiłoby się to np. po angielsku, to czy rezultaty takiego spisu znaczeń byłyby wystarczająco atomowe? Czy ludzie postrzegający słowo mylnie jako jedno znaczenie (ludzie chyba dążą do myślenia o słowach w ten sposób) nie sprawiliby kłopotu znajomym z Etiopii, którzy mają na te dwa znaczenia dwa różne słowa? A przecież Etiopczyków jest mniejszość, a jeszcze mniej ma dostęp do komputera, więc kto by ich usłyszał?

Oczywiście słownictwo to nie jest cały język, jest jeszcze gramatyka, słowotwórstwo i inne. Wbrew pozorom słowotwórstwo to problem osobny od słownictwa - jakie brzmienie nadać danemu słowu, jak to nadawanie brzmienia uzależnić od brzmienia istniejących słow. Pozostaje jeszcze wyodrębnienie zbioru głosek składających się na językoprotokół - wszystkie muszą być wymawialne przez ogromną większość ludzi na świecie. Nie może być np. 'l' i 'r' - Japończycy nie widzą różnicy. Jeżeli to samo zastosuje się do innych par dźwięczna - bezdźwięczna, np. 'k' i 'g', 's' i 'z', to taki język byłby jeszcze większym bełkotem, niż język angielski wymawiany przez niektórych Anglików. Można by nawet zaryzykować i zostawić te rozróżnienia, bo jeśli kiedykolwiek ktoś chciałby porozumieć się z innym czlowiekiem za pomocą językoprotokołu i powiedziałby "lagas", a drugi znałby to słowo jako "rakaz", to niezrozumieliby się. Gdyby jednak słuchała maszyna, to lepiej by było, żeby nie było tych rozróżnień, żeby komuś, kto ma wadę wymowy nie wychodziło ciągle "lakas", podczas gdy chodzi mu o "lagas", które miałoby inne znaczenie.
Dosyć tego. W następnym poście przemyślenia o gramatyce i słowotwórstwie.

wtorek, 24 lutego 2009

pora wreszcie zacząć pisać!

Pora wreszcie zacząć pisać na temat rozwoju kariery i samoświadomości.
Przedmiot, który o tym jest (Carier Management Skills) zaczął się na początku semestru, ale nie mogłem się jakoś skłonić do skrobania tego wszystkiego, mimo to, że miałem sporo przemyśleń. Wykładzik sprzed 5 minut skłonił mnie jednak do wykonania tego zadania. Tak dla porządku, wykład dotyczył tego, jak nie pisać listu motywacyjnego i jaka jest pełna lista tych rzeczy, których szukają pracodawcy u pracowników. Było też kilka praktycznych wskazówek na temat organizacji kariery. Czemu takie nudne rzeczy są takie przydatne? Właściwie to nie wiem, czy takie nudne, bo tak naprawdę jeszcze nie próbowałem porządkować tych spraw.
Tylko od czego zacząć? Może od wykładu nr 1 :)
Był bardzo ciekawy.
Pytanie ze slajdu: co chcesz osiągnąć na tym przedmiocie?
I kilka możliwych odpowiedzi:
"Zdecydować o karierze." Zdecydowanie nie. Jak zdecyduję o karierze podczas drugiego roku studiów, to wyląduję w jakiejś dziurze, robiąc coś, co jest zaledwie w miarę w porządku. Moment ostatecznej decyzji należy odwlekać jak najdłużej, żeby zostawić sobie mośliwości. Trzeba natomiast śledzić, co jest dostępne, co jest na czasie, na co jest popyt, a na co nie i robic to, co naprawdę się lubi.
"Aplikować, albo mieć rozmowę o pracę" W zasadzie to mi wszystko jedno, jeśli rozumieć to tak, że dla samego faktu aplikowania podejmuję się tego przedmiotu. Oczywiście dałoby mi to jakieś doświadczenie, ale nie ma to ogromnego znaczenia, bo i tak pewnie albo będę się samozatrudniał, albo gdzieś wskoczę przez jakiś projekt open source, albo ktoś mnie zarekomenduje, a najważniejsze będą i tak kwalifikacje (co do których mam duże plany). Głupi nie jestem, i podążając za poradami ze slajdów jestem w stanie napisać dobre CV, list i poopowiadać o rzeczach które mnie pasjonują na rozmowie (a jak praca nie będzie pasjonująca, to, jak mam nadzieję, będę mógł poszukać innej, a jak pracodawca nie widzi pasji, to i tak nie zatrudni). Chciałbym gdzieś aplikować, jeśli znalazłaby się płatna (nie koniecznie miliardy :) ) praca, która mi coś da, nie tylko będzie polegała na zrobieniu czegoś, czym nikt (łącznie ze mną) nigdy nie będzie się przejmował, albo polegająca na wykonywaniu czynności, które zaprojektowany przeze mnie na kolanie robot wykonywałby lepiej i taniej.
"Zabezpieczyć sobie pracę po studiach albo latem" Co do pracy po studiach, patrz punkt pierwszy. Co do pracy latem, jak najbardziej tak, ale nie będę wysyłał CV do "makdonaldów". Lepiej już zająć się w tym czasie jakimś projektem open source, który polepszy moje CV i pozwoli na lepiej płatną pracę w przyszłości. Tak na marginesie, mam kilka własnych pomysłów, ale mogę też rozważyć podłączenie się do czegoś większego, np. do rozwijania Code::Blocks.
"Opracować i zrobić swój własny plan samozatrudnienia" Zdecydowanie tak. Jest kilka kontaktów na stronie internetowej CMS. Mam zamiar ich użyć, żeby dowiedzieć się, jak to jest prowadzić, mieć, pracować w, rozwijać działalność w dziedzinie IT. Pozadaję kilka pytań kilku przedsiębiorcom, którzy zgodzili się służyć pomocą studentom na tym przedmiocie. Tak na dobry start. Oczywiście na tym blogu nie zostaną opublikowane żadne materiały, które nie pochodzą ode mnie, napiszę jednak ogólnie, czego się nauczyłem, bez wymieniania żadnych nazw własnych. Spróbuję również zadać kilka pytań mojemu tacie, od którego wiem już sporo, ale tak naprawdę nie wiem, co od niego wiem :)
Mam nadzieję, że będzie mnie trochę wspierał w tej sprawie, choć nieczęsto się ostatnio widzimy.
(Zachciało się cholera emigracji edukacyjnej! Najlepszy sposób na skomplikowanie życia.)
Może to wygląda, jakbym miał nie wiadomo jakie mniemanie o sobie, nie wiem, może praca kelnera albo sklepikarza czegoś by mnie nauczyła, ale nie chcę marnować życia. Ludzie powinni w 21 wieku sterować robotami, wcikać guziki i opalać się na Hawajach, a nie szorować podłogi nie mogąc patrzeć na ziarnko piasku i narzekać, że marnują życie. Im więcej ludzi to zrozumie, tym lepiej. Jak to się znacząco nie zmieni w ciągu kilkunastu lat, to chyba założę partię technokratyczną.

W (którymś) następnym poście kontynuacja CMS, mam nadzieję, że już z pewnymi wynikami.

sobota, 14 lutego 2009

rastrowo wektorowy motywacyjny kop

Piszę sobie ostatnio (formalnie od września 2008 :) ) program z kolegami na uczelni. Stwierdziliśmy, że ma to być program graficzny, żeby odróżnić go od wytworów poprzedniego rocznika, ale nie bardzo wiedzieliśmy, co wymyślić, żeby było oryginalnie, więc doszliśmy po nitce (z niewidzialnej szaty cesarza) do kłębka w postaci "edytora grafiki wektorowej on-line". Wszystko by było pięknie, gdyby to była jakaś gra albo jakieś fajne narzędzie akademickie, zawierające jakieś ciekawe algorytmy, ale grafika wektorowa? Nie muszę dalej tłumaczyć, że nie byłem tym zachwycony. Stwierdziłem, że pomysł ma spory potencjał (i na razie tylko potencjał) i może później znajdę jeszcze jakąś konkretną motywację do pisania tego narzędzia dla trzynastolatków (tak, oksymoron).
I znalazłem!
Poza kilkoma pomysłami na uczynienie z tego programu czegoś przytępnego, o których nie będę się tu teraz rozpisywał, planowałem stworzenie konwertera grafiki rastrowej na wektorową. Uzasadnienie jest oczywiste: dziwnym trafem zwabiony trzynastolatek, nie mający zielonego pojęcia o tym, czym jest grafika wektorowa zacznie gwałtownie próbować różnych przycisków w menu, aż w pewnym momencie ustrzeli "load image" i nagle odkryje, że może tam załadować zdjęcie tatusia po pijaku, wyciąć brutalnie tułów delikwenta i wkleić na dziób Titanika. Do tego wszystko w stylu kreskówkowym.

Działanie tej konwersji, choć jeszcze niedoszlifowane, zrobiło duże wrażenie na kumplach z teamu. W następnym poście opiszę dokładnie algorytm, którego użyłem. Może komuś się przyda. Choć raczej nie byłoby to odkrycie roku dla zaawansowanego informatyka, to jest taki efektowny drobiazg, który daje motywacyjnego kopa, jak uda się go zaimplementować.
Do zobaczenia!

moja strona

A tak dla uzupełnienia pierwszego posta, zapraszam na moją stronę domową.
klosio.neostrada.pl
Jeśli ktoś ma jakiekolwiek spostrzeżenia na temat mojej strony, proszę o komentarz tutaj.

wtorek, 3 lutego 2009

(jakiś nudny, typowy tytuł pierwszego posta)

Ten blog powstał z czystego, chorego poczucia obowiązku, wynikającego z nacisku na samoświadomość, który z czystą, obopólną przyjemnością serwuje mi od tego semestru moja uczelnia. Prawdopodobnie nikt nie potrzebuje tego czytać, więc z góry witam wszystkich, którzy tu kiedyś wejdą z czystego podglądacwa, po przeczytaniu jakiegoś posta, który rzeczywiście im się przyda. Miłego czytania.