2009/10/31

Как написать фреймворк за два часа, часть 1, про Сущности и Хранилища

Наше тело получает жизнь из пустоты. Существование там, где ничего нет, составляет смысл слов: "Форма есть пустота". Слова же: "Пустота есть форма" свидетельствуют о том, что пустота содержит в себе вещи. Не следует полагать, что пустота и вещи суть различны.
Сегодня решил написать не про модули, а про сущности и хранилища; просили.
Вспомним договорённости.
Подумаем про хранилища. Напишем:
interface CRUD
{
public function & create();
public function & read($criteria);
public function update();
public function delete($criteria);
}
почему так? рассказываю дальше:
abstract class StorageEngine implements CRUD
{
protected $__entity;
function __construct($what)
{ $this->__entity = $what; }

function __destruct()
{ $this->update(); }

// здесь ещё раз список методов, т.к. конкретную реализацию оставим для неабстрактных классов
}
ясно? или не полностью?
Возврат значений по ссылке обеспечивает обратную связь сущности (ещё не объявленной) с хранилищем, которое деструктором закрывает сущность, сохраняет её на физическом уровне.
Методы обеспечивают элементарный доступ к сущностям, сложенным в хранилище.
create обеспечивает динамическое создание копии сущности (пока только в памяти времени исполнения)
read читает коллекции сущностей из физического хранилища
update сохраняет коллекцию обратно
delete удаляет быстро и беспощадно
$criteria - признак выборки, XPath

Понимаете ведь, что это только здесь всё так красиво :) Внутри там конкретный аксессор к конкретному хранилищу и много других радостей. К которому можно подключить доп. драйвер и простенький шаблонизатор SQL для совсем уж чудных запросов. Для наших задач вполне хватает $accessor->query('SELECT _read(:criteria)', $array('citeria'=>$criteria));
Как кому-то уже понятно, в качестве драйвера используется PDO::PG, а сами выборки переложены на могучие плечи субд, на пользовательские функции. (Конкретнно чтение, выборку по критерию правильнее было бы оформить через VIEW, но я пошёл по пути унификации. И ещё: в процессе написания функций я обнаружил, что постгрес поддерживает перегрузку функций - функции с одним именем, но разным набором параметров)


Про сущности же подумаем так:
interface XML
{
function asXML();
function XPath();
}
Это два метода, которые нам необходимы. Первый для преобразования объекта к читабельному виду, второй для удобной работы. Да-да, XPath гораздо удобней, чем in_array(). Освоение множеств XML и преобразований требует некоторого мозга, но особого труда не составляет, будем работать с нормальными технологиями.
Кто использовал XML с PHP, конечно же, уже узнал этот интерфейс :) Да, это SimpleXML. Не будем изобретать сущности, извините за тавтологию, воспользуемся имеющейся.
class Entity extends SimpleXMLElement implements XML
{
// здесь меня ожидало несколько весьма занятных ээ... особенностей реализации языка. например, нельзя переопределить конструктор. пришлось изобретать конструкцию загрузки сущностей из схем и других источников, типа такой

static function load($source)
{
if (isXML($source)) $xml = $source;
if (is_file($source)) $xml = file_get_contents($source);
return new self($xml);
}
}
Со статическими методами тоже получилось интересно, почти неделю парился, уже думал, что пхп не поддерживает их перегрузку. Оказалось ещё хитрее ;) До ветки 5.3 self указывает не на текущий класс, а на класс, в котором был написан. То есть наследовать от Entity можно только с переопределением загрузчика. Но в принципе, особой нужды в этом нет, SimpleXML дал нам Entity::getName(), который выдаст имя корневого элемента (здесь необходимо вспомнить правила оформления XML;)

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

Вопросы?

зы: ах да, пример
$sth = new EntityStorage( Entity::load('scheme.xml') );
$sth->create();
или
$data_collection = & $sth->read('user/profile[name="USERNAME"]');
foreach ($data_collection as $user)
{
print $user->id;
print $user->profile->name;
}
$user->profile->name = 'LASTUSER';
$sth->update();

и замечание напоследок: нет, это не ORM, здесь отсутствует преобразование из плоской формы в объектную. На Observer похоже, но отсутствует подписка на изменения. Как назвать, не особенно важно, оно работает =%)

2009/10/20

OpenID + php

