Наверняка любой разработчик, который пишет для web сталкивался с проблемой кэширования контента. При этом проблема может делится на две части: кэширование динамического контента и кэширование статического контента. Эти проблемы связанные с оптимизацией времени загрузки сайта. Я же подойду к этой проблеме с другой стороны: проблемы с кэшированием при разработке. Ведь все мы сталкивались с тем, что при изменении всего-лишь одной строке в javascript или изменении класса в CSS приходится в очередной раз очищать кэш браузера. И никакие магические сочетания Ctrl + F5 не помогают. В случае с Internet Explorer не всегда помогает даже очиситка кэша (Ctrl+R) в IE Developer Tools - приходится это делать стандартными средствами браузера.

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

Уточню, что я редко использую веб-сервер, встроенный в Visual Studio, т.к. считаю что IIS, встроенный в Windows Vista/7 более приближен к тому решению, которое будет на stage и production environments. Из этих же соображений некоторый используют Windows Server на своих рабочих станциях.

Как всегда, сначала немного теории о том, как это всё кэширование работает.

В заголовке ответа от веб-сервера (Response) может быть поле Cache-Control, которое говорит браузеру о том, как нужно кэшировать полученный файл. Самые используемые поля это:

  • no-cache - отключить кэширование;
  • max-age - максимальное время (в секундах) жизни закешированного ресурса;
  • min-fresh - минимальное время (в секундах) жизни закешированного ресурса.


Так же часто используется параметр “Expires”, который содержит дату, когда необходимо будет заново загрузить ресурс с сервера.
Подробнее о всём это можно почитать в спецификации HTTP протокола по адресу http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html.

Ещё одним способом указать браузеру, что запрашиваемый ресурс не изменился является ответ с кодом “304 Not Modified” (http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html).

Таким образом, для отключения кэширования нам достаточно всегда добавлять поле no-cache в заголовок response. Побочных эффектов я тут вижу два:

  • нужно не забыть потом включить кэширование;
  • при отключенном кэшировании производительность сайта может значительно упасть, но я надеюсь, что у всех нас имеются достаточно мощные ПК для комфортной работы/разработки.

