środa, 24 listopada 2010

Danny MacAskill - "Way Back Home"

Dziś nieco inaczej niż zwykle, link: Danny MacAskill - "Way Back Home". Jestem pod ogromnym wrażeniem.

środa, 3 listopada 2010

Remont silnika odpowiedź

Anonimowy użytkownik zapytał czemu w poście Remont silnika wyraziłem nie chęć do stosowania rozwiązań typu singleton "Czemu zero rozwiązań typu singleton? Globalny, jednolity stan w jakiejkolwiek formie (monostate, singleton, zwykła klasa statyczna), jest bardzo naturalny i nie ma sensu unikać go na siłę w imię jakichś pustycznych idei."

Odpowiedź jest dość obszerna, także umieszczę to w nowym wpisie.

Moim zdaniem największym problemem z wszelkiej maści obiektami o dostępie globalnym są zależności jakie powstają pomiędzy różnymi modułami oprogramowania.
Pisząc swój silnik graficzny byłem bardzo pozytywnie nastawiony do tego typu rozwiązań, bo "ułatwiały" mi życie. Dzięki nim mogłem zmniejszyć ilość parametrów przekazywanych do metod. Unikałem również przekazywania obiektów w głąb hierarchii wywołań. (chcemy zasób, więc przekazujemy managerowi obiekt api, ten przekazuje go fabryce, ta przekazuje go konkretnej metodzie). Kto potrzebuje singletona ten sam może go sobie wziąć. I tak właśnie powstają zależności pomiędzy jednym modułem, a drugim. Przykładowo klasa tekstury potrzebowała rozmiar okna dla którego będzie render targetem. Bach, okno jest singletonem, wszyscy maja do niego dostęp. To był chyba największy błąd projektowy jaki popełniłem.

Zależności się nie skalują. Zmiana w jednym module często pociąga ogromne zmiany w całym systemie.
Zależności się bardzo szybko rozrastają. Ja w końcu się pogubiłem w kolejności otwierania i zamykania modułów. We własnym kodzie straciłem orientację.
Zależności się nie skalują. Jak zapewnić rozsądny dostęp do globalnych obiektów w środowisku wielowątkowym?
Obiekty globalne gryzą się z raii. Obiekt globalny jakim jest std::clog jest bardzo wygodny kiedy potrzebujemy coś logować. Osobiście bardzo często z niego korzystam, w taki sposób, że podpinam pod niego plik.
W main robie sobie taki trick:
fstream log("log.log" fstream::out);
clog.rdbuf(log.rdbuf());
Potem w dowolnym miejscu kodu wystarczy zapisać do std::clog i wszystko trafi do pliku.
Informacją, którą szczególnie warto logować jest moment otwierania i zamykania poszczególnych modułów. Obiekt zarządzający modułem powstanie już po otwarciu pliku, więc log powstanie poprawnie. Jeżeli jednak pozwolimy istnieć takiemu obiektowi poza czas trwania maina to mamy problem. Ja nie raz popełniłem taki błąd, nie tylko przy projekcie tego silnika. Niby wiem, że tak jest, a i tak wciąż popełniam ten błąd.