Авторизация в Google, “Site is not registered”

Май 30th, 2011

При авторизации в гугловской реализации OAuth рано или поздно приходится наткнуться на чрезвычайно информативное сообщение:

The site “http://xxx” has not been registered

Как почти всегда у гугла проблема, после того как к ней потерял интерес разработчик с рабочим местом в форме змеи подвешенном на дереве не решается годами и не планируется быть решенной никогда.

Решение проблемы:
Continue reading →

Эффект использования PHP/APC

Май 14th, 2011

Задача – иметь REST-бакенд, который отрабатывает нажатия клавиш пользователем в интерактивном режиме. Скорость реакции при этом критична.

Накладные расходы при обработке REST-запросов связаны во-первых с нахождением обработчика для каждого URL’а, а во-вторых с подгрузкой кода обработчика. Очевидно, что include’ить на каждое обращение код всех возможных сервисов это сильно по индийски.

Обе задачи изящно решаются с использованием кеширования при помощи APC. Первый REST-запрос приводит нахождению файла, который содержит описание класса ответственного за сервис (spl_autoload_register), создание экземпляра класса и помещение URL’а запроса и экземпляра в кеш. При каждом следующем обращении к этому же URL’у, объект-обработчик мгновенно находится в кеше без чтения/интерпретации файла и без создания нового экземпляра.

Результат – трехкратное сокращение обработки запроса:

Хотется посмотреть на цифры J2EE’шного REST-сервера. Может быть дойдут как нибудь руки.

Реализация среды для анализа кода

Май 13th, 2011

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

Для контроля качества кода у нас используется связка Fisheye+Crucible регулярно мониторищая репозитарий через который проходят все изменения.

Техническая проблема состоит при этом в том, что Fisheye/Crucible с одной стороны потребляют значительное количество ресурсов и, при практическом использовании, регулярно доводят сервер до неспособности обслуживать другие сервисы, с другой же стороны постоянный мониторинг SVN репозитария при использовнии и svn-протокола и, тем более, http оказывается неприемлемо медленным.

Решение пришло в виде микро-инстанции Amazon EC2 – ее стоимость вполне допускает выделенный J2EE сервер обслуживающий только Fisheye/Crucible, а NFS доступ “только чтение” к другой инстанции EC2 на которой расположен SVN репозитарий по внутренней сети Amazon Cloud обеспечивает и быстрое сканирование и практически нулевую стоимость сетевого трафика.

ExtJS 4: использование ассоциаций

Май 13th, 2011

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

Во-первых, в одном классе объединены фактически две разных функциональности. Одна – это трансляция в Ext.data.Model сложных типов данных с вложенными объектами, а другая – это работа с реляционными моделями. При том, что используется одно и тоже API входные параметры и возвращаемые результаты оказываются разными и принимают разные значения. Чтобы убедиться/ужаснуться с чем приходится иметь дело достаточно посмотреть на этот фрагмент:

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

Итак, вначале вариант со сложными данными. Пусть имеется вот такая JSON-структура:

[{
    id: 1,
    site: 'www.armour.up',
    component: {
      id: 2,
      name: 'theme'}
 },{
    id: 3,
    site: 'www.armour.up',
    component_id: 4
    component: {
      id: 4,
      name: 'plugins'
    }
}]

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

Ext.define('D.model.Deploy', {
  extend: 'Ext.data.Model',
  alias: 'model.deploy',
  fields:[{
    name:'id', type: 'int'},{
    name:'site', type: 'string'},{
  }],
  associations: [{
    type: 'belongsTo',
    model: 'D.model.Component',
    associatedName: 'Component', 
    instanceName: 'component' 
  }],

Самое сложное и путанное здесь – это опции assotiations.
model должна быть полным путем, так как определяет имя класса-модели для дочерней записи;
associatedName будет использоваться для автоматического именования производных полей:

name        : associatedName,
foreignKey  : associatedName.toLowerCase() + "_id",
instanceName: associatedName + 'BelongsToInstance',
associationKey: associatedName.toLowerCase()
getterName     = me.getterName || 'get' + associatedName,
setterName     = me.setterName || 'set' + associatedName;

instanceName – это имя поля родительской модели в котором сохранится созданная дочерняя модель. Можно его оставить в ComponentBelongsToInstance, но я предпочел более логичное component

Дальше все просто, при чтении структуры данных моделью Deploy для дочерних элементов component будут создаваться соответсвующие модели D.model.Component (описание опущено за очевидностью), которые будут доступны либо по record.component(record.ComponentBelongsToInstance) либо record.getComponent().

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

[{
    id: 1,
    site: 'www.armour.up',
    component_id: 2
    },{
    id: 3,
    site: 'www.armour.up',
    component_id: 4
}]

а имена компонент нужно получать отдельным запросом. Тогда описание ассоциации радикально меняется:

  associations: [{
    type: 'belongsTo',
    model: 'D.model.Component',
    associatedName: 'D.model.Component',
    getterName: 'getComponent',
    name: 'component',
    foreignKey: 'component_id',
    instanceName: 'component'
  }]

Неприятности начинаются из-за того, что в одном месте в коде associatedName используется для определения класса модели и поэтому должно быть полными путем. Из-за этого имя геттера, например, становится очень кучерявым: getD.model.Component, что явно не то, что кто нибудь может хотеть. Чтобы избежать таких проблем приходится явно именовать все остальные опции. Ну и указать имя поля в модели, которая является ключом для поиска связанной foreignKey.

Кроме того, что меняется описание ассоциации, совершенно иначе себя начинает вести getComponent. Эта функция больше не возвращает никакого значения, а напротив принимает параметром две функции, каждая из которых вызовется в случае успешного и неуспешного запроса связанного объекта:

  record.getComponent({
      success:function(a,b){console.log(a);console.log(b)}
      failure:function(a,b){console.log(a);console.log(b)}
    });
«  1 2 3 4 5 6 7 8 9 10 11 12 13   »