Читать книгу Programowanie gier - Robert Nystrom - Страница 20
Jakim kosztem?
ОглавлениеBrzmi świetnie, prawda? Oddzielimy wszystko, co trzeba, a będziemy w stanie kodować niczym wicher. Każda zmiana będzie się wiązać z modyfikacją tylko jednej lub dwóch wybranych metod, a my będziemy mogli tańczyć na tafli kodu źródłowego, nie zostawiając nawet cienia śladu.
To uczucie sprawia, że ludzie tak ekscytują się abstrakcjami, modularnością, wzorcami projektowymi i architekturą oprogramowania. Praca nad programem o dobrej architekturze to naprawdę radosne doświadczenie, a każdy lubi być bardziej produktywny. Dobra architektura ma ogromny wpływ na produktywność. Trudno przecenić jak głęboki może on być.
Jak wszystko w życiu, ma to jednak swoją cenę. Dobra architektura wymaga prawdziwego wysiłku i dyscypliny. Za każdym razem, gdy dokonujemy jakiejś zmiany lub implementujemy jakąś funkcjonalność, musimy się ciężko napracować, aby zgrabnie zintegrować ją z resztą programu. Musimy starannie zadbać zarówno o dobrą organizację kodu źródłowego, jak i o to, by utrzymać ten stan w trakcie dokonywania tysięcy drobnych zmian składających się na cykl produkcyjny oprogramowania.
Druga część – poświęcona utrzymaniu naszego projektu – zasługuje na szczególną uwagę. Widziałem wiele programów, których początki były piękne, a które następnie dogorywały w wyniku tysiąca drobnych cięć w miarę jak programiści raz za razem dodawali „jeszcze tylko jeden, malutki kawałek”.
Musimy się zastanowić, między którymi częściami programu powinny zostać oddzielone zależności i w tych miejscach wprowadzić abstrakcje. Podobnie musimy określić, gdzie powinna zostać uwzględniona możliwość rozszerzenia, tak by przyszłe zmiany były łatwiejsze do wprowadzenia.
Jak w ogrodnictwie – nie wystarczy posadzić nowe rośliny, trzeba je również przycinać i odchwaszczać.
Ludzie naprawde się tym ekscytują. Wyobrażają sobie, że w przyszłości programiści (albo po prostu oni sami) zagłębiają się w bazę kodu i orientują się, że jest ona otwarta, potężna i wprost prosi się o to, by ją rozszerzyć. Wyobrażają sobie „Silnik Gry nad Wszystkie Inne Silniki”.
Ale to właśnie tu zaczynają się schody. Zawsze gdy dodajemy warstwę abstrakcji lub miejsce wspierające rozszerzalność, spekulujemy, że w przyszłości ta elastyczność będzie nam potrzebna. Zwiększamy objętość oraz złożoność kodu naszej gry, co wymaga poświęcenia czasu na zaprogramowanie, usunięcie usterek i utrzymanie.
Wysiłek się opłaci, jeśli zgadniemy poprawnie i w przyszłości wrócimy do tego kodu. Przewidywanie przyszłości jest jednak trudne, a gdy taka modułowość koniec końców nie okaże się pomocna, szybko zaczyna aktywnie szkodzić. Ostatecznie jest to dodatkowy kod, z którym musimy sobie radzić.
Niektórzy ukuli termin „YAGNI” od angielskiego „You aren’t gonna need it” (Nie będzie ci to potrzebne) i stosują go jak mantrę, aby zwalczyć pragnienie spekulowania o tym, czego może potrzebować nasze przyszłe „ja”.
Gdy ludzie zaczynają podchodzić do tego zbyt gorliwie, dostajemy bazę kodu, której architektura wymknęła się spod kontroli. Wszędzie mamy do czynienia z interfejsami i abstrakcjami. Systemy wtyczek, abstrakcyjne klasy bazowe, obfitość metod wirtualnych i wszelkiego rodzaju punkty rozszerzenia.
Poruszanie się po całym tym rusztowaniu zajmie nam wieczność, nim znajdziemy jakiś rzeczywisty kod, który faktycznie coś robi. Gdy musimy coś zmienić – jasne, pewnie znajdzie się interfejs, który nam w tym pomoże. Powodzenia w jego odszukaniu! W teorii całe to oddzielanie znaczy, że mamy mniej kodu, który musimy zrozumieć, zanim będziemy mogli go rozszerzyć, ale przecież same warstwy abstrakcji też wypełniają nasz mentalny dysk.
Tego typu bazy kodu sprawiają, że wiele osób krzywo patrzy na architekturę oprogramowania, a na wzorce projektowe w szczególności. Łatwo jest tak mocno zaplątać się w sam kod, że tracimy z oczu to, że próbujemy dostarczyć na rynek jakąś grę. Syreni śpiew rozszerzalności wciąga niezliczonych programistów, którzy spędzają lata, pracując nad „silnikiem”, nie rozumiejąc nawet, czemu ten silnik ma służyć.