English | Русский

Блог о Linux и велосипедах

Новоселье! Новый сайт на vlevit.org

Предыстория

Два года назад я создал блог zeuhl-mode на платформе Blogger. Туда я публиковал заметки об интересных инструментах для Linux, а также о своих наработках. Использование Blogger'а тогда мне казалось более-менее удобным, так как его легко можно было создать, а содержимое постов можно было вставлять в разметке HTML. Посты писал я в org mode, экспортировал в HTML, и полученный код вставлял в форму.

Со временем я обнаружил множество недостатков такого подхода. К ним относится и необходимость повторения процедуры копирования+вставки при каждом изменении поста, и неудобства, вызываемые ручным копированием заголовков и тегов, загрузкой изображений, и ограничения, связанные с дизайном блога и системой комментариев.

В то же время у меня начали появляться заметки не на техническую тематику, и я начал задумываться о создании собственного сайта, где я бы мог разместить несколько блогов одновременно.

Генераторы статических сайтов: преимущества и недостатки

Простым и удобным решением могло бы стать использование какого-либо существующего генератора статических сайтов. Помимо очевидных преимуществ такого решения, как нетребовательность к хостингу и высокая скорость работы, оно также обладает рядом удобств:

  • вся информация хранится в текстовом виде
  • блог удобно держать в системе контроля версий
  • выбор языка разметки остаётся за пользователем
  • сайт можно посмотреть локально
  • публикация может осуществляться одной командой (например, git push)

Однако у такого решения есть существенный недостаток. Статические сайты не могут содержать комментарии, которые по своей природе являются динамическим контентом. Популярным решением этой проблемы является задействование стороннего сервиса комментариев, такого как Disqus, который встраивается в страницу в виде JavaScript-модуля. Я не принадлежу к числу фанатов такого решения как по техническим причинам, так из-за соображений, связанных с контролем.

Разработка собственного динамического сайта

Я не находил для себя разработку собственного сайта чем-то, выходящим за рамки разумного, так как понимал, что любое готовое решение мне придётся серьёзно адаптировать под свои нужды. Требованием, которое я предъявлял к сайту, было, чтобы процесс ведения и публикация блога оставался таким, как в случае с генераторами статических сайтов.

Рабочий процесс

Веб-сайт я решил писать на Django, а размещать на Heroku. Принцип работы такой. Код и контент находятся в одном git-репозитории. Когда приходит время публиковать, выполняется git push, который инициирует развёртывание новой версии сайта. На развёртывание повешен хук, по которому шлётся POST-запрос по адресу, который инициирует импорт блога в базу данных.

В отличие от большинства статических генераторов, в которых промежуточный результат между генерациями не сохраняется, здесь базу данных приходится поддерживать в актуальном состоянии: определять удаление, добавление и изменение поста. Отвечающий за импорт код находится в importers.py. Чтобы увеличить скорость загрузки, импорт заметок осуществляется только при изменении файла, в котором они находятся. В одном файле может быть много заметок — это удобно для блогов с короткими постами.

Язык разметки

Для постов в качестве языка разметки используется Markdown. Но перед тем, как пост будет преобразован из Markdown в HTML, он пройдёт ещё две фазы. В первой строка вида

/title: Новоселье! Новый сайт на vlevit.org

преобразовывается в

{% title Новоселье! Новый сайт на vlevit.org %}

и таким образом, файл превращается в полноценный Django-шаблон. На второй фазе полученный шаблон рендерится, а переменные, такие как title, сохраняются. На последнем этапе, полученный вывод обрабатывается с помощью Markdown-процессора. Такой подход позволяет устанавливать название, дату, метки, вставлять изображения, не ухудшая при этом читаемость исходников. Исходник этой заметки можно посмотреть здесь.

Комментарии