Очень хорошо написано здесь http://www.oneid.ru/info/openid-php/ про библиотеку http://openidenabled.com/php-openid/ самая большая с обширной документацией. Много кода, требует cURL и матэкстеншн GMP

Но есть и альтернативные решения вроде http://www.phpclasses.org/browse/package/3290.html

upd: php-openid поддерживает и pgsql тоже =:)

upd2:

Не стал писать новую заметку, но увиденное слегка шокировало

файл примера из библиотеки:
// For OpenID 1, send a redirect. For OpenID 2, use a Javascript
// form to send a POST request to the server.

и оно действительно делает
$form_html = $auth_request->htmlMarkup(getTrustRoot(), getReturnTo(),false, array('id' => $form_id));
 
// otherwise, render the HTML.
print $form_html;

бред какой-то. мощнейшая библиотека, и столько хлама. надо переписывать, срочно.

там ещё и втф встречается типа
function & fn($param){ ... return new someClass($param) }

зы: документация уг, либо я её неправильно читаю. кста, если кому-нить захочется почитать доки, надо начать с класса Auth_OpenID_AuthRequest, а потом перейти к Auth_OpenID_Consumer. Auth_OpenID включить, разумеется, забыли; он находится в файле OpenID.php

2009/10/14

Как написать фреймворк за два часа, часть 0

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

Сейчас мы позанимаемся образцово-показательным проектированием и планированием. Да и вообще, делать что-либо без идеи и цели не имеет никакого смысла, пустая трата времени. Итак, приступим.

Определим цели. Во фреймворке необходимо обеспечить:
  • доступность понимания структуры и кода, чтобы начинающий программист мог его освоить
  • некоторый уровень технологий, чтоб джыдаю было не скучно
  • не изобретать велосипедов
  • зы: совсем забыл! заложить в архитектуру максимально возможный уровень расширяемости и не заниматься преждевременной оптимизацией
Осмотревшись, мы находим PHP - достаточно распространённый скриптовый язык с очень (ОЧЕНЬ!) низким уровнем вхождения. В принципе, это проблема пхп, из-за которой он получил дурную славу. Попробуем вернуть языку его достоинство.
Внутренним (и внешним) единым форматом передачи данных примем XML. Что может быть проще и технологичней?
И в случаях затруднений будем руководствоваться принципом KISS Keep It Simple, Stupid - Не тупи, будь проще.
Маленькое лирическое отсутпление. Во время работы в %COMPANYNAME% в среде программистов был изобретён принцип JMS Just Make Simple - Просто сделай проще. От часто прозносимых фраз: "Давай сделаем это проще", "Я знаю как проще". Стали ли они продолжать линейку JMS CMS, я не в курсе.
Продолжаем. Пишем мы фреймфорк для веба, то бишь, чтоб делать сайты. Сайт, в конечном итоге, это текст, причём, текст структурированный. Понятию тега разметки практически идеально соответсвует понятие блока. Да и визуальное оформление обычно составлено из вложенных блоков.
Введём основное понятие фреймворка: модуль - основная и единственная структурная единица фреймворка. Хотя, на самом деле,)) модуль может быть и исполняемым кодом, и шаблоном, и чем-нибудь ещё.
Введём соглашение: каждый модуль обязан возвращать XML. Всегда. Пусть пару строк, но возвращать (как будет видно дальше, мы немного отсутпим от правила, самую малость). Обратно, всё, что не является модулем, не обязано возвращать XML и всё, что не возвращает XML, не является модулем.

Вспомним хитрое слово ReST, которое, в принципе, ничего конкретного не представляет, или, наоборот, представляет слишком многое. Это и технология, и способ, и принципы, и идея; остановимся на слове RESTful подход. Для нас это будет означать Человеко-Понятный Урл + принцип передачи параметров (формирования запросов) в модули + структурированность иерархии модулей, аналогичную URL.

Принцип работы сайтов, по большому счёту, заключается в получении данных, их сохранении и визуальном оформлении.
Основной единицей информации назначаем сущность - Entity. Сущность подготавливается по описанию. Это второй объект, который мы напишем. Первым будет, конечно, хранилище (Storage) сущностей. Хранилище должно реализовывать интерфейс CRUD Create Read Update Delete. Элементарно.
Введём второе соглашение: каждый объект, работающий с данными, принимает и\или возвращает объект типа "сущность".

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

