Dodatki do koduKomentarze umieszczamy w kodzie, aby opisać jego działanie. Są one przeznaczone wyłącznie dla osób czytających go i jedynie programy typu javadoc czy doxygen - służące automatycznemu generowaniu dokumentacji - mogą się niektórymi komentarzami interesować. Na pewno jednak nie robi tego kompilator.
Wymyślono jednak, że niektóre elementy kodu potrzebują innych, specyficznych "komentarzy", przeznaczonych dla kompilatora właśnie. Różnie się one nazywają w różnych językach, ale ich głównym celem jest przekazanie dodatkowych informacji odnośnie klasy, metody, typu czy innego elementu programu, bez potrzeby stosowania.
W .NET takie dodatki nazywa się atrybutami i umieszcza przed wybraną deklaracją, w nawiasach kwadratowych (lub kątowych w przypadku Visual Basica), oddzielone przecinkami. Atrybuty te mogą dotyczyć właściwie wszystkiego, począwszy od wskazania na klasę, która może być serializowana (i pola, które nie powinny być) po informacje dla Form Designera na temat danej właściwości niestandardowego komponentu:
Ogólnie dotyczą one jednak różnych funkcji samej platformy .NET i służą wskazaniu, które elementy pełnią określone role w różnych rozwiązaniach, które działają w jej ramach. Można aczkolwiek definiować także własne atrybuty, a potem w czasie działania programu wydobywać o nich informacje przy pomocy mechanizmu refleksji.
A jak to wygląda w Javie? Otóż tam od wersji 1.5 istnieją adnotacje. Ich nazwy poprzedza się znakiem @ i umieszcza w osobnych linijkach, poprzedzających deklaracje, których dotyczą. Ponieważ tutaj język jest ściśle związany z platformą (maszyną wirtualną Javy), adnotacje czasami pełnią funkcje "brakujących" słów kluczowych lub dyrektyw dla kompilatora. Typowy przykład to adnotacja Override:
którą możemy oznaczać przesłonięte wersje metod wirtualnych. Jest to praktyczne, gdyż w przypadku popełnienia błędu (np. literówki w nazwie) kompilator ostrzeże nas, że tak naprawdę zdefiniowaliśmy zupełnie nową metodę (bez tego błąd objawiłby się dopiero nieprawidłowym działaniem programu).
Naturalnie, możliwe jest też tworzenie własnych adnotacji oraz pobieranie informacji o nich przy pomocy refleksji. Aż korci, żeby sprawdzić, kto od kogo ściągał tutaj pomysły ;-)
W C++ deklaracje standardowo nie mają żadnych "ozdobników", ale pod tym względem w różnych kompilatorach bywa różnie. Na przykład w Visual C++ mamy słówko __declspec, które służy do całego mnóstwo różnych celów. Wśród nich są chociażby takie oto warianty:
__declspec(align(n)) służy do określania, jak dane (np. pola struktur) mają być wyrównane w pamięci. Dzięki temu będą one umieszczone tak, by zajmowały zawsze wielokrotność podanych n bajtów, co przy odpowiedniej wartości (np. 32) może zwiększyć wydajność lub (dla 1) zmniejszyć zajętość pamięci.__declspec(deprecated) pozwala oznaczyć dany element kodu jako przestarzały. Jego użycie będzie skutkowało wtedy ostrzeżeniem kompilatora.__declspec(dllexport) i __declspec(dllimport) służą do tworzenia symboli eksportowanych w bibliotece DLL i do importowania tych symboli w innym programie.__declspec(property) wprowadza konstrukcję właściwości do klasy, bardzo podobną do tych obecnych w Delphi. Po podaniu jednej lub dwóch metod dostępowych (do odczytu i ew. zapisu), otrzymujemy właściwość o danej nazwie i typie. Jaka szkoda, że to nieprzenośne :)Zasadniczo Visual C++ posiada też atrybuty podobne do .NETowych, które są konieczne do tworzenia interfejsów COM. Na szczęście nimi, jak i samym COM-em, nie trzeba już sobie zaprzątać głowy :)
Wyrazy obce i ich odmianaKilka dni temu doczekałem się w końcu materiałów w IV Ogólnopolskiej Konferencji Inżynierii Gier Komputerowej, która odbyła w Siedlcach w kwietniu zeszłego roku. W ich skład wchodzą między innymi teksty referatów, jakie zostały tam wygłoszone. Wprawdzie wśród nich nie ma tym razem żadnego referatu mojego autorstwa, ale i tak były one bardzo ciekawe ;-)
Przeglądając je, zauważyłem też, że reprezentują one całkiem niezły poziom językowy. Nie jest to oczywiście sprawa najważniejsza (w końcu o wiele istotniejsza jest zawartość merytoryczna), ale brak dbałości o poprawność dość często idzie w parze z niską jakością tekstu także według innych kryteriów. Wciąż zresztą zdarzają się pojawiać na rynku książki informatyczne, których redaktorzy "położyli" sprawę niemal pod każdym względem: od tłumaczenia po korektę.
Odpowiednie tłumaczenie to często - w przypadku publikacji z tej branży - decyzja, które terminy pozostawić w oryginalnej formie. Akurat w przypadku programowania gier bardzo dużo z nich nie tylko jest używanych wyłącznie w formie angielskiej, ale wręcz nie ma dobrych polskich odpowiedników (jako najlepszy przykład zawsze podaję 'shader'). To sprawia, że teksty o tej tematyce są prawie zawsze naszpikowane obcojęzycznymi wyrazami, które jeszcze często podlegają odmianie tak samo, jak inne słowa. A to rodzi mnóstwo problemów natury ortograficzno-edytorskiej, jakich można uniknąć, jeżeli pamiętamy o kilku zasadach:
Nie są to jak widać specjalnie skomplikowane reguły, a stosując się do nich, powiększamy coraz bardziej zagrożony obszar poprawności językowej w Internecie i nie tylko.
Z unikodem lub bezUnicode to ciekawy wynalazek. Zamiast stosować wymyślne sposoby na "przełączanie" sposobu interpretowania zwykłych 8-bitowych znaków, ktoś mądry wymyślił po prostu, że obecnie nie ma większych przeciwwskazań, aby zwykły tekst zajmował dwa razy więcej miejsca niż dotychczas. Powstał więc standard UTF-16, w którym stron kodowych nie ma, a każdy znak jest zapisany za pomocą jednego z 65536 kodów.
Ale jak to zwykle bywa z rozwiązaniami, które mają rozwiązywać istniejące problemy, Unicode natychmiast stworzył swoje własne :) Oprócz tego, że założone 16 bitów szybko okazało się za małe (stąd istnienie także UTF-32), powstał też szereg kłopotów praktycznych. Jednym z nich jest choćby to, że żyjemy w okresie przejściowym (który zresztą trwa już wybitnie długo) i że w użyciu jest zarówno unikod, jak i zwykłe ANSI. A na pierwszy rzut oka (ludzkiego i programowego) tekst jest po prostu ciągiem bajtów i bez zewnętrznych wskazówek nie jest możliwe określenie w stu procentach, czy został on zapisany w ANSI, UTF-8, UTF-16 czy UTF-32. Co więcej, znaki Unicode są oczywiście liczbami, a ponieważ zasadniczo zajmują one więcej niż jeden bajt, pojawia się problem z ustaleniem właściwej kolejności tych bajtów (little-endian lub big-endian).
Oba te problemy ma rozwiązywać tzw. znacznik porządku bajtów (Byte Order Mark), ale oczywiście jak większość dobrych praktyk, także i jego umieszczanie na początku dokumentów nie jest zbyt popularne :)
Z programistycznego punktu widzenia sprawa nie wygląda aczkolwiek aż tak źle i w większości przypadków jesteśmy w jednej z dwóch sytuacji. Pierwsza z nich to "nieświadome" korzystanie z unikodu (czy może raczej "szerokich", dwubajtowych znaków), bo został o niego oparty używany przez nas język oraz platforma; najlepszymi przykładami są tu .NET i C# oraz Java.
Druga sytuacja to możliwość wyboru, z jakiego systemu będziemy korzystali. Bardzo dobre jest to, że prawie zawsze możemy zdecydować się na... oba, czyli potencjalne kompilowanie dwóch wersji: ANSI i Unicode. Pod Windows na przykład w programach pisanych w C++ wystarczy przestrzegać kilku prostych i dobrze znanych zasad:
char (lub wchar_t) należy - wszędzie tam, gdzie chodzi nam o znaki - używać typu TCHAR, który w zależności od wersji zostanie zamieniony na jeden z tych dwóch.TEXT (czyli TEXT("Coś") zamiast po prostu "Coś"), dzięki czemu zostaną one skompilowane jako łańcuchy ANSI lub Unicode.Niestety, słowo 'niektóre' sytuuje się dość daleko od 'wszystkie' i dlatego ostatecznie nie jest tak różowo. Czołowe miejsce na liście "niewspółpracujących" zajmuje standardowa biblioteka C++. Z nią trzeba sobie poradzić we własnym zakresie.
Nie jest to aczkolwiek bardzo trudne, jako że każdy kompilator definiuje makro dla rozróżnienia wersji ANSI i Unicode. Visual C++ na przykład włącza w tym przypadku symbol _UNICODE, którego możemy użyć do stworzenia odpowiednich aliasów:
Możemy je umieścić we własnym pliku nagłówkowym i dołączać we własnych projektach. Ponieważ jednak typów zależnych od znaków jest w STL całkiem sporo, można z powodzeniem użyć chociażby rozwiązania zamieszczonego na CodeProject, w razie potrzeby rozszerzając je o kolejne aliasy.
Znikające ikonki zasobnikaNie ma systemów bezproblemowych, więc po kilkutygodniowym "miodowym" okresie z Vistą zdarzył mi się w końcu pewien drobny problem. Nie był on specjalnie kłopotliwy i w gruncie rzeczy należał do zabawnych... gdyby nie to, że zdecydowanie zbyt dużo działo się tu samo.
Zacznijmy od tego, że - jak powszechnie wiadomo - w zasobniku systemowym (system tray) widoczne są między innymi ikonki dotyczące dźwięku i głośności oraz sieci i łączności. Ta pierwsza pokazuje z grubsza aktualną głośność - lub ewentualne wyciszenie, zaś druga stan sieci i jej aktywność. Dobrze jest więc mieć je na wierzchu.
Dlatego też niespecjalnie spodobało mi się, gdy pewnego dnia podczas uruchamiania systemu nie pojawiły się one na pasku tak jak zwykle. Ponieważ ich widoczność można kontrolować, otworzyłem okienko Właściwości paska zadań, lecz ku mojemu zdziwieniu odpowiednie pola wyboru okazały się nie tylko odznaczone, ale też... nieaktywne.

