Moi koledzy-częściowo-po-fachu, czyli programiści silników gier, wymyślili niedawno magiczny trzyliterowy akronim DOD – skrót od Data-Oriented Design, czyli projektowanie oparte o dane. Oczywiście określenie ‘niedawno’ jest względnym i pewnie wielu z nich orzekło by, że DOD jest z nimi już całkiem długo. Każdy mem potrzebuje jednak czasu na rozprzestrzenienie się, a w przypadku tego fala tweetów na jego temat dotarła do mnie dopiero niedawno. Niedługo potem rzecz wydała mi się cokolwiek podejrzana.
Podstawowe pytanie brzmi rzecz jasna: o co w tym właściwie chodzi?… Ponieważ mówimy o programowaniu gier, to odpowiedź jest jasna: jeśli nie wiadomo o co chodzi, to chodzi o wydajność. W zaawansowanych grach czasu rzeczywistego mamy do czynienia z ogromną ilością danych, na których trzeba wykonać wiele, często skomplikowanych operacji, a wszystko to jeszcze musi być zrobione dostatecznie szybko, aby możliwe było pokazanie na ekranie kolejnej klatki bez widocznych przycięć. Dlatego też już dawno zauważono, że kodowanie “blisko sprzętu” się opłaca, bo pozwala maksymalnie wykorzystać jego możliwości.
To oczywiście nakłada na kod pewne wymagania oraz stwarza konieczność zwrócenia uwagi na rzeczy, którymi “normalnie” nie ma potrzeby się zajmować. Ładnym przykładem jest chociażby zarządzanie pamięcią. W wielu językach jest ono albo kompletnie pomijalne (garbage collector), albo sprowadza się do dbania o to, aby każdy zaalokowany blok był w końcu zwolniony. Gdy jednak stawiamy na wydajność, powinniśmy też zainteresować się szybkością samej operacji alokacji oraz takim rozmieszczeniem przydzielanych bloków, aby komunikacja na linii procesor-pamięć odbywała się z jak najmniejszą liczbą zgrzytów.
Ten i wiele podobnych szczegółów platformy sprzętowej powodują, że pisanie efektywnego kodu w silnikach gier to często dość literalne postępowanie według zasady Do It Yourself, połączone z ignorowaniem części feature‘ów wysokopoziomowych języków programowania, o których wiadomo, że negatywnie odbijają się na wydajności. Cóż, życie; nie ma w tym nic zaskakującego. Myślę, że każdy co bardziej zaawansowany programista zdążył zdać sobie sprawę z tego, że wszelkie koderskie udogodnienia związane z podniesieniem poziomu abstrakcji mają swój koszt liczony w dodatkowych cyklach procesora (i nie tylko). Rezygnacja z nich jest więc dobrym posunięciem, jeśli chcemy te “stracone” cykle odzyskać.
Robiąc to, będziemy mieli ciastko, ale już nie będziemy mogli go zjeść – a to oczywiście nie jest przyjemne. I po części zapewne stąd wzięło się pojęcie DOD, które nie odnosi się do niczego w gruncie rzeczy nowego, ale pozwala łatwiej odnosić się do tego rodzaju koderskich praktyk poprzez nadanie im nazwy. A przy okazji – jak mi się wydaje – w jakiś nie do końca wytłumaczalny sposób redukuje dysonans poznawczy programistów silników gier, którzy świadomie muszą pozbawiać się możliwości przestrzegania “jedynie słusznych” zasad pisania kodu.
Jak dotąd wszystko jest w gruncie rzeczy bardzo ładne i sensowne, i bez problemu zgadzam się z postulatami Data-Oriented Design tam, gdzie się one aplikują. Zgadzam się nawet z tą domniemaną ukrytą motywacją, zwłaszcza że sam nieraz narzekałem na owe “jedynie słuszne” rady. Za to nijak nie mogę pojąć, dlaczego następnym krokiem – po wynalezieniu pojęcia DOD – był mniej lub bardziej frontalny atak na programowanie obiektowe, określane nieco bardziej znanym (ale naturalnie również trzyliterowym) akronimem OOP.
Nie, nie chodzi o to, że programowanie obiektowe jest doskonałe – bo nie jest, nie było, nigdy nie będzie i nawet nie aspiruje do miana finalnego rozwiązania dla dowolnego problemu (już nie wspominając o tym, że takowe po prostu nie istnieją). Rzecz w tym, że zwolennicy DOD (DOD-a? :]) w nieprzemyślany sposób wybrali sobie przeciwnika, nie zauważając, że jest on paradygmatem zupełnie innego rodzaju niż ich własny. A to przecież takie proste:
Widać to, prawda?… Miedzy powyższymi dwoma podejściami nie tylko nie ma sprzeczności. One są od siebie po prostu niezależne, co oznacza również, że mogą występować razem w jednym programie.
Jeśli Data-Oriented Design koniecznie potrzebuje jakiegoś przeciwnika, to są nim raczej inne xOD-y, których jest już przynajmniej kilka, chociaż wiele nie zostało jeszcze nawet nazwanych. (Dobry przykład to projektowanie oparte o user experience, czyli wrażenie użytkownika, gdzie priorytetem jest m.in. responsywność, nie będąca wcale synonimem wydajności). To, co piewcy DOD zdają się krytykować w swoich publikacjach, to jakieś “projektowanie oparte o eleganckie abstrakcje”, czyli pisanie kodu, który jest sztuką dla sztuki: ładnie wygląda (w założeniu), ściśle trzyma się założeń używanego paradygmatu przy jednoczesnym eksploatowaniu wszelkich jego “zdobyczy” (czyli np. wzorców projektowych). I chociaż bywają w swoich wysiłkach niezwykle twórczy (w prezentacjach z tego tematu spotkałem nawet cytaty z Baudrillarda), to nie zmienia to faktu, że kopią leżącego (czy raczej biją martwego konia, jakby to powiedzieli Amerykanie ;-)). Bo jeśli ktoś naprawdę posuwa się do takich absurdów jak czteropoziomowa hierarchia dziedziczenia obiektów gry, to znaczy że ma znacznie poważniejsze problemy niż okazjonalny cache miss :)
Bardzo dobrze napisane! Też nie widzę sprzeczności między OOP i DOD.
Też się zastanawiam czemu niektórzy stawiają oba pojęcia jako przeciwne sobie. Przecież równie dobrze można zaprojektować klasy zorientowane na dane, które zawierają w sobie ciągi odpowiednich danych i wykonują na nich określone zadania. A zmiana i dostęp do tych danych można zrealizować za pomocą klas zorientowanych obiektowo, które będą zawierać wskaźniki na te dane.
Może dla tego, że niektórzy jak już programują obiektową robią to naprawdę do bólu – wyobraźcie sobie model MFC w grze, w której układa się klocki. I to zrobiony w 100% książkowo, sama komunikacja między obiektami to jakiś koszmar…
Tu nie chodzi o OOP, który może kod bardzo uprościć, ale o OOD który niewłaściwie użyty powoduje rozdmuchiwanie kodu. Ludzie po prostu próbują pisać max elastycznie, zamiast krótko i zwięźle. Oby DOD to zmienił.
A ja widzę sprzeczność między DOD a OOP. To nie znaczy że każda obiektowość jest zła, bo można przecież używać klas. Ale poczytaj więcej o DOD i zwróć uwagę na przytaczany często przykład virtual update()=0, żeby zobaczyć, jak obiektowy sposób myślenia przeszkadza w tym, na co DOD kładzie nacisk – wydajności, prostocie i łatwości zrównoleglenia.
Również nie rozumiem potępiania OOP przez zwolenników DOD. W szczególności obrażania zwolenników OOP. Jest nowy, inny sposób kodowania – ok. Po co krytykować wcześniejsze podejścia? Żeby zyskać trochę rozgłosu? Przypuszczam, że to rodzaj strachu przed OOP z ich strony.
Nie zgodzę się z tym, że OOP i DOD są niezależne.W DOD chodzi o to, żeby dane były ułożone w pamięci wg typu. W OOP naturalne, że w pamięci obok siebie leżą dane różnego typu – zazwyczaj są to różne pola jednej klasy. To oczywiście jest ze sobą sprzeczne.
Ciekawy byłby język programowania, który pozwalałby programować obiektowo i jednocześnie układać dane w pamięci wg typu :-)
Ciekawy byłby język programowania, który pozwalałby programować obiektowo i jednocześnie układać dane w pamięci wg typu :-)
Ja nie widzę tu problemu, nie widzę nawet potrzeby tworzenia nowego języka. To po prostu kwestia lukru składniowego i zastąpienia
class Foo
{
int age;
public:
int getAge() { return age; }
}
na
class Foo
{
public:
int ID;
int getAge() { return ages[ID]; }
}
Przy czym wg. mnie takie podejście w perfekcyjny sposób łączy wady OOP i DOD :)
Jak się ma Data oriented (który słyszę pierwszy raz) do Data driven (o którym słyszałem nieraz)? Synonimy?
Nie wydaje mi się.
Data-driven to sterowanie działaniem gry/programu za pomocą “danych”, czyli logiki zapisanej poza kompilowanym kodem – czyli głównie skryptów.
Data-oriented to sposób organizowania kodu uwzględniający jak najefektywniejszy dostęp do danych w pamięci.
Jedno ani nie wyklucza, ani specjalnie nie wspomaga drugiego. To po prostu dwa niezależne pojęcia.
Eee trochę histeria, trochę szpanerstwa, wyróżniania się… jak zawsze…
Ja stawiam wciąż na kod korzystający z dobrodziejstw abstrakcji. Programiści powinni skupić się na poprawianiu bugów w grach, a nie przysparzania okazji do generowania kolejnych pisząc jakieś read-only-nie-wiadomo-szpanerskie-co…
Mało kto potrafi dobrze napisać grę nawet pisząc dość swobodnie, a wszyscy już się za pojedyncze bity… bez sensu. Strzelanie sobie w stopę, albo i kolano…
A przecież to bugi w grach najbardziej ssą, a nie FPS 25 zamiast 35…