Хм, теперь под выбранную идеологию подберём инструментарий. Это будет:
  • уже упомянутый PHP в связке с Apache. Тип связи с веб-сервером и сам веб-сервер могут быть любыми, это пока не принципиально, но Apache + mod_php весьма распространены, будем ориентироваться на такой тип.
  • т.к. XML клиенту (пользователю) не интересен, подключим XSLT и нагрузим преобразованиями клиента (браузер) - проверено, работает
  • добавим к этому грамотный CSS и какой-нибудь javascript framework: не мудрствуя долго, остановим выбор на jQuery
  • выбор физического воплощения хранилища представил некоторую проблему. Основное требование: нативное хранилище объектов. Но объектно-ориентированные базы весьма нетривиальны и не удовлетворяют требованию простоты фреймворка.
    Ещё одно лирическое отступление. В процессе поиска наткнулся на одно интересное решение: база не имеет собственного клиента, доступ через http RESTful или через API, возвращает xml или json, обращаться можно хоть из javascript. Оригинальное решение и достаточно старое. Но я не поставил вовремя закладку, а название забыл! %( Но в этот фреймворк тоже не подходит в виду излишней оригинальности.

    Остановился на PostgreSQL с дополнением для XML, кстати, прекрасно работает.
    Не забываем переложить бизнес-логику на базу, это её прямое назначение.

Итак, что мы насобирали:
RESTful + modulability (гхм)
XML
Entity-Storage-CRUD
PostgreSQL
PHP
Apache
XSLT+CSS+jQuery

Всё!
Энжой :)

За два часа вроде бы уложился

зы: тру пхп-кодер спросит: где же шаблонизатор? а вот php и есть шаблонизатор, если кто не в курсе

2009/10/09

Программисты, моноширинные шрифты и виндовс

Да, программеру без равномерных фонтов никуда. А какие фонты в винде, ну вы помните, да?
На этот курьер я смотрю лет десять, наверное. Надоело. Бесповоротно.

Было выяснено, что тру-джыдаи давно используют нормальные шрифты, как то: Terminus и Consolas; затем, в процессе сёрфинга, к ним добавились Liberation, Bitstream Vera, и вспомнился Monaco. Выгуглено было страниц под сотню и выяснено, что:
  • Consolas свободно сливается с сайта производителя. Но представляет собой Clear-Type шрифт, что мне не подходит технически: на ЖК с невысоким разрешением клеартайп размазывается между пикселями. Но кому глаз не режет - в принципе, хвалят.
  • Туда же, кстати, ушёл Bitstream Vera, который вроде бы и есть в поставке висты, но можно слить с гнома.
  • Monaco ищется достаточно легко, шрифт старый, известный. Но не нашёл русских букв.
  • Terminus я искал долго. В смысле, чтоб с кириллицей. Так и не нашёл. Без кирилицы - "первая ссылка в гугле". Если у кого вдруг есть terminus-cyr.ttf, пришлите, пожалуйста на почту.
  • В процессе поисков были обнаржуны залежи полезного, но буржуинского http://stackoverflow.com/questions/4689/recommended-fonts-for-programming, http://www.codeproject.com/KB/work/FontSurvey.aspx, http://damieng.com/blog/2007/11/14/droid-sans-mono-great-coding-font. А также поставлен растровый фонт из этой ветки. Первая удача! он заработал. Мне понравилось
  • И Liberation - это шрифт от RedHat. Можно взять с официального сайта. Было ли это ошибкой, но сначала я слил и поставил файл с самым большим номером версии, но шрифт в списке не показался. И я пошёл искать всё прочее, о чём выше. А потом я слил файл с самым коротким названием ;) и заработал Liberation Mono, остальные из пакета почему-то отказались.
Вот так мы поменяли шрифты =:)

Не прощаюсь

2009/10/07

Юзабилити не существует

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

Среди свитков, висящих на стене у господина Наосигэ, был свиток со словами: "К важным делам следует относиться легко".


Как я написал в каком-то каменте, меня не перестают удивлять люди, занимающиеся как бы "юзабилити". Хабрапипл вполне представляет, чем чреваты подобные хабразаявления.
Казалось бы, толпы народов съезжаются, устраивают конференции, изводят тонны макулатуры и человеко-лет. На что? А ни на что. Сейчас в очередной раз посмотрим, как получать деньги из воздуха.