Oczywiście standardowe magiczne inkantacje stosowane w takich wypadkach - czyli restart systemu oraz sprawdzenie, czy wszystkie aktualizacje są zainstalowane - nie przyniosły rezultatu. Podobnie konsultacja z bardziej doświadczonymi użytkownikami systemu (cześć Asmodeusz :)) - głównie dlatego, że perspektywa przywracania stanu komputera sprzed tygodnia nie przedstawiała się szczególnie zachęcająco :)
Tym czego nie zrobiłem, było przeszukanie zasobów Internetu w poszukiwaniu rozwiązania. Okazało się to jednak zbytecznie, że problem ten naprawił się sam, i to nawet nie bardzo wiadomo kiedy. Przypadkiem zajrzałem po prostu ponownie do okienka Właściwości paska zadań i menu Start, żeby stwierdzić, iż pola wyboru Głośność i Sieć są wprawdzie nadal oznaczone, ale już jak najbardziej dostępne.
Z jednej strony to dobrze, że problemy które pojawiają się nagle i nie wiadomo skąd, nie wymagają samodzielnego rozwiązywania. Z drugiej strony wypadałoby wiedzieć, jakie są ich przyczyny. Tego nie udało mi się ustalić, ale wykonana poniewczasie analiza wyników wyszukiwania w sieci wykazała, że w razie nawrotów choroby należy wykonać następujące kroki:
IconStreams oraz PastIconStreams, aż szukana fraza nie będzie już występowała w Rejestrze.Cóż, jeśli genialna Vista potrafiła to wszystko wykonać z własnej inicjatywy, to wypada tylko być pełnym podziwu :) Podejrzewam jednak, że zarówno w tajemnicze pojawienie się, jak i zniknięcie problemu, zamieszane są nieznane siły wyższe, których pochodzenia nigdy nie poznamy. Są po prostu takie rzeczy, które się nie śniły filozofom i informatykom - zwłaszcza w odniesieniu do Windows ;P
Własności właściwościNiezastąpionym rodzajem składników klas są pola i metody, ale większość języków umożliwia też dodawanie również innych elementów. Ich głównym przeznaczeniem jest ułatwianie życia programiście i czynienie kodu bardziej czytelnym - pod takim rzecz jasna warunkiem, że są one odpowiednio użyte.
Do tej szuflady wpadają na przykład właściwości. Są to takie składniki klas, które wyglądają jak zmienne, lecz w rzeczywistości za pobieraniem i ustawianiem ich wartości może kryć się bardziej skomplikowany kod niż tylko proste odwołanie do zmiennej.
Spośród mainstreamowych języków prawdopodobnie najwygodniejszy mechanizm właściwości występuje w C#:
Ważną cechą właściwości jest też to, aby możliwe było tworzenie takowych w wersji tylko-do-odczytu. Tutaj wystarczy pominąć frazę set.
Dla kontrastu w Javie właściwości nie ma... w ogóle :) Mimo to narzędzia do wizualnego tworzenia aplikacji radzą sobie całkiem nieźle w odczytywaniu funkcjonalności komponentów, posługując się tzw. JavaBeans. W skrócie jest to pewien mechanizm oparty na refleksjach (odczytywaniu informacji o klasie w kodzie programu) i specyficznej konwencji nazywania metod dostępowych. Oczywiście nawet najlepsze nazwy nie zrekompensują dziwnej składni takich "właściwości", ale sam pomysł trzeba uznać za dosyć udany.
W Delphi w zasadzie też trzeba tworzyć metody dostępowe, lecz można je podpiąć pod faktyczne właściwości:
Możliwe jest też, jak widać, bezpośrednie przełożenie właściwości na odpowiednią zmienną, która przechowuje jej wartość. Całkiem niezłe, chociaż wymaga to sporo pisania - co aczkolwiek jest charakterystyczną cechą Delphi :)
A cóż z naszym ulubionym językiem, czyli C++? Właściwości w nim oczywiście nie ma, chociaż w Visual C++ na przykład istnieje deklaracja __declspec(property), mająca podobne możliwości do słówka property z Delphi. Jeśli zaś chodzi o przenośne rozwiązanie, to można sobie wyobrazić obiekt "opakowujący" wskaźnik na pole lub metodę, który działałby jako symulacja właściwości - na przykład:
Przy użyciu kilku sztuczek z szablonami, wspomnianymi wskaźnikami i być może jakimś rozwiązaniem dla delegatów, taka implementacja jest zapewne możliwa. Istnieje aczkolwiek dość poważna niedogodność: taki obiekt opakowujący należałoby zainicjować w konstruktorze:
zatem "deklaracja" naszej "właściwości" rozbita by została na dwa miejsca. A właściwie - na co najmniej dwa miejsca, bo w przypadku większej ilości konstruktorów rzecz wygląda nawet gorzej.
Technika ta będzie przydatna wtedy, gdy pola będziemy mogli inicjalizować w momencie ich deklaracji, co jest proponowane w C++0x. Wygląda więc na to, że znów dochodzimy do konkluzji, że język C++ pozostaje daleko w tyle w stosunku do swych młodszych braci. Ale czegóż można oczekiwać po staruszku, który w tym roku będzie obchodził swoje ćwierćwiecze? :) Zanim więc otrzyma on jakże konieczny lifting, musimy żyć z niezbyt wygodnymi, ale koniecznymi, metodami dostępowymi.
Hmm... A przecież chciałem dzisiaj ponarzekać raczej na Javę... No cóż, nie wyszło ;-)
Efektywne stawianie pikseliObecnie biblioteki graficzne umieją już bardzo, bardzo dużo. W narzędziach takich jak DirectX czy OpenGL mamy ogromne możliwości efektywnego wyświetlania grafiki trójwymiarowej, a jednocześnie ich obsługa staje się z kolejnymi wersjami coraz łatwiejsza. Należy oczywiście poznać nieco matematycznych podstaw stojących za całą grafiką 3D: przekształceniami, oświetleniem, buforem głębi, i tak dalej. Zasadnicza część - czyli cały potok renderowania oraz rasteryzacja - jest już jednak wykonana za nas.
Powiedzmy jednak, że nie zadowala nas ten stan rzeczy i ze względów edukacyjnych - lub możliwych czynników zewnętrznych :) - chcemy sami dowiedzieć (w sposób najbardziej praktyczny, czyli poprzez implementację), jak to wszystko działa. Wówczas do szczęścia potrzebujemy właściwie tylko jednej operacji: wyświetlenia pojedynczego piksela w określonym kolorze. I jest tylko jedno ale: aby to wszystko działało w jakikolwiek sensowny sposób, operacja ta musi być diabelnie szybka.
Niestety (a może właśnie 'stety') czasy, w których łatwo możemy pisać bezpośrednio po pamięci ekranu, najwyraźniej już dawno się skończyły. Nowoczesny system operacyjny nie pozwala po prostu na takie niskopoziomowe operacje żadnym programom użytkownika. Z drugiej strony korzystanie z tego, co w zakresie wyświetlania grafiki ów system oferuje, może być niewystarczająco - pod względem wydajnościowym, rzecz jasna.
Dlatego wydaje się, że do eksperymentów dobrze nadają istniejące biblioteki graficzne - tyle że ograniczone do jednej funkcjonalności: renderowania sprite'ów punktowych (point sprites). Polega ona na rysowaniu quadów (kwadratów złożonych z dwóch trójkątów) w taki sposób, że zawsze są one zwrócone przodem do kamery. Biorąc pod uwagę to, że wielkość takich punktów możemy określić, ustawienie jej na równą jednemu pikselowi sprawi, że wyświetlanie sprite'ów punktowych będzie dobrym substytutem "stawiania" pojedyncznych pikseli.
Gdzie w zakamarkach bibliotek graficznych ukryta jest tego rodzaju funkcjonalność? Otóż:
D3DRS_POINTSCALEENABLE na FALSE (co zresztą jest domyślną wartością) oraz D3DRS_POINTSIZE na 1.0f, czyli wielkość odpowiadającą jednemu pikselowi. Co ciekawe, trzeci o nazwie D3RS_POINTSPRITEENABLE wbrew pozorom lepiej jest zostawić ustawiony domyślnie na FALSE. Nie dotyczy on bowiem (co jest dość mylące) samej możliwości rysowania sprite'ów punktowych, a jedynie sposobu mapowania współrzędnych tekstur - co w przypadku symulowania pikseli nie jest nam potrzebne.D3DFVF_XYZRHW oraz D3DFVF_DIFFUSE przy pomocy dowolnych wywołań DrawPrimitive[UP] z typem prymitywów D3DPT_POINTLIST.1.0f). Jeśli zaś chodzi o samo rysowanie punktów to jednym ze sposobów (i pewnie nie najlepszym :)) jest ustawienie wszystkich macierzy na jednostkowe i podawanie współrzędnych punktów jako wektorów 4D z ustaloną współrzędną Z (np. 0) oraz W równą 1, do funkcji glVertex4*. Musi być ona umieszczona oczywiście między glBegin (z parametrem GL_POINTS) a glEnd, zaś kolor punktu-piksela określić możemy przez glColor*.Jak widać, mechanizmy wspomagające nas w ręcznej, pikselowej robocie są nieco ukryte. Co więcej, w DirectX 10 na przykład sprite'y punktowe zostaną wyeliminowane z biblioteki i konieczne będzie samodzielne tworzenie odpowiednich quadów, jeśli zechcemy uzyskać podobną funkcjonalność. To prawdopodobnie słuszna decyzja, bowiem nawet w swoim głównym zastosowaniu - czyli systemach cząsteczkowych - są one zbyt ograniczone (choćby dlatego, że są cały czas zwrócone do kamery, co wyklucza możliwość obrotu cząstek). A przyznajmy, że samodzielne stawianie "pikseli" jest dość egzotyczne - co nie znaczy, że nie warto wiedzieć, jak to się robi, jeśli kiedykolwiek będzie to nam potrzebne...
Całe to Web 2.0Wraz początkiem tego roku minęło okrągłych 8 lat, od kiedy to po raz pierwszy zajrzałem w to "coś", co nazywamy Internetem. Nie były to z jednej strony bardzo zamierzchłe czasy. Strony WWW były oczywiście bardziej statyczne i mniej wypełnione obrazkami (mała przepustowość łącz!), ale nie wyglądały wcale ubogo. Tak chętnie używane teraz komunikatory również istniały i były całkiem popularne - na czele z dzisiaj już trochę zapomnianym ICQ.
Z drugiej jednak strony wydaje się, że tamten okres jest już prehistorią. I nie chodzi tu tylko o znaczne zwiększenie szybkości dostępu do sieci, do poziomu pozwalającego chociażby oglądać filmy streamowane w czasie rzeczywistym. Prawdopodobnie ważniejszą zmianą jest bowiem jego upowszechnienie oraz to, co z tego wynikło: zmiana podejścia do Internetu, które to od kilku lat określa się supermodnym terminem 'Web 2.0'.
Jako że jest to pojęcie bardzo na czasie, bywa ono nadużywane i dlatego nie bardzo poddaje jednoznacznemu zdefiniowaniu. Sam zazwyczaj rozumiem je jako taką zasadę działania Internetu (chociaż dotyczy to prawie wyłącznie WWW), w myśl której to użytkownicy są nie tylko odbiorcami, ale i głównymi (a często i jedynymi) twórcami treści.
Mamy więc łatwość jej tworzenia oraz szeroki dostęp do sieci. Co powstaje z połączenia tych dwóch czynników?... Rezultaty są, mówiać oględnie, bardzo różne. Widać rzecz jasna "inteligencję tłumu", której największym dziełem jest zapewne Wikipedia - chociaż równie cenna jest cała masa innych serwisów tematycznych, współtworzonych przez swoich gości. Przy bliższym spojrzeniu można jednak łatwo zauważyć, że wszystkie te twory funkcjonują i są wartościowe głównie dlatego, że ktoś zawsze nad nimi czuwa i dba o ich jakość. Bez ciągłej opieki wszystko ulega bowiem degeneracji. Analogicznych zjawisk można się dopatrzeć niemal wszędzie, od ekonomii (zły pieniądz wypiera dobry) po fizykę (entropia układu nigdy nie maleje), serwisy spod znaku Web 2.0 też nie są od nich wolne. Wręcz przeciwnie: konieczna jest systematyczna i niemająca końca praca autorów, poprawiających artykuły zamieszczone na wiki, czy moderatorów dbających o poziom dyskusji na forach. Próbkę tego, w jakim kierunku podążyłaby cała sieć bez tej pracy, można zobaczyć, oglądając komentarze pod artykułami na dowolnym internetowym portalu.
W sumie jednak nie jest to nic nowego: trolle na grupach dyskusyjnych istnieli pewnie od zarania Usenetu i kolejna forma ich "ewolucji" była zupełnie do przewidzenia. Podobnie większość z rozwiązań określanych teraz mianem Web 2.0 istniało na długo przed ukuciem tego terminu (w 2004 roku). Jednak dopiero po jego powstaniu ujrzeliśmy cały wysyp pomysłów, których twórcy zaczęli ideę Web 2.0 intensywnie wcielać w życie.
Efektem tego są na przykład różne 'ciekawe' serwisy i usługi, których przeznaczeniem jest wymiana 'informacji' między użytkownikami. Zaczynają się one od takich, przez które możemy poinformować znajomych o tym, co aktualnie robimy, zaś kończą na wielofunkcyjnych i rozbudowanych serwisach 'społecznościowych'. Można tam stworzyć swój profil, zamieszczać zdjęcia, tworzyć listy znajomych, a nawet dyskutować na forach. Zadziwiające, prawda?...
Rzeczywiście, przynajmniej dla mnie jest zupełnie niewytłumaczalne, na czym polega fenomen popularności takich miejsc. Wystarczy bowiem zadać jedno proste pytanie, by zakwestionować cały sens ich istnienia. Brzmi ono: "No i co z tego?". No właśnie - czy mamy w tym przypadku do czynienia z jakimiś genialnymi pomysłami? Przecież to wszystko już było: dla każdego takiego serwisu (oraz każdej jego funkcji) można z łatwością znaleźć istniejącą usługę sieciową - lub jej część - która potrafi mniej więcej lub nawet dokładnie to samo.
Trik zatem polega najprawdopodobniej na zintegrowaniu tego wszystkiego i odgadnięciu sposobu myślenia przeciętnego użytkownika Internetu, dla którego sieć zaczyna się i kończy w przeglądarce WWW. Nadal jednak nie wyjaśnia to gigantycznej liczby użytkowników tego rodzaju stron.
Kiedyś mieliśmy serwisy, wokół których - jeśli były popularne - tworzyły się społeczności, przyczyniające się do poprawy ich jakości i wytyczające ścieżki dalszego rozwoju. Teraz mamy serwisy społecznościowe, którego niczego nie poprawiają i nie przyczyniają się do niczyjego rozwoju...
Jakie więc może być dalszy kierunek zmian? Może sparafrazujmy Einsteina: mówił on, że nie wie, jak będzie wyglądała III wojna światowa, ale IV zapewne będzie na kije i pałki. My zaś nie mamy jeszcze zbytniego pojęcia, czym bedzie Web 3.0 - więc kto wie, czy z kolei wersja 4.0 nie będzie polegać na czymś podobnym? ;-)