Почему не нужно начинать с Django
пост написан и отправлен в печать 2011-08-28 примерно в 20:26
У меня случилось огромное "горе" - проект, который был взращен мной и небольшой компанией программистов практически для личного пользования, вдруг стал популярен, подвергся реддит, дигг и стамблапон эффектам (и пережил их почти без даунтаймов, эта отдельная гордость и тема для другого поста), обзавелся серьезными инвесторами и наполнился хорошей релевантной активной аудиторией. Обойдемся без имен и названий - нас интересует исключительно технологическая сторона. Случилось это около года назад, под управлением талантливого PMа всего через 5 месяцев после публичного старта удалось монетизировать сервис без потерь лояльности клиентов - правда пару злых мудаков в бложиках все же плюнули злым словцом в сторону нашей корыстности. И вот, в один прекрасный день мы уткнулись носом в стену. Данный пост поможет вам не повторять наши ошибки и призван поделиться опытом выбора инструментария разработки и деплоймента в самом начале долгого пути.

Основная проблема в проектах нашего типа - недальновидность, по этим же причинам facebook в свое время был написан на PHP, который в последствии пытались собирать в С++ в HipHop, не знаю,чем там все закончилось, но подобных примеров миллионы, к сожалению, лишь крупные компании на этапе первичного планирования могут позволить себе разработку архитектуры горизонтального и вертикального масштабирования и предвидеть дальнейшее развитие проекта. Все маленькие команды создают проекты на одной левой коленке с помощью простого и быстрого инструментария, а далее начинает действовать правило снежного кома - старый код обрастает новым и заменить ядро можно только полность раскопав верхние слои. Не обошла стороной эта проблема и нас, для реализации был выбран фреймворк Django, возможностей которого хватало примерно с год, а дальше мы столкнулись с проблемой большинства. При куче достоинств у этого инструмента есть один большущий минус - узколобое и совершенно не гибкое ORM на котором завязано абсолютно все: CRUD интерфейс панели администрирования, модуль аутентификации, генератор форм и тому подобное. Проблема была достаточно серьезная - нужно было либо внедрять прямые SQL инъекции, используя сторонние raw sql билдеры, сведя на нет переносимость, абстрагированность от синтаксиса и саму идею ORM, либо искать альтернативные решения. Второй вариант показался нам более предпочтительным, принимая во внимание тот факт, что из Django мы использовали лишь верхний слой шаблонизатора, URL Routing, ORM (ну и генератор форм) и memcached backend. Для шаблонов сразу был найден jinja2, практически полностью совместимый с django-templates, небольшие синтаксические различия состояли лишь в передаче параметров фильтрам и отсутствии некоторых методов (вроде того же {% url %}, он повсеместно использовался нами для генерации ссылок), которые были написаны самостоятельно с учетом особенностей нового ядра. Вторая часть команды занималась портированием контроллеров в новый фреймворк Pyramid (продолжатель идей Pylons), а мне оставалась самая "вкусная" работа - переписывать модели с Django ORM на SQLAlchemy, ну и переносить данные. Не буду углубляться в детали, скажу лишь, что ничего не мешало использовать алхимию поверх таблиц, генерированных джанго - в отличии от своего инвалидного собрата, sqlalchemy умеет custom database scheme, но хотелось абстрагироваться от ужасных many-to-many relations с таблицей в 500K записей, оставленных в наследство. Проблема генерации и валидации форм тоже была сведена на нет с помощью formalchemy. В остальном, это была вполне выполнимая рутина. Через 10 дней в SVN ветке с заветным названием migration уже была рабочая тестовая версия, которую нужно было скармливать обезьянкам из отдела тестировки и QA.

Теперь поговорим про deployment. В датацентре компания арендует несколько серверов в стойке - фронтэнд с nginx для простой пропорционального upstream load-balancing, 2 backend-а для python и memcache, 3 сервера для pgpool-II PostgreSQL кластера. Статика и файлы пользователей хранятся в Amazon S3. Раньше на бэкэндах мы использовали FastCGI интерфейс manage.py прямо из коробки Django руководствуясь приципом "нам лениво", с переходом на Pyramid был выбран родной для Python WSGI и Green Unicorn в качестве сервера, который умеет работать с Paste-совместимыми фреймворками. Для данного окружения был создан отдельный virtualenv на каждом сервере, позволяющий вести тестирование и установку новых версий необходимых библиотек, не боясь повредить хрупкие dependancies для уже работающего проекта. В качестве сторожевого пса была выбрана тоже не чужая для python система контроля процесса supervisord. Для управления нашими новыми окружениями было построено небольшое приложение на основе fabric, инициирующее svn up обновление bleeding edge версий через SVN post-commit хук и перезагружающее gunicorn workers простой и удобной коммандой kill -HUP `cat /var/run/g_be.pid`. 

Предварительные выводы пока делать достаточно рано - новая версия все еще не ушла в production, но синтетические нагрузки с помощью утилит аля siege показали заметную экономию на времени генерации страницы и ресурсах CPU\RAM. Что касаемо Django - поистине великолепный инструмент, Ruby On Rails, но только для Python и я ни в коем случае не списываю его со счетов. Этот блог был целиком и полностью написан на Django за 5 часов, но если вы планируете создать что-то, что гипотетически будет усложняться структурно - вам необходимо смотреть в сторону альтернативных инструментов. Удачный пример миграции, описанный в этом посте - скорее success story и большая удача, чем правило. Просто большинство нашего функционала было вынесено в packages, а Django был просто прослойкой для создания логики. Вам же может повезти намного меньше.

И в качестве послесловия: опытный программист и системный архитектор (охуитительно же звучит) в лице меня ищет интересную работу на расстоянии. Интересную не в смысле денежной компенсации или комплексных обедов, интересным и технически сложным должен быть проект и команда. Хотя команда может быть и не сложной, просто опытной и приятной в общении. Рассмотрю любые предложения, отправленные мне на электронную почту, указанную в шапке.