Супергибкий суперустойчивый движок

предыдущая серия

Конечно, JavaScript плохо подходит для построения API или серверных скриптов. В нем нету поддержки пространств имен, системы пакетов и тому подобных фич, и конечно его никак нельзя назвать универсальным. Отмечу, что ужос современного мэйнстрима в том, что при этом JavaScript как раз позиционируется как универсальный!

Но при решении специфических задач JavaScript подходит просто отлично. Это например модульные тесты, когда возможность трактовать каждый объект или класс как набор свойств, в соответствии с нашим паттерном моделирования, делает совсем простым создание mock-объектов. Причем для организации таких тестов на JavaScript нам совершенно не требуются специализированные фреймворки, как в C++ или Python.
Также, JavaScript — один из двух самых лучших языков сценариев в мире. Если под сценарием понимать самое правильное значение — язык, разработанный специально для встраивания в крупные хост-системы, и позволяющий манипулировать объектами этой системы. JavaScript минималистичен в плане реализации, имеет более-менее удовлетворительную (полу)формальную спецификацию, и главное, предлагает хороший интерфейс для обработки хост-объектов.

На контрасте, Python или Ruby, C++ или Java — в сравнении с ним огромные системы, претендующие на универсальность, и поэтому сильно проигрывающие в роли скрипт-языка.

Второй правильный язык сценариев, как вы наверное уже догадались — это Lua, разработанный для игровой индустрии. И что самое интересное: в Lua в качестве центрального механизма так же выбран паттерн свойств! Его ключевая структура Table удивительно похожа на Object из JavaScript, и также применяются прототипы вместо классов.

Итак, просто ли это совпадение, такой космический синхронизм? Можно ли в качестве сценарного языка успешно использовать язык на основе классов? Дело в том, что когда хост-система растет и расширяется, использование универсальных языков в качестве скриптовых начинает сильно усложнять жизнь разработчикам из-за серьезных ограничений в гибкости.

Давайте теперь посмотрим, как Steve Yegge применял паттерн свойств в его игре Wyvern. Эта ММО полностью написана на Java, однако ее коренной объект по сути представляет собой список свойств (как Object в JavaScript). В Wyvern реализовано наследование прототипов, и любой игровой объект может стать прототипом для другого.

Стив думал над этой концепцией несколько месяцев! Было это в 1996-м, еще до JavaScript и многого другого. Он пытался спроектировать максимально легко расширяемую архитектуру — в частности, чтобы весь (реально, весь) контент мог создаваться игроками. Были продуманы десятки самых разных нестандартных вариантов, в которых это было бы возможно. В конечном итоге родилась богатая система команд и мощная система хуков/подсказок. Но главное, что в основу все же был заложен паттерн свойств.
В результате в Wyvern появилась отличная поддержка метапрограммирования: например, уведомления о запрете на изменение свойств, а сами свойства могут быть как изменяемые, так и персистентные. Важной оказалась идея статической типизации свойств, когда значением свойства может быть либо нечто одного из базовых типов, либо функция, либо другой прототип.

В итоге эта идея оправдала себя, начиная с конца 1990-х, и по сей день! И даже весьма амбициозные задумки оказались в итоге на практике превзойдены! Особенно игроки оценили такую фишку, как мощнейшая возможность расширения/модификации внутриигровой логики без перезагрузки системы. Например, очевидным способом можно динамически создать новый класс монстров на базе какого-либо существующего, а игра при этом продолжит работать в горячем режиме.

Однако в Wyvern была допущена и серьезная архитектурная ошибка. Коли уж было решено централизованно придерживаться паттерна свойств в плане семантики, требовалась столь же удобная поддержка и на синтаксическом уровне. В идеале, надо было взять тот язык программирования, который поддерживает такой паттерн «с нуля».

В результате Стив совершил классическую ошибку: сперва, нафигачив сотни тысяч строк кода на Java с монотонными getProperty/setProperty и сильно приуныв, он решил все же взять более удобный и гибкий инструмент под свой паттерн, и остановился на Python (Jython). Но затем, тоже накодив на Питоне кучу кода, перепугался, что потеряет в производительности, и снова стал смешивать игровую логику на Python и Java. В итоге оптимизировать и рефакторить систему стало весьма трудоемко.

А правильно было бы так: инфраструктурный движок (сеть/мультиплеер, база, UI и ключевые механизмы реального времени (для 3D-игр это обычно анализ коллизий объектов)), и игровая логика на сценарном языке, поддерживающем паттерн прототипов/свойств.

Далее мы рассмотрим еще несколько примеров по теме (Lisp, BigTable, …), после чего займемся детальным рассмотрением самого паттерна свойств в плане реализации.

Поделиться статьей ...Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0Share on VKPrint this page

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *