[Из песочницы] Встраиваемая JavaScript база данных с прицелом на API совместимость с MongoDB
Как-то давно мы задумали написать один проект для Node.js которому очень нужно было работать с NoSQL базой данных, но при этом не иметь никаких зависимостей от внешних приложений. Как это обычно бывает, все закончилось разработкой новой библиотеки.
Начав разработку два года назад, желание использовать встроенную базу данных для web приложения казалось весьма странным. В самом деле, зачем? Сейчас, когда появился проект node-webkit, объяснить это гораздо легче. Используя встроенную базу данных возможно разработать web приложение двойного назначения. Такое приложение сможет работать как в классической схеме клиент-сервер, так и с использованием node-webkit как обычное загружаемое приложение. Важной особенностью и в том и другом случае является то, что код базы данных является частью вашего приложения, что избавляет от многих проблем совместимости и установки.
Осмотревшись вокруг, мы нашли несколько различных проектов, но остановились почему-то на Alfred.js. Внешне, да и по первым тестам, он выглядел очень здорово и делал то, что нам нужно. Во-первых, он не загружал все данные в память, а использовал файловый доступ. То есть потенциально он мог работать с относительно большим объемом данных, разумно потребляя память. Во-вторых, он умел использовать индексы, что очень важно. Ну и в третьих, казалось, что он очень хорошо проработан хотя бы потому, что там была даже предусмотрена репликация.
Пройдя экватор в разработке, мы начали спотыкаться об Alfred.js. Реалистичные наборы данных вызывали множественные ошибки включая порчу данных. В какой то момент вместо разработки приложения мы занялись починкой кода базы данных. Потратив много времени с переменным результатом, мы не добились ничего кроме разочарования. Самое главное, что проблемы с базой данных полностью остановили разработку самого приложения, и это расстраивало больше всего.
В какой-то момент времени было принято решение заменить базу данных на MongoDB и одновременно попробовать разработать собственную библиотеку баз данных, которую можно было бы использовать не меняя ничего в коде приложения. То есть такая база данных должна иметь функциональность и API идентичный драйверу MongoDB для Node.js. Было изначально понятно, что сложно реализовать всю функциональность MongoDB. Однако мы точно знали, что все и не нужно. По известному правилу нам нужно только 20% возможностей, которые покроют 80% потребностей. Таким образом, дальнейшая разработка пошла в двух направлениях. Часть команды занялась адаптацией приложения на MongoDB, другая часть разработкой базы данных.
Как ни странно, адаптация кода под MongoDB оказалась не такой тривиальной. Тот факт, что Alfred.js использует похожий синтаксис запросов и методы скорее навредил, чем помог. Этот опыт помог нам уяснить, что только полная идентичность — это путь, по которому нужно двигаться. Поэтому изначально было решено, что все тесты должны работать один в один как с нашей новой базой, данных так и с MongoDB.
Позднее, реализовав базовый функционал, появилась идея взять готовые тесты из проекта Node.js драйвера для MongoDB. Это был серьезный вызов, который мы приняли и осуществили. Интегрируя готовые тесты мы узнали много нового о самом драйвере и где-то даже разочаровались. Заимствованные тесты в большинстве случаев не проверяют коды ошибок, что очень сильно мешало. Кроме прочего, API оказался через чур гибким на наш взгляд. Например, функция Collection.find допускает 7 различных комбинаций параметров и каждый раз, когда ее вызывают, десятки строчек кода занимаются только тем, что пытаются угадать, какой именно вариант был использован. Тем не менее, все это поведение было детально воспроизведено вплоть до текста исключений и вероятных ошибок.
В какой-то момент обоим направлением разработки суждено было встретиться. С одной стороны, мы уже имели хорошо работающее приложение, использующее MongoDB. С другой стороны, мы получили базу данных, которая реализует требующийся нам функционал и проходит несколько сотен тестов. Встреча не прошла идеально, но вскрывшиеся проблемы оказались незначительными. Вскоре приложение заработало со встроенной базой данных так же хорошо, как и с MongoDB, что и продолжает делать до сих пор.
Нашу базу данных мы назвали TingoDB (TInymoNGODB) и опубликовали исходный код на GitHub.