Ведь и правда, нельзя делать подобные заявления голословно, нето %юзернейм% негодуэ оппоненты сильно расстраиваются.
Университетов мы кончали, распишем всё по трафарету.

Начнём с названия. Юзабилити - us-ability use-ability - хмм... возможность использования? в приниципе, это бинарное состояние: можно пользоваться \ нельзя пользоваться. Но километры копий не даром же сломаны?

Хорошо, вспомним, что "абилити" имеет характеристический оттенок, а "юз" может служить мерилом полезности. Наверное, предполагаем дальше, эти замечательные люди изучают степень пользибельности ээ... объектов окружающего мира, замеряют её специальными полезнометрами, строят кучу графиков и схем, по которым оказывается, что лимон, выращенный на солнечной стороне холма на 5 полезнопоинтов полезней.
На таком материале делают докторские.

Включив немного мозга и обратившись к источникам интернетам, мы узнаем, что юзабилити... м-м - как бы это по-мягче сформулировать - ничем не является.

Оно не является научной дисциплиной по причине отсутствия аксиоматического аппарата, объекта исследования и подхода изучения - это почти основные элементы, отличающие (характеризующие) науку от прочих сфер человеческой жизнедеятельности. (Не лезем в философию и проблему демаркации, ок?)
Но оно и не является сферой человеской деятельности! Так-то!
Словцо это обозначает всего лишь определение понятия в подразделе эргономики - микроэргономике. ("обозначает определение понятия" это я красиво загнул ;) вообщем, вы поняли, да?)

...the extent to which a product can be used by specified users to achieve specified goals with effectiveness, efficiency and satisfaction in a specified context of use.

Э-э! посвятить всего себя изучению одного понятия - задача, достойная философа. Ещё раз к месту слово "докторская". Но я подозреваю малое количество мизантропов-отшельников среди этих удивительных людей.

Увидев этот свиток, мастер Иттэй добавил: "К несущественным делам следует относиться серьёзно".


Пойдём с другой стороны, попытаемся сформулировать род занятий "юзабелист" через перечисление (грязный антинаучный хак). Занятие представляет собой попытку предсказать реакцию (удовлетворённость) и поведение (продуктивность) определённых групп людей при попытке взаимодействия (эффективность) с продуктом.
Вот для чего сотни мегабайт букв, озаряет нас внезапная догадка! Юзабелист подобен древнему врачу, практически вслепую ведущего команду инженеров, проектировщиков, маркетологов, художников и рабочих сцены к светлому приятию конечным пользователем светлых идей, воплощённых в качественном продукте.

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

Попробуем дать хоть какое-то научное обоснование.

По моему скромному мнению, человеческими деяниями управляют два фактора. Точнее, даже один. Инстинкты. Не будем опускаться до полной павловщины, это сильное такое допущение, но остановимся, как на одном из самых понятных.
Так вот, люди всё делают либо по привычке, либо по глупости. По привычке выполняются знакомые операции, уже повторенные несколько раз: свет вкл\выкл, зубная щётка на полке слева, крестик справа сверху, ссылка - синяя и\или подчёркнутая, центр-клик = опен ин нью таб, поиск где-то рядом, в меню можно выбирать, между абзацами обычно отступ два\полтора интервала, колбаса хороша в салате. Это не только приобретённые инстинкты, но и врождённые, типа частоты дыхания, изменения состояния от воздействия определённых цветовых сочетаний, инстинкт слежения [взглядом], моргание, зевание.

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

Таким образом получается, что юзабилити, как наука, могла бы располагаться на стыке физиологии, психологии, философии, инженерии и архитектуры, изучая психомоторные реакции контрольных групп на цветоформовые раздражители. Что-то я не наблюдаю в сообществе подобных выкладок. Но только советы, свалку несистематизированных правил (хорошо, их можно назвать эмпирическими), и предложения обучить, исправить, удлиннить, проанализировать и проконсультировать.

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


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


Успехов и до новых встреч.

Юзабилити не существует! =;)

2009/10/01

Торвальдс о GIT

Хороший парень перевёл выступление Л. Торвальдса о GIT на Гуглтолк
Смотреть и слушать на хабре или ютубе