Поскольку комментарии являются по сути единственным достойным оправданием, почему я не использую генератор статических сайтов, над ними пришлось повозиться. Разумеется, первым решением, на которое я обратил внимание, стало django.conrtib.comments. Хорошо — подумал я — но в нём нет поддержки древовидных комментариев. Тогда я поискал и обнаружил django-threadedcomments, расширяющие стандартные комментарии. После нескольких дней погружения в код обоих приложений, стало очевидно, что код реализаций не очень гибкий... Где-то в это время выходит Django 1.5, и в документации к разработческой версии Django указывается, что django.conrtib.comments устарел. И что нам рекомендуют взамен? Disqus... Я не смог смириться с тем, что прожил несколько дней зря, и поверх django-threadedcomments реализовал собственное решение.

В моей модификации отправка и предварительный просмотр комментария, обновление списка комментариев и валидация форм осуществляется посредством Ajax-запросов. Комментарий можно писать в Markdown. Подсветка кода включена и благодаря Pygments поддерживается огромная база языков. И даже autoit!

Обязательными полями являются только имя и сам комментарий. Я до сих пор не до конца понимаю, почему почти во всех реализациях комментариев email является обязательным полем. Его не верифицируют, поэтому он может быть недействительным, а подписка на комментарии по email'у, если и есть, то должна осуществляться по желанию и быть доступной всем, а не только тем, кто оставил комментарий. Или сегодня email используется только для того, чтобы отобразить аватарку с Gravatar?.. Пока эта тайна мне не раскрыта, я ваши email'ы не собираю!

Импорт и экспорт комментариев

Комментарии с zeuhl-mode я вытащил при помощи регулярных выражений из Atom'а, в который экспортирует Blogger. И поместил их в читаемый YAML. Комментарии хранятся в древовидной структуре (рекурсивный список словарей), а содержимое комментария хранится в Markdown, таким образом, комментарии хорошо читаются и в исходных текстах. Функции импорта и экспорта комментариев обитают вo views/comments.py.

Дизайн сайта

Я человек скромный, поэтому и дизайн сайта не претенциозный. На некоторые элементы дизайна повлияло оформление distractable.net и тема Redux, ранее стандартная тема Tumblr. Моей основной целью было, чтобы дизайн не вызывал раздражение, а длинные посты было удобно читать.

Мои эксперименты с веб-шрифтами ни к каким результатам не привели. Подобрать подходящий шрифт, который содержит и кириллицу, и латиницу непросто. К тому, же такие шрифты будут значительно весить, в особенности если использовать разные шрифты для заголовков и основного текста. В конечном итоге я остановился на использовании sans-serif почти везде с надеждой на то, что система сама подберёт наиболее читаемый доступный шрифт.

Размер шрифта вначале я оставил стандартным1, положившись на то, что значения по умолчанию имеют под собой какие-то основания. Мой системный шрифт без засечек — Dejavu Sans, который заметно крупнее большинства других шрифтов. Поэтому я привык к тому, что кривые сайты разлезаются с этим шрифтом, и я тогда уменьшаю размер шрифта специально для сайта. Уменьшил я шрифт и для своего сайта при тестировании. Но благодаря netrender через время узнал, что 16px и для Internet Exploer'а огромный шрифт. И чем обусловлены такие странные значения в по умолчанию? Дань истории? В конечном итоге, я остановился на 14px в качестве размера основного шрифта для блогов с длинными постами и 13px — с короткими.

В дизайне сайта используется минимум картинок. На момент написания поста их всего несколько: favicon, аватар и значок RSS. Сторонние виджеты и другие элементы слежки не используются.

Хостинг

Я разместил свой сайт на Heroku, PaaS с поддержкой Python среди прочих. С точки зрения удобства использования, решение бесспорно хорошее: развёртывать удобно, администрировать не надо. Но есть и недостатки. Нет возможности контролировать окружение. Вместо этого для хранения данных, кеширования, логирования, мониторинга и других задач предлагается использовать дополнения, тесно интегрированные в систему. Большинство дополнений, как и dyno (контейнеры, на которых выполняется веб-приложение), используют модель freemium, то есть минимальная функциональность предоставляется бесплатно, а если нужно больше, необходимо платить. Поэтому цены на платный сервис достаточно высокие.