Подробно всё уже давно описано на сайтах Technet (http://technet.microsoft.com/en-us/library/cc770661(WS.10).aspx) и IIS (http://www.iis.net/ConfigReference/system.webServer/staticContent/clientCache), поэтому повторяться не буду, тем более что у меня вряд ли получится написать лучше. Скажу только пару слов о моём решении.

Кэширование я отключаю с момощью комманды “appcmd set config /section:staticContent /clientCache.cacheControlMode:DisableCache”, которую я поместил в bat-файл discache.bat.

Включаю аналогичной командой “appcmd set config /section:staticContent /clientCache.cacheControlMode:NoControl” из файла encache.bat.

Ярлыки для этих файлов можно поместить в удобное для вас место либо добавть путь к ним в переменную окружения PATH для быстрого доступа к ним из любого места. Таким образом включение/выключение кэширования происходит одним кликом/одной строчкой в командной строке и позволяет избавиться от всех проблем при активной работе с javascript, CSS и картинками.


[Update]

Теперь пункт "Ссылка на сайт(блог)" в анкете является необязательным.

[/Update]

Всем привет. Особый привет моим постоянным читателям и тем, кто активно комментирует.

Так уж сложилось, что последние 4 года я занимаюсь разработкой веб-приложений на платформе .NET о чем пишу в своём блоге. Последний год начал интересоваться Python'ом, более активно им интересуюсь последние полгода. Из-за этого начали появляться посты о Python и связанными с ним вещами. Догадываюсь, что некоторым может быть это не интересно, а мне создавать отдельный блог для этого не хочу, но и терять .net-ориентированную аудиторию не хочется, особенно учитываю то, что со многими (или не многими :)) знаком за пределами online-пространства.

Суммируя вышесказанное, предлагаю вам ответить на один или более вопросов о блоге и его RSS ленте.

Результаты опроса обязательно опубликую через неделю-две после выхода этого поста.

Также вас ждёт небольшой сюрприз в формате блога, но об этом все узнают только завтра :(


jQuery - достаточно мощный и удобный javascript framework. Последняя версия 1.4.4 имеет размер 179KB для разработчиков и всего-лишь 26KB для использования в production. 26 килобайт кода не много, но в таком сжатом формате разобраться практически не возможно даже с помощью дебаггера. В неупакованный версии разобраться проще, в дебаггере всё выглядит хорошо, но всё-равно все тонкости работы и устройства jQuery проходят мимо нас. В 7180-ти строках javascript-кода даже с помощью средств IDE и не менее мощной комбинации Ctrl+F  найти нужный кусок кода не так уж и просто.

Что же делать тем, кто хочет разобраться к том, как работает jQuery? Ответ достаточно простой: скачать исходники. Звучит странно и непонятно. В голове возникает вопрос: какие могут быть исходники у библиотеки, написанной на javascript? Под фразой “исходники jQuery” я подразумеваю то, что лежит у них в репозитории http://github.com/jquery/jquery.

 


Сразу уточню, что описываю я бранч версии 1.4.4. В текуoем master branch (trunk), в котором идёт работа над версией 1.5, переработан модуль ajax, из-за чего все, что к нему относится, вынесено в каталог /src/ajax. Кроме того, разработчики настоятельно не рекомендуют использовать последнюю версию из репозитария для production использования. На момент написания этого поста последняя версия - 1.5pre.

Итак, вернёмся к нашим баранам исходникам.  В корне у нас есть следующие 4 каталога, файлы лицензий и файлы для build-систем (make и ant):

  • build - файлы, необходимые для сборки;
  • speed - тесты на производительность (benchmarks): необходимы для того, чтобы измерить производительность текущей версии, по сравнению со собранной из исходников; если вы не вносили никаких изменений - время выполнения обоих скриптов будет одинаковым;
  • test - unit tests (модульные тесты), написанные с помощью qunit;
  • src - сами исходники jQuery.

Для сборки необходимы Java 1.6.0 и выше и NodeJS, если вы будете собирать из master branch. Сборка выполняется одним из двух способов: с помощью ant, которому нужно передать в качестве параметра файл build.xml, либо с помощью выполнения команды make, которая доступна во всех *nix-системах. После сборки файлы jquery.js и jquery.min.js будут находится в папке /dist.

Какие же есть преимущества у использования такой версии jQuery? На мой взгляд, стоит выделить такие:

  1. В исходниках значительно проще разобраться, чем в одном собранном файле. Здесь каждый модуль расположен в отдельном файле (css.js, event.js и т.д.), что даёт возможность быстро и легко узнать как это всё работает. Этот способ и натолкнул меня на  этот подход к использованию jQuery и написанию этого поста.
  2. Есть возможность отключить ненужные/не используемые модули для уменьшения размера итогового файла. Этот подход применяется при скачивании http://jqueryui.com/download с нужными компонентами.
  3. Можно вносить необходимые для проекта изменения и с помощью тестов убедиться что всё работает. Эти изменения также можно будет предлагать разработчикам jQuery в виде патчей.
  4. При использовании последней версии вы становитесь бета-тестерами и вносите свой, пусть и небольшой, но всё же вклад в развитие проектов :).


По своему опыту могу сказать, что даже для тестовых приложений использование самых последних исходников приносит достаточно много проблем: иногда это просто не собирается (http://forum.jquery.com/topic/can-t-build-latest-jquery-from-the-git-repository), могут не работать многие плагины, особенно с учетом переработанного в версии 1.5pre модуля ajax. Но при использовании бранча с последнего стабильного релиза, inho, плюсов значительно больше.


 

Так уж сложилось, что мне было необходимо выбрать framework для разработки небольшого приложения на python + GAE. Первым делом я посмотрел в сторону Django и немного огорчился, узнав что теперь GAE team рекомендуют использовать форк django-nonrel - практически тот же django, но дающий возможность простой работы с NoSQL базами данных. Так как django-nonrel все ещё не достиг версии 1.0 и имеет ряд недоработок, которые разработчики обещают исправить в ближайшее время. Из недостатков, которые для меня оказались решающими стоит отметить - не работает с GAE “из коробки”, соответственно необходимо многое доустанавливать-настраивать руками, на что не хотелось тратить время. Позже я обязательно напишу про этот фреймворк, но уже на примере django-nonrel + MongoDB. Тем временем мне порекомендовали посмотреть в сторону tipfy, на котором я остановился и о котором написан этот пост.

Как написано на сайте http://www.tipfy.org/, tipfy - маленький, но мощьный web framework, сделанный специально для GAE (“tipfy is a small but powerful framework made specifically for Google App Engine”). Текущая версия - 0.6.4, что говорит нам о том, что у него всё ещё впереди.

tipfy действительно очень маленький и быстрый, но благодаря расширениям (extensions) быстро приобретает необходимую функциональность. Посмотрим на структуру архива, который можно скачать по адресу http://www.tipfy.org/tipfy.zip

 

 

 

Всё, что лежит в корне архиве необходимо только для сборки своей версии tipfy, с добавленными или отключенными расширениями. К слову, добавление или отключение какого-либо расширение осуществляется редактированием всего одной строчки в файле buildout.cfg и запуском билд-скрипта, который загрузит и установит нужные расширения. Подробнее об этом можно почитать на странице http://www.tipfy.org/wiki/guide/extensions/#adding-or-removing-extensions

 

Всё, что необходимо для запуска и работы приложения находится в каталоге app. Как видно на скриншоте, там уже есть приложение “hello world” (куда же без него? :)). После “hello world” сразу же бросается в глаза jinja2 - достаточно известный template engine с хорошей докоментацией и сообществом. Если по каким-то причинам вам не нравится(перечеркнуто) подходит jinja, можно использовать Genshi или Mako.

В целом, приложение с использованием tipfy практически ничем не отличается от любого MVC-приложения, за исключением, конечно, специфики фреймворка.

Рассмотрим приложение “hello world” более детально.

Так как, это достаточно простой пример, то никакой модели нет. Но в случае необходимости - модели будут представлять собой обычные классы, наследуемые от GAE db.Model:

 

Наше приложение состоит из двух модулей (url.py и handlers.py) и одного шаблона (hello_world.html).

urls.py:

Содержит правила маппинга url-адресов на обработчики. По умолчанию их два:

 

  • Rule('/', endpoint='hello-world', handler='apps.hello_world.handlers.HelloWorldHandler') - указывает какой обработчик должен обрабатывать default page
  • Rule('/pretty', endpoint='hello-world-pretty', handler='apps.hello_world.handlers.PrettyHelloWorldHandler') - обработчик, который выполнится при открытии http://yoursite.com/pretty

 

handlers.py:

Каджый handler представляет собой класс, который наследуется от RequestHandler и имеет методы get(), post и др. для обработки соответствующих типов запросов.

В нашем случай это: 

 

 

 

В целом отмечу что переход с django на tipfy не вызывает никаких трудностей, только несколько маленьких неудобств, а именно: отсутствие уже готовой админки (частично, её может заменить аналога приложения в GAE) и другой template engine (хотя, многие успешно используют jinja в djanпo).

Такое короткое введение в tipfy и GAE. Продолжение следует...

 


Проблема с использованием разных версий софта практически настолько же стара как мир разработки этого самого софта. Смотря со стороны разработчика, то самый простой случай - это когда нужно пофиксить какие-либо баги в предыдущей версии. Проблема заключается в том, что для dev environment уже используется более новая версия python, django и/или другого, необходимого для проекта, ПО. В более “тяжелом” случае все становится еще интересней: в production одно, на stage -  другое, на машине разработчика - третье, а тут еще нужно писать под google app engine, для которого требуются специфические (старые) версия python/django. 

Первой моей идеей было поднять разные виртуалки для тестирования, но немного погуглив наткнулся на такую замечательную вещь, как virtualenv. Как написано на оффициальном сайте - “virtualenv is a tool to create isolated Python environments”, что в переводе звучит, примерно, так: “virtualenv - приложение для созданий изолированных рабочих сред для python”. Таким образом вы можете создать несколько окружений с разными версиями python и/или других библиотек. 

Установка virtualenv ничем не отличается от установки любой библиотеки, написанной на python. В моем случае установка выглядила так:

sudo easy_install virtualenv

После установки virtualenv процесс создание виртуального окружения состоит всего лишь из одной команды:

virtualenv -p /usr/bin/python2.5 ./gae/

Здесь с помощью параметра -p я указал версию python, которую необходимо использовать для виртуального окружения. Последним параметром идет путь к  директории, в которой необходимо все создать. Так же рекомендуется добавлять параметр --no-site-packages, для того, чтобы из виртуального окружения не было доступа к пакетам из “реальной” среды (из встроенной справки: Don't give access to the global site-packages dir to the virtual environment). У себя этот параметр я не использовал по следующей причине: на рабочем PC mbp я использую такую схему библиотек:

  • последняя версия python и необходимых библиотек устанавливается обычным образм, без virtualevn;
  • если для каких-то причин необходимы другие версии интерпретатора или библиотек - создаю virtualenv;
  • в virtualenv доустанавливаю только те библиотеки, версии которых должны отличаться от реальной среды моей ОС (в моем случае - необходимо использовать более старую версию).

Теперь, после создания virtualenv появилась такая структура папок:

bin include lib

В Windows-like OS структура папок может немного отличаться.

$ python --version

Python 2.6.5

$  ./bin/python --version

Python 2.5.4

Например, мне нужно запустить GAE-приложение с использованием django.  Если я его запущу в текущей конфигурации моей рабочей машины, то получу следеющую ошибку:

UnacceptableVersionError: django 1.0 was requested, but 1.2.1.final.0 is already in use.

Поэтому, мне необходимо установить django 1.0 в созданное виртуальное окружение. Описывать процесс загрузки и распаковки не буду, надеюсь, с этим справятся все, а перейду сразу у описанию установки.

Для переключения в виртуальное окружение проще всего использовать скрипт activate, который лежит в каталоге bin нашего  vitrualevn:

e0ne-macbook:gae e0ne$ source bin/activate

(gae)e0ne-macbook:gae e0ne$ python --version

Python 2.5.4

Для выхода из виртуального окружения существует команда deactivate:

(gae)e0ne-macbook:gae e0ne$ deactivate 

e0ne-macbook:gae e0ne$ 

Перейдем непосредственно к установке djngo в созданное виртуальное окружение. Установка любого python-пакета в virtualenv ничем не отличается от обычного процесса установки и выполняется всем знакомой командой:

(gae)e0ne-macbook:Django-1.0.4 e0ne$ python setup.py install

Теперь у меня есть 2 полноценных рабочих среды с простым и быстрым переключением между ними.

Я описал лишь базовые возможности пакета virtualenv, но и этого вполне достаточно для того, чтобы увидеть всю его мощь, спрятанную я простым и понятным интерфейсом. Как всегда, все подробности на оффициальной странице: http://pypi.python.org/pypi/virtualenv