Данный сайт обходится исключительно бесплатными сервисами Heroku. Главным ограничением для небольшого сайта, как этот, является то, что после часа простоя dyno засыпает (покупка второго dyno обойдётся в 35$ в месяц), и обработка первого запроса, выводящего его из спящего режима, занимает больше 10 секунд. Ограничение легко преодолевается периодическим пингованием сайта, которое в моём случае выполняет дополнение New Relic, сервис для мониторинга сайтов. Статическое содержимое приходится хранить на Amazon S3, так как у Heroku нет подобного сервиса.

Альтернативой Heroku может служить OpenShift, PaaS от Red Hat. Печальным я нахожу то факт, что и Heroku, и OpenShift исполняются всё на том же AWS. По сути такие PaaS живут только за счёт использования другой бизнес-модели.

Сбор статистики

Для сбора статистики запросов использовать сторонний сервис, такой как Google Analytics, как и в случае с комментариями, у меня желания не было. А так как веб-сервер находится не в нашим управлении, статистику приходится собирать на уровне Django-приложения. Эту функцию выполняет django-request. Он предоставляет основную статистику по запросам к сайту: график количества обращений, наиболее посещаемые страницы, ссылающиеся ресурсы, статистику по браузерам и пару других параметров. Я рекомендую устанавливать версию с GitHub, так как в PyPI находится очень старая версия.

Так как пользовательские запросы распределяются «роутерами» Heroku, то в приложение в REMOTE_ADDR приходит IP-адреса этих роутеров, из-за чего изначально запросы с моего IP-адреса учитывались в статистике. Проблема устраняется, если также учитывать значение HTTP_X_FORWARDED_FOR, для чего в Django 1.0 даже существовал специальный middleware, который я благополучно скопировал себе в проект.

Ленты новостей

Почти за всем интересным в интернете я слежу помощью лент новостей. Я крайне негативно отношусь к авторским блогам, раздающим через ленты только часть поста, и обычно я на них не подписываюсь. Если вы автор такого блога, прошу вас задуматься о том, что вы выигрываете (или теряете) от того, что принуждаете заходить читателей на ваш сайт.

Пока на сайте постов немного и трафик низкий, через ленты отдаются абсолютно все заметки. Со временем, возможно, я установлю ограничение на их количество. Сейчас доступно три типа RSS-лент на посты: лента для постов на всех блогах

http://vlevit.org/ru/blog.rss

на определённом блоге (например, tech)

http://vlevit.org/ru/blog/tech.rss

с определенным тегом (например, велосипед)

http://vlevit.org/ru/blog/tech/tag/велосипед.rss

Также есть три типа лент на комментарии: на все комментарии во всех блогах, на все комментарии в определённом блоге (например, tech) и комментариям к определённому посту (например, vlevit-org). Соответственно ленты будут такими:

http://vlevit.org/ru/blog/comments.rss
http://vlevit.org/ru/blog/tech/comments.rss
http://vlevit.org/ru/blog/tech/vlevit-org/comments.rss

Если блог доступен на английском языке, то к нему можно подписаться, заменив в вышеприведенных ссылках ru на en.

План переезда

Все содержимое технического блога до этого поста находилось на zeuhl-mode. Полгода назад я перевёл zeuhl-mode на собственный домен blog.vlevit.org. Через некоторое время я настрою перенаправление с blog.vlevit.org на vlevit.org и постараюсь сохранить все старые ссылки действительными. Старый блог zeuhl-mode останется на Blogger'е — не люблю, когда люди всё своё забирают с собой.

Читайте с удовольствием!


  1. То есть 16px для большинства браузеров. 

  2. А без удовольствия не читайте! 

Комментарии

RSS
Здесь можно Markdown