﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>Software People</title>
	<atom:link href="http://softwarepeople.ru/feed/" rel="self" type="application/rss+xml" />
	<link>http://softwarepeople.ru</link>
	<description>Software People</description>
	<pubDate>Mon, 30 Aug 2010 22:00:58 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>CSS3 в IE 6-8 любой ценой</title>
		<link>http://softwarepeople.ru/blog/2010/08/26/css3_ie_6_8/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/26/css3_ie_6_8/#comments</comments>
		<pubDate>Thu, 26 Aug 2010 09:53:09 +0000</pubDate>
		<dc:creator>Software People Team</dc:creator>
		
		<category><![CDATA[web-разработка]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=3072</guid>
		<description><![CDATA[Автор статьи: Денис Кийко

Мне, как наверное и многим другим, очень хочется при верстке использовать плюшки CSS3. Все большая поддержка 3 уровня каскадных таблиц такими браузерами как Opera, Firefox, Safari, Chrome и даже Explorer 9 только подогревает это желание, но как обычно есть «но», IE6-8. При этом стоит понимать, что аллергия IE9 к winXP откидывает мечту [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Автор статьи: <a href="http://beatlejute.habrahabr.ru/">Денис Кийко</a></strong><br />
<hr noshade color="eeeeee">
Мне, как наверное и многим другим, очень хочется при верстке использовать плюшки CSS3. Все большая поддержка 3 уровня каскадных таблиц такими браузерами как Opera, Firefox, Safari, Chrome и даже Explorer 9 только подогревает это желание, но как обычно есть «но», IE6-8. При этом стоит понимать, что аллергия IE9 к winXP откидывает мечту на годы вперед. На этом можно было бы и закончить, но настырность и зуд в области мозга которая отвечает за желание использовать CSS3 не позволяют мне этого сделать.</p>
<p>Весь смысл этого поста сводится к тому, что IE не умеет CSS3 и поэтому его нужно научить, а если не захочет — заставить. И поиск подобного решения сподвиг меня сделать данную подборку.</p>
<h3>Встречайте, парад нездоровых решений</h3>
<h5><a href="http://code.google.com/intl/ru/chrome/chromeframe/">Google Chrome Frame</a></h5>
<p>Всем известное решение, плагин для IE который рендерит страницы движком хрома.</p>
<p>Плохо оно тем, что нужно ставить плагин поверх IE. Люди которые используют IE не хотят/боятся/не могут ничего ставить.</p>
<p>Но сам по себе он наталкивает на мысль — «действительно, может в место IE заставить рендерить страницы что-нибудь другое». Ну разумеется, заниматься таким гиблым делом с нуля нет резона, поэтому нужно найти готовые решения и довести до нужного результата.</p>
<p>Нашлись очень забавные вещи, html-рендеры написанные на flash.</p>
<h5><a href="http://motionandcolor.com/">HTMLWrapper</a></h5>
<p>HTML и CSS рендер на Actionscript с вариациями флеша, градиенты, анимация, видео и аудио…</p>
<p>Ну и еще парочка подобных извращений:</p>
<h5><a href="http://as3htmlparser.sourceforge.net/">AS3 HTML Parser Library</a></h5>
<h5><a href="http://deng.com.br/">DENG</a></h5>
<p>Между прочим, встречал даже рендер HTML на SVG и джаваскриптовый рендер джаваскрипта </p>
<p>Но это все уж как-то хардкорно слишком, нужно поэлегантней.</p>
<p>Можно, конечно, использовать всевозможные хаки и приемы, как нам <a href="http://www.smashingmagazine.com/2010/04/28/css3-solutions-for-internet-explorer/">советует</a> Smashing Magazine, но это не удобно и некрасиво.</p>
<p>Нужна система, и она есть, можно многими любимого зверька JQuery заставить сделать апорт.</p>
<h5><a href="http://bililite.com/blog/2009/01/16/jquery-css-parser/">jQuery CSS parser</a></h5>
<p>Этот замечательный плагин для JQuery позволяет вместо джаваскриптового </p>
<p><code>$('.gallery a').lightbox({overlayBgColor: '#ddd'});</code></p>
<p>сделать CSSное</p>
<p><code>.gallery a {<br />
-jquery-lightbox: {overlayBgColor: &#8216;#ddd&#8217;};<br />
}</code></p>
<p>А плагинов, эмулирующих CSS3 у JQuery полно:</p>
<h6>border-radius</h6>
<p>
<a href="http://ragamo.medioclick.com/jquery/corners/">jQuery Canvas Rounded Corners</a><br />
<a href="http://www.atblabs.com/jquery.corners.html">jQuery Corners</a></p>
<h6>border-image</h6>
<p></p>
<p><a href="http://www.lrbabe.com/sdoms/borderImage/index.html">borderImage</a></p>
<h6>Multiple Backgrounds</h6>
<p><a href="http://plugins.jquery.com/project/backgroundlayers">Background Layers</a></p>
<p>Ну и так далее…</p>
<p>Однако, большинство из этих эмуляций кривые, почти все убогие и хорошо работают только на демо-версиях своих родных сайтов. Те же которые работают хорошо, превращают страницу в кашу при сочетании друг с другом, попробуйте, например, border-radius и Multiple Backgrounds сделать на один блок.</p>
<p>Именно поэтому я решил писать свою библиотеку, эмулирующую CSS3, но об этом в другой раз.</p>
<p>P.S. Я прекрасно понимаю, что IE будет притормаживать иногда, но считаю это плюсом, пользователи Internet Explorer должны страдать…</p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/26/css3_ie_6_8/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Пишем себе немного OpenID-авторизации</title>
		<link>http://softwarepeople.ru/blog/2010/08/26/openid_authorization/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/26/openid_authorization/#comments</comments>
		<pubDate>Thu, 26 Aug 2010 09:42:14 +0000</pubDate>
		<dc:creator>Николай</dc:creator>
		
		<category><![CDATA[web-разработка]]></category>

		<category><![CDATA[Другое]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=3042</guid>
		<description><![CDATA[
Взгляд в будущее
В последнее время всякие социальные сети и вообще сервисы-лидеры интернета по посещаемости и количеству аккаунтов завели очень неплохую, на мой взгляд, привычку — предоставление уникальных OpenID-идентификаторов для пользователей, дабы с их использованием можно было зайти на сторонний сайт. Кроме того, параллельно развивается очень похожая, но все-таки не совсем производная технология OAuth, которая появилась [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://softwarepeople.ru/files/2010/08/3065ad5259bd.png" alt="3065ad5259bd" title="3065ad5259bd" width="300" height="120" class="alignnone size-full wp-image-3043" /></p>
<h3>Взгляд в будущее</h3>
<p>В последнее время всякие социальные сети и вообще сервисы-лидеры интернета по посещаемости и количеству аккаунтов завели очень неплохую, на мой взгляд, привычку — предоставление уникальных <a href="http://ru.wikipedia.org/wiki/OpenID">OpenID-идентификаторов</a> для пользователей, дабы с их использованием можно было зайти на сторонний сайт. Кроме того, параллельно развивается очень похожая, но все-таки не совсем производная технология <b><a href="http://ru.wikipedia.org/wiki/OAuth">OAuth</a></b>, которая появилась на свет благодаря стараниям создателей небезызвестного Twitter и, цитируя википедию, «позволяет предоставить третьей стороне доступ к защищенным ресурсам пользователя, без необходимости передавать ей (третьей стороне) логин и пароль».<br />
Лично меня такая тенденция очень радует и, более того, я почти уверен, что за подобной технологией будущее. В частности, в будущем обязательно появятся новые мэшапы для агрегирования информации с кучи сайтов (в частности, хочется вспомнить очень хороший, но несправедливо забытый сервис <a href="http://pipes.yahoo.com/pipes/">Yahoo Pipes</a>, который так и не смог покорить сердца и умы просто потому, что его время тогда еще не пришло. Возможно, все еще впереди), а именно такой «форм-фактор» требует логина на кучу сервисов сразу.<br />
Петь дифирамбы подобным технологиям можно очень долго, но лично меня, например, всегда напрягали сайты, на которых надо с нуля регистрироваться, чтобы что-нибудь скачать. Ведь все мы неизменно сталкивались с тем, что когда ищешь, где скачать тот или иной материал — он зачастую оказывается на каком-то совершенно левом и непонятном сайте с названием в духе allbooksmusicwarezzz.omg.su, который ко всему прочему еще и регистрацию требует. Да нет, дело не в пиратстве, дело в том, что сайтов со всяким барахлом, сделанных на коленке, уйма. А вот человеческая память на логины-пароли ограничена, и тут уж ничего не сделаешь. Но приятный момент здесь еще и в том, что многие OpenID-провайдеры кроме информации, непосредственно служащей для авторизации, могут по запросу предоставить еще и базовую информацию о пользователе — e-mail, полное имя, предпочтительный язык и т.п. Причем на многих подобных сервисах можно управлять тем, что отдавать, а что сохранить в секрете. Например, разве пользователю не будет приятно, когда он, зайдя на очередной сайт, увидит приветливую надпись «Добро пожаловать, Вася!» на чистом русском языке, да еще и профиль уже готов к употреблению, вместе с аватаром, привычками и кличкой нежно любимого кота?</p>
<h3>Делаем дело и работаем работу</h3>
<p>Довольно лирики, думаю, кому оно надо как разработчику — он и так все вышенаписанное уже знает, а простым пользователям дальнейший материал вряд ли будет интересен. Еще больше хвалебных речей и рассуждений легко найти в <a href="http://softwaremaniacs.org/blog/">блоге Ивана Сагалаева</a>, а мы давайте попробуем сделать свою систему авторизации через OpenID (например, для блога) на Python, с преферансом и пианистками.<br />
Для своего блога, который сейчас находится в разработке у меня в папочке <i>Projects</i>, я решил вообще отказаться от системы регистрации и авторизации через логин-пароль, а оставить только OpenID. В качестве фреймворка был выбран <a href="http://pylonshq.com/">Pylons</a>, а для прикручивания OpenID к Django-проектам существует и развивается проект с простым и понятным названием <a href="http://github.com/simonw/django-openid">django-openid</a>. Для Pylons, в общем-то, тоже существует решение под названием <a href="http://authkit.org/">AuthKit</a>, однако с ним у меня отношения как-то не очень сложились, а все, что я нашел в сети — это несколько сниппетов, в которых и пришлось разбираться.<br />
Для начала надо установить модуль <a href="http://github.com/openid/python-openid">python-openid</a>, чтобы обеспечить поддержку технологии, а потом создаем контроллер (обработчик запроса по URL, ближайшая ассоциация — джанговский views.py) и начинаем колдовать.</p>
<p><code>$ paster controller auth</code></p>
<p>Сразу оговорюсь, что код рабочий ровно до той степени, которая обеспечивает непосредственно аутентификацию, что делать дальше и как это все оформлять — решать только вам, господа творцы. Начало довольно стандартное:</p>
<p><font color="#0000ff">from</font> openid.consumer.consumer <font color="#0000ff">import</font> Consumer, SUCCESS, FAILURE, DiscoveryFailure<br />
<font color="#0000ff">from</font> openid.store <font color="#0000ff">import</font> filestore<br /></code></p>
<p><code><font color="#0000ff">from</font> openid <font color="#0000ff">import</font> sreg<br />
<font color="#0000ff">from</font> datetime <font color="#0000ff">import</font> datetime<br />
<font color="#0000ff">from</font> hashlib <font color="#0000ff">import</font> md5</code></p>
<p><code><font color="#0000ff">class</font> <font color="#cc6633">AuthController</font>(BaseController):<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">def</font> <font color="#cc6633">__before__</font>(self):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>self</b>.openid_session = session.get(<font color="#008000">&#8220;openid_session&#8221;</font>, {}) <font color="#696969">#&nbsp;проверяем,&nbsp;не&nbsp;существует&nbsp;ли&nbsp;openid-сессии</font></code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">def</font> <font color="#cc6633">index</font>(self):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> render(<font color="#008000">&#8216;/accounts/enter.html&#8217;</font>)</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;@rest.dispatch_on(POST=<font color="#008000">&#8220;signin_POST&#8221;</font>) <font color="#696969">#&nbsp;разделяем&nbsp;GET-&nbsp;и&nbsp;POST-запросы&nbsp;по&nbsp;разным&nbsp;обработчикам&nbsp;для&nbsp;удобства</font></code></p>
<p><code></code>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">def</font> <font color="#cc6633">signin</font>(self):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font> c.user: <font color="#696969">#&nbsp;проверяем,&nbsp;не&nbsp;попытался&nbsp;ли&nbsp;уже&nbsp;залогиненый&nbsp;юзер&nbsp;зайти&nbsp;еще&nbsp;раз</font></code></p>
<p><code></code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session[<font color="#008000">'message'</font>] = <font color="#008000">&#8216;Already&nbsp;signed&nbsp;in.&#8217;</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.save()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;redirect(url(action=<font color="#008000">&#8216;index&#8217;</font>)) <font color="#696969">#&nbsp;и&nbsp;если&nbsp;да,&nbsp;то&nbsp;не&nbsp;пущаем</font></code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.clear()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> render(<font color="#008000">&#8216;/index.html&#8217;</font>) </code></p>
<p>Теперь подходим к самому интересному:</p>
<p><code><font color="#0000ff">def</font> <font color="#cc6633">signin_POST</font>(self):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;problem_msg = <font color="#008000">&#8216;A&nbsp;problem&nbsp;ocurred&nbsp;comunicating&nbsp;to&nbsp;your&nbsp;OpenID&nbsp;server.&nbsp;Please&nbsp;try&nbsp;again.&#8217;</font><br /></code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g.openid_store = filestore.FileOpenIDStore(<font color="#008000">&#8216;.&#8217;</font>) <font color="#696969">#&nbsp;создаем&nbsp;временное&nbsp;хранилище&nbsp;для&nbsp;хранения&nbsp;OpenID-данных,&nbsp;g&nbsp;здесь-массив&nbsp;глобальных&nbsp;переменных&nbsp;Pylons</font></code></p>
<p><code><b>self</b>.consumer = Consumer(<b>self</b>.openid_session, g.openid_store) <font color="#696969">#&nbsp;ага,&nbsp;вот&nbsp;и&nbsp;наш&nbsp;клиент</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;openid = request.params.get(<font color="#008000">&#8216;openid&#8217;</font>, None) <font color="#696969">#&nbsp;достаем&nbsp;из&nbsp;запроса&nbsp;строку&nbsp;с&nbsp;OpenID&nbsp;-&nbsp;идентификатором</font></code></p>
<p>Ага, а вот тут немного магии. <code>SReg</code> — это то самое расширение, которое позволяет нам запросить у сервера дополнительные данные о пользователе. Поля, значение которых хотелось бы узнать, перечисляем в списке optional, а дополнительные данные, если что, всегда можно запросить у пользователя потом. Если же какая-то дополнительная информация требуется прямо кровь из носу, то можно запросить ее в required, но если сервер ее не отдаст — будет ошибка.</p>
<p><code>...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sreg_request = sreg.SRegRequest(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#696969">#required=['email'],</font><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;optional=[<font color="#008000">'fullname'</font>, <font color="#008000">'timezone'</font>, <font color="#008000">'language'</font>, <font color="#008000">'email'</font>, <font color="#008000">'nickname'</font>]</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font> openid <font color="#0000ff">is</font> None:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session[<font color="#008000">'message'</font>] = problem_msg<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.save()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> render(<font color="#008000">&#8216;/index.html&#8217;</font>)</code></p>
<p><code>... </code></p>
<p>Здесь я позволил себе схалявить и написал этот код только для того, чтобы объяснить разницу между простым OpenID и кросс-логином с гугловского аккаунта. Дело в том, что гугл не представляет пользователям OpenID-идентификатора вида <i>https://vasya_pupkin.google.com/</i>, а все куда проще и веселее. URL идентификации у всех пользователей гугла выглядит абсолютно одинаково — <i>https://www.google.com/accounts/o8/id</i>. Любопытно то, что при запросе на этот URL гугл отдает готовый XRDS (XML-подобного вида документ, <a href="http://ru.wikipedia.org/wiki/Yadis">возвращаемый сервером по стандарту OpenID 2.0</a>), который уже содержит все необходимое для авторизации, а вам как пользователю присваивается уникальный ID, который и является, по сути, идентификатором OpenID.</p>
<p><code><font color="#0000ff">if</font> openid == <font color="#008000">&#8216;google&#8217;</font>:</li>
<p>&nbsp;&nbsp;&nbsp;&nbsp;openid = <font color="#008000">&#8216;https://www.google.com/accounts/o8/id&#8217;</font></p>
<p>&nbsp;</p>
<p><font color="#0000ff">try</font>:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;authrequest = <b>self</b>.consumer.begin(openid) <font color="#696969">#&nbsp;панеслася</font></code></p>
<p><code><font color="#0000ff">except</font> DiscoveryFailure, e: <font color="#696969">#&nbsp;а&nbsp;вдруг&nbsp;ошибка&nbsp;в&nbsp;адресе&nbsp;или&nbsp;такой&nbsp;провайдер&nbsp;существует&nbsp;только&nbsp;в&nbsp;твоем&nbsp;воображении?</font></code><br />
<code>&nbsp;&nbsp;&nbsp;&nbsp;session[<font color="#008000">'message'</font>] = problem_msg<br />
&nbsp;&nbsp;&nbsp;&nbsp;session.save()<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">return</font> redirect(url(controller=<font color="#008000">&#8216;auth&#8217;</font>, action=<font color="#008000">&#8217;signin&#8217;</font>))<br />
&nbsp;<br />
authrequest.addExtension(sreg_request) <font color="#696969">#&nbsp;подключаем&nbsp;SReg,&nbsp;дабы&nbsp;извлечь&nbsp;требуемые&nbsp;поля&nbsp;для&nbsp;профиля</font></code></p>
<p><code>redirecturl = authrequest.redirectURL(h.url_for(<font color="#008000">&#8216;/&#8217;</font>, qualified=True),<br />
&nbsp;&nbsp;&nbsp;&nbsp;return_to=h.url_for(action=<font color="#008000">&#8216;verified&#8217;</font>, qualified=True),<br />
&nbsp;&nbsp;&nbsp;&nbsp;immediate=False<br />
) <font color="#696969">#&nbsp;после&nbsp;всего,&nbsp;что&nbsp;у&nbsp;нас&nbsp;было&nbsp;с&nbsp;сервером,&nbsp;надо&nbsp;как-то&nbsp;жить&nbsp;дальше</font></code></p>
<p><code>session[<font color="#008000">'openid_session'</font>] = <b>self</b>.openid_session<br />
session.save()<br />
<font color="#0000ff">return</font> redirect(url(redirecturl))</code></p>
<p>Ну, теперь можно поговорить с сервером, останемся ли мы друзьями.</p>
<p><code>...<br />
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">def</font> <font color="#cc6633">verified</font>(self):<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;problem_msg = <font color="#008000">&#8216;A&nbsp;problem&nbsp;ocurred&nbsp;comunicating&nbsp;to&nbsp;your&nbsp;OpenID&nbsp;server.&nbsp;Please&nbsp;try&nbsp;again.&#8217;</font></code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>self</b>.consumer = Consumer(<b>self</b>.openid_session, g.openid_store)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;info = <b>self</b>.consumer.complete(request.params, (h.url_for(controller=<font color="#008000">&#8216;auth&#8217;</font>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action=<font color="#008000">&#8216;verified&#8217;</font>,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;qualified=True)))</code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if</font> info.status == SUCCESS: <font color="#696969">#&nbsp;все&nbsp;пучком</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sreg_response = sreg.SRegResponse.fromSuccessResponse(info) <font color="#696969">#&nbsp;извлекаем&nbsp;затребованные&nbsp;в&nbsp;SReg&nbsp;поля</font></code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;user = User(by_openid=info.identity_url) <font color="#696969">#&nbsp;ищем&nbsp;юзера&nbsp;по&nbsp;идентификатору&nbsp;в&nbsp;базе</font><br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">if not</font> <b>user</b>.exist: <font color="#696969">#&nbsp;а&nbsp;вот&nbsp;тут&nbsp;можно&nbsp;делать&nbsp;что&nbsp;угодно.&nbsp;Например,&nbsp;внести&nbsp;юзера&nbsp;в&nbsp;базу</font></code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newuser = User()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">try</font>:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;email = sreg_response.get(<font color="#008000">&#8216;email&#8217;</font>, u<font color="#008000">&#8221;</font>),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0000ff">except</font>:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;email = u<font color="#008000">&#8221;</font></code></p>
<p><code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newuser.create(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;openid = <b>unicode</b>(info.identity_url),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;email = email,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;password = <b>unicode</b>(<b>md5</b>(info.identity_url).hexdigest()),<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ip = request.environ[<font color="#008000">'REMOTE_ADDR'</font>]</code></p>
<p>Вот, собственно, и все. Что делать с полученными данными — засовывать в куки, продолжать регистрацию и просить у пользователя дополнительную информацию — решать только вам. Да, и еще, данный код не работает с OpenID от <b>Yahoo</b>. Если охота по завещанию Козьмы Пруткова позрить в корень — есть <a href="http://softwaremaniacs.org/blog/2008/11/21/yahoo-openid-on-cicero/">информация все в том же блоге Ивана Сагалаева</a>. Буду рад услышать любую критику, уточнения, предложения. Постараюсь в дальнейшем разобраться с <b>OAuth</b> и организовать интересующимся немного кода по кросслогину из твиттера.</p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/26/openid_authorization/feed/</wfw:commentRss>
		</item>
		<item>
		<title>ГОСТ-овский стиль управления</title>
		<link>http://softwarepeople.ru/blog/2010/08/26/gost_style/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/26/gost_style/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 20:41:37 +0000</pubDate>
		<dc:creator>Владислав</dc:creator>
		
		<category><![CDATA[Project Management]]></category>

		<category><![CDATA[Другое]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=3058</guid>
		<description><![CDATA[Многим, кто работал по ГОСТ-19 или 34, или по другим ГОСТ вариациям ЕСКД, этот стиль хорошо знаком. Он значительно отличается от западной &#8220;классики&#8221;, хоть и сам является не меньшей классикой.
Многие из тех, кто с ним сталкивался, применяют его для внешнего взаимодействия, и считают формальностью и неизбежным злом. Пока вы его используете так - вы ни [...]]]></description>
			<content:encoded><![CDATA[<p>Многим, кто работал по ГОСТ-19 или 34, или по другим ГОСТ вариациям ЕСКД, этот стиль хорошо знаком. Он значительно отличается от западной &#8220;классики&#8221;, хоть и сам является не меньшей классикой.</p>
<p>Многие из тех, кто с ним сталкивался, применяют его для внешнего взаимодействия, и считают формальностью и неизбежным злом. Пока вы его используете так - вы ни черта не поймете.</p>
<p>Однако, в некоторых организациях, он же применяется и для управления работами сотрудников. Часто такое бывает, когда многие сотрудники работают по контрактам.</p>
<p>И вот тогда, когда вы не только выставляете &#8220;внешний интерфейс&#8221; в виде ГОСТ-19, но и сами выдаете задания по его правилам - становится понятна вся его сила и весь смысл.</p>
<p>Это очень простой, чрезвычайно эффективный, и, вероятно, наиболее недооцениваемый стиль из существующих. И этот стиль по-настоящему крут. Сейчас разберем его отличительные особенности по практике его применения. Без шелухи и формализма - только суть и дух. То, про что я расскажу - базовые принципы, общие для всех ГОСТ, посвященных организации работ. Однако, если вам хочется определенности - думайте, что я говорю про ГОСТ-19.</p>
<p>Значит, первое, и главное. <strong>Единицей планирования</strong> в ГОСТ является ТЗ. Техническое задание. Вокруг предназначения и сути этого документа много непонимания. Многие путают его с Requirements Specification.</p>
<p>Так вот, это НЕ Requirement Specification. Начать можно с того, что правильно составленное ТЗ обычно гораздо короче, и в секции &#8220;технические требования&#8221; содержит в основном ключевые требования, определяющие успех всей работы. Почему? Потому, что эта секция - только одна из секций документа, который суть &#8220;Задание&#8221;, а не требования.</p>
<p>Вторая главная секция - <strong>поэтапный план работ</strong>. Это простая таблица - последовательность этапов выполнения работы. В ГОСТ есть список стадий и этапов, <strong>но этот список носит рекомендательный характер</strong>. На практике у вас есть полная свобода в определении количества этапов, их названий, и состава работ.</p>
<p>Итак, что такое &#8220;этап&#8221;? Этап имеет срок окончания, название, описание результатов этапа, и (наименее важная, информационная составляющая) - перечень видов работ-активностей, которые выполняются в рамках этапа. Если оплата работ сдельная - в этой же таблице стоят суммы за каждый этап, и ТЗ - является приложением к договору подряда.</p>
<p>Почему активности - наименее важная составляющая? Потому, что ГОСТ не содержит никаких инструментов контроля, выполняются на самом деле эти активности, или нет. Этап проверяется по результатам. Точка. А активности - указываются для того, чтобы заказчику было понятно, чем люди заниматься будут, и почему у этапа такие сумма и сроки.</p>
<p>Итак, что такое ТЗ? ТЗ, это комбинация ключевых требований, определяющих успех работ, и поэтапного плана данных работ. ТЗ - это единица планирования. Это не &#8220;требования&#8221;. Это - <strong>задание</strong>.</p>
<p>ТЗ определяет, что должно быть сделано (ключевые признаки успеха проекта), в какие сроки, каковы промежуточные этапы (точки контроля). И кроме этого - он определяет требования к проведению работ (дополнительные ограничения на выполнение), к обеспечению работ и испытаний (что необходимо для выполнения работ и для проведения приемки - это обязан предоставить выдающий задание), а также - к проведению испытаний (обычно, там дается ссылка на документ &#8220;программа и методика испытаний&#8221;).</p>
<p>Ближайшим аналогом ТЗ является Project Charter, если угодно.</p>
<p>А еще в ТЗ есть очень короткая секция, в самом начале, с которой у большинства есть огромные проблемы. Но - в которой состоит весь дзен ТЗ. Называется &#8220;Цели и задачи работы&#8221;. <img src='http://softwarepeople.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>В чем состоят проблемы? В неумении людей отличать цели от задач. Типичное содержимое - &#8220;целью работы является разработка системы Х. Задачами работы, <s>э-э-э&#8230; Чорт! Что здесь писать?</s> являются проектирование, кодирование, и отладка системы Х&#8221;.</p>
<p>Надо ли говорить, что разработка (т.е. процесс) не может являться целью работ? <img src='http://softwarepeople.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> По опыту знаю - не только надо, но надо еще и пояснить. Смотрите:</p>
<p>&#8220;Задача - достать денег в партийную кассу, предотвратив тем самым закрытие типографии&#8221; - таковы цели и задачи Грина в одном из эпизодов &#8220;Статского Советника&#8221; Акунина.</p>
<p>&#8220;Задача - достать денег, с целью хорошо отдохнуть в Европе&#8221; - казалось бы, другая цель, но какая разница, если выполнять надо одну задачу - достать денег? А разница очень большая.</p>
<p>Типографию надо оплатить в течении трех дней. Более того, ради такой цели можно рискнуть очень многим, она высокоприоритетна. И нужна вполне конкретная сумма.</p>
<p>Хорошо отдохнуть в Европе - цель не срочная, сильно рисковать ради ее достижения глупо, ибо отдыхать будет некому. Понятно? Понимание цели дает исполнителю возможность додумать детали и расставить приоритеты.</p>
<p>И в конце концов, раз у вас затруднение с формулировкой цели работ, и она дублирует задачи - может быть, работу вообще не стоит выдавать? Ну, раз выдающий задание не в состоянии внятно объяснить, зачем нужен результат работ? То, может, и работа не нужна?</p>
<p>Ок, переходим на конкретику. Задача работы - получить работоспособную реализацию аудиокодека Dolby Digital. А вот с какой целью? Проще выражаясь - зачем он нам нужен, ради чего вообще эта работа затеяна, для решения какой проблемы? Плевать, что вам это очевидно - это <strong>необходимо</strong> довести до исполнителей.</p>
<p>Если с целью испытаний архитектурного прототипа медиаплеера - это одно. Берем GPL-реализацию, и допиливаем. Главное в данной работе - архитектуру проверить как можно быстрее, а не ковыряться с одним из десятка кодеков.</p>
<p>Если же с целью использования в конечном продукте - тут уже совершенно другое дело. Абсолютно другие требования к качеству, и GPL лицензия не подойдет.</p>
<p>Цель работ, т.е. решаемая работой проблема, rationale, стоящее за задачей - <strong>обязательно</strong> должны быть обозначены явно. Для этого, в принципе, допустимо ввести отдельную &#8220;главу&#8221; в ТЗ - она называется как-то вроде &#8220;характеристика предметной области&#8221; (забыл, как она точно называется, см. ГОСТы в сети), где простым человеческим образом описать проблему. Можно это сделать в той же самой секции &#8220;цели и задачи&#8221;.</p>
<p>Здесь многие знатоки ЕСПД-ЕСКД со мной не согласятся. Ибо - общая практика такова, что к данной секции относятся наплевательски - лень мозги включать. Не без греха и автор этих строк - бывало, что писал в эту часть полную хрень. Но я скажу - вне всякого сомнения, &#8220;цели и задачи работы&#8221;, вкупе с описанием решаемой проблемы - самая важная секция ТЗ. И умение отделять цели от задач - ключевое в составлении ТЗ и менеджменте вообще.</p>
<p>Теперь два фокуса.<br />
1) Вас могут не устраивать фиксированные даты окончания этапов. Пишете в соответствующей графе: &#8220;в соответствии с ведомостью исполнения&#8221;. И все ок.<br />
2) Вас может волновать отсутствие детально расписанных требований в документе ТЗ. Волноваться не надо - у вас есть &#8220;программа и методика испытаний&#8221;.</p>
<p>Этот документ - именно, что программа (то есть, тест-план), и методика (общие принципы построения тест-плана и организации тестирования). Этот документ - фиксирует требования в конструктивной форме. Хреначьте в него свои юз-кейсы и юзер-стори. И включайте наличие первой версии этого документа в результат первого этапа.</p>
<p>Далее - вы сможете отслеживать прогресс работ по количеству проходящих пунктов этого &#8220;документа&#8221;. Вот и весь фокус.</p>
<p>Вкратце - все. Но к самому интересному моменту мы только подошли. Вы видите - ТЗ это очень укрупненный план. Вот у вас есть ТЗ на весь проект. Что же делать дальше? Составлять WBS? Рисовать задачи?</p>
<p>Черта с два. Единственная &#8220;задача&#8221; - это ТЗ. Правильный ответ - выделять частные, более мелкие ТЗ, на более мелкие работы. И так - до самого мелкого уровня. Две главных секции - я показал. Это технические требования плюс поэтапный план.</p>
<p>Вот в этом и состоит второе важное отличие схемы ГОСТ от классической. План работ - это совокупность заданий, на каждое из которых выписано ТЗ. Результат каждого задания - конкретный и проверяемый. Проходит обязательную приемку. Задание может иметь промежуточные этапы - каждый из которых также проходит приемку.</p>
<p>То есть, в отличии от классики, ГОСТ:<br />
1) Объединяет планирование и управление требованиями в единую технику.<br />
2) Явно фокусируется на результате работ, а не на процессах и активностях.<br />
3) Опирается на одну и ту же технику при управлении программой и проектом. Он предполагает, что вы вместо выдачи &#8220;заданий&#8221;, будете дробить крупные &#8220;проекты&#8221; на &#8220;подпроекты&#8221;, концентрируясь на результатах каждой задачи и этапа.<br />
4) Не предполагает отдельной роли &#8220;менеджера&#8221;. Все, кто завязан в процесс - в той или иной степени инженеры. Задание-то &#8220;техническое&#8221;, как ни крути.<br />
5) Совместим со стилем управления Auftragstaktik, про который я много писал.</p>
<p>Когда вы понимаете принцип, стоящий за ГОСТ (а ГОСТ были изначально разработаны для управления большими программами, вроде разработки комплексов ПВО), все становится очень просто и симпатично.</p>
<p>Настолько - что вы можете даже не писать документов-ТЗ. Честно. Смотрите: Берете Redmine.<br />
1) Иерархия ТЗ - это иерархия проектов и подпроектов.<br />
2) Этапы - это &#8220;версии&#8221; для каждого проекта.<br />
3) Технические требования - можете в вики писать, а можете задавать тикетами. Это уж как душе угодно.</p>
<p>Вот вам и все управление. Просто, симпатично, и, самое главное - отлично работает.</p>
<p>Я даже скажу так. Это - одна из немногих техник, которая <em>действительно</em> работает на практике. </p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/26/gost_style/feed/</wfw:commentRss>
		</item>
		<item>
		<title>HTML5 Audio и Game Development: баги браузеров, проблемы и их решения, идеи</title>
		<link>http://softwarepeople.ru/blog/2010/08/25/html5_audio_and_game_development/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/25/html5_audio_and_game_development/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 06:49:20 +0000</pubDate>
		<dc:creator>Software People Team</dc:creator>
		
		<category><![CDATA[web-разработка]]></category>

		<category><![CDATA[Другое]]></category>

		<category><![CDATA[Технологии]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=3031</guid>
		<description><![CDATA[Автор статьи: Павел Пономаренко (twitter)
Я расскажу о нюансах использования тега &#60;audio&#62; в разных браузерах при разработке игр, о проблемах, с которыми я столкнулся и о том, как их решить. Объяснение будет идти параллельно с написанием обертки для удобной работы.
Элемент Audio имеет очень красивый интерфейс, но нам его надо расширить, потому напишем обертку:
    [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Автор</strong> статьи: <strong>Павел Пономаренко</strong> (<a href="http://twitter.com/p_ponomarenko/">twitter</a>)</p>
<p>Я расскажу о нюансах использования тега <code>&lt;audio&gt;</code> в разных браузерах при разработке игр, о проблемах, с которыми я столкнулся и о том, как их решить. Объяснение будет идти параллельно с написанием обертки для удобной работы.</p>
<p>Элемент Audio имеет очень красивый интерфейс, но нам его надо расширить, потому напишем обертку:</p>
<p><code>    var LibCanvasAudio = function (file) {<br />
        this.audio = new Audio;<br />
        this.audio.src = file;<br />
    };<br />
    LibCanvasAudio.prototype = {};</code></p>
<h3>.ogg vs .mp3</h3>
<p>Для начала — муть с поддерживаемыми кодеками. Большинство браузеров поддерживает ogg vorbis(для Оперы в Линуксе  не забудьте установить gstreamer base и good плагины), но, например, Apple решил выебнуться. Давайте для вменяемых браузеров будем отдавать в .ogg, всем остальным — в .mp3. Все звездочки в имени файла будем заменять на ogg или mp3 соответственно:</p>
<p><code>    var LibCanvasAudio = function (file) {<br />
    this.audio = new Audio;<br />
    this.src(file);<br />
};<br />
LibCanvasAudio.prototype = {<br />
    src : function (file) {<br />
        var codec = this.getSupport();<br />
        if (!codec) throw &#8216;AudioNotSupported&#8217;;<br />
        this.audio.src = file.replace(/\*/g, this.getSupport());<br />
        this.audio.load();<br />
        return this;<br />
    },<br />
    getSupport : function () {<br />
        return !this.audio.canPlayType ? false :<br />
            this.audio.canPlayType(&#8217;audio/ogg;&#8217;)  ? &#8216;ogg&#8217; :<br />
            this.audio.canPlayType(&#8217;audio/mpeg;&#8217;) ? &#8216;mp3&#8242; : false;<br />
    }<br />
}<br /></code></p>
<h3>Схема Гатлинга</h3>
<p>Мы подошли к главной теме. Допустим, мы разрабатываем экшн. У нас огромное количество взрывов, выстрелов, етс. Допустим, один взрыв с эхо длится 5 секунд, а интервал между взрывами может быть 0.5 секунд. Если просто запускать файл сначала, то предыдущий взрыв резко оборвется. Мы могли бы клонировать элемент Audio каждый раз перед запуском, но так мы будем плодить кучу DOM-элементов. Приблизительно через 5 минут игры все браузеры сходят с ума. Потому предлагаю воспользоваться схемой Гатлинга. Заносим определенное количество элементов в массив и вызываем их по очереди. Пока сыграет последний элемент первый успеет закончиться. Главное — выставить достаточно количество «стволов» для каждого из звуков.</p>
<p><code>    LibCanvasAudio.prototype = {<br />
    // &#8230;<br />
    cloneAudio : function () {<br />
        audioClone = this.audio.cloneNode(true);<br />
        audioClone.load();<br />
        return audioClone;<br />
    },<br />
    gatling : function (count) {<br />
        this.barrels = [];<br />
        this.gatIndex =  0;<br />
        while (count&#8211;) {<br />
            this.barrels.push(this.cloneAudio());<br />
        }<br />
        return this;<br />
    },<br />
    getNext : function () {<br />
        var elem = this.barrels[this.gatIndex];<br />
        ++this.gatIndex >= this.barrels.length &#038;&#038; (this.gatIndex = 0);<br />
        return elem;<br />
    },<br />
    playNext : function () {<br />
        var elem = this.getNext();<br />
        elem.pause();<br />
        elem.currentTime = 0;<br />
        elem.play();<br />
        return this;<br />
    }<br />
};</code></p>
<p>Интерфейс у нас получается приблизительно такой:</p>
<p><code>   var shotSound = new LibCanvasAudio('explosion.*').gatling(6);<br />
    window.addEventListener(&#8217;keydown&#8217;, function (e) {<br />
        (e.keyCode == keys.SPACE) &#038;&#038; shotSound.playNext();<br />
    }, false);</code></p>
<h3> Облом в Опере </h3>
<p>В Опере нас ждёт облом. Детально изучив этот вопрос нашел баг, который я зарепортил с кодом DSK-309302. Клонированный элемент Аудио в Опере не работает:</p>
<p><code>    // var audioOrig   = document.createElement('audio'); // аналогично с:<br />
    var audioOrig      = new Audio();<br />
    audioOrig.src      = &#8217;shot.ogg&#8217;;<br />
    audioOrig.controls = &#8216;controls&#8217;;<br />
    var audioClone = audioOrig.cloneNode(true);<br />
    function appendToBody (node) {<br />
        document.getElementsByTagName(&#8217;body&#8217;)[0].appendChild(node);<br />
    }<br />
    audioOrig.play(); // работает<br />
    audioClone.play(); // не работает в Опере<br />
    appendToBody(audioOrig);  // работает<br />
    appendToBody(audioClone); // не работает в Опере</code></p>
<p>Напишем небольшой фикс для Оперы:</p>
<p><code>    LibCanvasAudio.prototype = {<br />
        // ..<br />
        cloneAudio : function () {<br />
            if (window.opera) { // Reported Opera bug DSK-309302<br />
                var audioClone = new Audio;<br />
                audioClone.src = this.audio.src;<br />
            } else {<br />
                audioClone = this.audio.cloneNode(true);<br />
            }<br />
            audioClone.load();<br />
            return audioClone;<br />
        },<br />
        // ..<br />
    };</code></p>
<h3>Баг в Фоксе </h3>
<p>Другой баг мы можем наблюдать в firefox 3.5 (в 3.6 и 4 уже нету) — при повторном воспроизведении аудиотрека первая секунда± — дублируется. Судя по всему, не только у меня: «<a href="http://www.wait-till-i.com/2010/05/23/rimshots-for-all-using-html5-audio-and-css3-to-make-instantrimshot-com/">the second time you hit the button it plays the “badumm” twice in Firefox</a>». (<a href="http://freecr.ru/libcanvas/audio/ff-audio-bug.ogv">видео с записью бага</a>). Добавим небольшой фикс — будем отматывать аудио не в начало, а на 25 миллисекунду (минимальное значение установлено экспериментально и равно приблизительно 0.021-0.022 секунды). При желании можно добавить проверку версии и всех кроме 3.5 фокса возвращать в начало (но разница между 25 миллисекундой и нулевой не ощущается, в крайнем случае, зная про этот нюанс можно всё аудио отодвинуть в любимом аудиоредакторе на 25 миллисекунд влево):</p>
<p><code>    LibCanvasAudio.prototype = {<br />
        // ..<br />
        playNext : function () {<br />
            var elem = this.getNext();<br />
            elem.pause();<br />
            elem.currentTime = 0.025;<br />
            elem.play();<br />
            return this;<br />
        }<br />
    };</code></p>
<h3>Бонус</h3>
<p>В IE9 preview 4 не работает <code>new Audio()</code>, но это очень просто решить, заменив его на <code>document.createElement('audio');</code></p>
<p>Исходник, получившийся в результате: <a href="http://pastebin.com/xG4mhX3w">pastebin.com/xG4mhX3w</a></p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/25/html5_audio_and_game_development/feed/</wfw:commentRss>
<enclosure url="http://freecr.ru/libcanvas/audio/ff-audio-bug.ogv" length="1034638" type="video/ogg" />
		</item>
		<item>
		<title>CouchDB сегодня</title>
		<link>http://softwarepeople.ru/blog/2010/08/20/couchdb_today/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/20/couchdb_today/#comments</comments>
		<pubDate>Fri, 20 Aug 2010 07:25:18 +0000</pubDate>
		<dc:creator>Software People Team</dc:creator>
		
		<category><![CDATA[Другое]]></category>

		<category><![CDATA[Технологии]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=3018</guid>
		<description><![CDATA[Автор статьи: Филипп Рудь (twitter)
Что такое CouchDB для вас? Вероятно любой, кто хоть немного интересуется популярной нынче темой NoSQL, прекрасно знает общие детали: это такая симпатичная игрушка с map/reduce-запросами, которые пишутся на Javascript, с которой можно работать, гоняя JSON по HTTP-протоколу, а также не исключено, что слышали, что она fault-tolerant, то бишь не ломается вообще. [...]]]></description>
			<content:encoded><![CDATA[<p>Автор статьи: Филипп Рудь (<a href="http://twitter.com/coffeesnake">twitter</a>)</p>
<p>Что такое CouchDB для вас? Вероятно любой, кто хоть немного интересуется популярной нынче темой NoSQL, прекрасно знает общие детали: это такая симпатичная игрушка с map/reduce-запросами, которые пишутся на Javascript, с которой можно работать, гоняя JSON по HTTP-протоколу, а также не исключено, что слышали, что она fault-tolerant, то бишь не ломается вообще. Дальше этого обычно дело не идёт, в результате CouchDB отправляется в delicious в общую кучу со всякими MongoDB, Cassandra, Hadoop и т.п.</p>
<p>Примерно такого мнения придерживался и я вплоть до недавнего времени, пока не возникла острая необходимость переосмыслить архитектуру текущего проекта (упёршегося лбом в свою реляционную БД) и пересесть на документную базу данных, которая бы умела map/reduce. После того, как более пристально взглянул на CouchDB, я понял, что он уникален в своём классе, его не следует ставить в один ряд с упомянутыми продуктами. Идеи, которые заложены в CouchDB, настолько концептуальны, что способны в корне перевернуть представление о разработке веб-приложений.</p>
<p>Сразу хочу сказать, что если вы уже имеете определённый опыт использования CouchDB, то, вероятно, что вы уже и сами «с усами» и эта статья не для вас. А вот что касается остальных, то может после прочтения появится желание и возможность прилечь на такой вот красный диван и расслабиться, как и рекомендуют разработчики CouchDB.</p>
<p>Следует сказать, что шумиха вокруг CouchDB вплоть до последнего времени несколько поутихла, хотя за последний месяц твиттер буквально взорвался новостями о релизе CouchDB 1.0 и о выходе Cloudant из фазы закрытого Beta-тестирования (о чём я расскажу чуть подробнее ниже). Это событие толком не было освещено. Такую несправедливость надо исправлять, так как, если вы помните CouchDB как сырую альфу с медленными insert-ами и бешеным потреблением памяти и процессора, то забудьте — это всё уже в далёком прошлом. На сегодняшний день это production-ready система с доступной коммерческой поддержкой и реальными примерами использования в production такими компаниями как BBC, например.</p>
<p><img src="http://softwarepeople.ru/files/2010/08/sketch.png" alt="sketch" title="sketch" width="292" height="340" class="alignnone size-full wp-image-3019" /></p>
<p>Я не буду детально расписывать основные возможности, о которых вы при желании сможете прочитать на <a href="http://couchdb.apache.org/">сайте проекта</a>. Постараюсь рассказать о том, что для меня не было очевидно до тех пор, пока я не решился посмотреть на этот продукт поближе в результате чего не уделял этому продукту должного внимания, тогда как мог бы сэкономить себе кучу времени и нервных клеток.</p>
<h3>map/reduce</h3>
<p>Казалось бы, что здесь сложно кого-то чем-то удивить. Многие NoSQL базы данных используют именно эту парадигму доступа к данным, которые не имеют строго определённой схемы. Плюс ещё настораживает использования Javascript для описания map/reduce-функций. Первое впечатление — это же должно быть страшно медленно, ведь как минимум <code>map()</code> необходимо выполнять для <strong>каждого</strong> документа в базе данных. Плюс ещё и движок-то SpiderMonkey — далеко не V8 по быстродействию. В чём же подвох?</p>
<p>Зоркий глаз узреет, что вобще-то в CouchDB используется не map/reduce чистом виде, а т.н. incremental map/reduce. Вся идея заключается в том, что CouchDB не расчитывает свои представления (так называемые views — результаты выполнения функций вроде <code>map()</code> и <code>reduce()</code>) каждый раз. Это делается только при первом обращении к новому представлению, после чего результат спокойно индексируется и ID документов спокойно попадают в B+-дерево по нужному нам ключу с дополнительной информацией в узлах (а также результатами промежуточных редьюсов). Далее всё просто: когда в базу попадает новый документ (или изменяется старый) для него один раз вызывается <code>map()</code> после чего он кладётся в дерево индекса. Т.е. нет необходимости перерасчитывать индекс целиком, дерево просто инкрементно достраивается.</p>
<p>Когда нам нужны результаты, Couch просто отдаёт нам то, что уже посчитано заранее, нет необходимости заново обходить документы, выполняя <code>map()</code>. В отличие от того, чтобы проиндексировать несколько отдельных колонок для ускорения поиска, как делает большинство баз данных, мы проиндексировали все результаты запроса одним махом. Представьте себе MySQL, которому вообще не нужно «выполнять» запрос — он может сразу достать все его результаты из одного единственного индекса.</p>
<p>Единственный аналог, который приходит в голову — это материализованные представления данных (materialized views) из «больших» РСУБД вроде Oracle, но только намного более легковесный. Не забывайте, что хранится только индекс результатов и только нужные вам значения — избыточность не такая уж большая по сравнению с обычными базами данных с кучей индексов, ведь индексируются только результаты map/reduce — те данные, которые вам нужны в контексте данного запроса, а не все колонки. Да и винты нынче дешёвые относительного того потенциала, который сулит этот метод.</p>
<h3>I need more power©</h3>
<p>Тот факт, что <code>map()</code> по сути выполняется один единственный раз для каждого нового/изменённого узла, очень интересен. Это позволяет выполнять довольно тяжёлые операции над новым документом, все равно это делается единожды. И если вам кажется, что со встроенным Javascript рантаймом особо не разгонешься, то тут всплывает ещё одна интересная особенность CouchDB — на самом деле он не завязан ни на какой конкретный язык, а использует абстракцию в виде View-сервера. Т.е. вы просто подключаете view-сервер для вашего любимого языка программирования и пишите <code>map()</code> и <code>reduce()</code> например на Python, пользуясь его его богатой стандартной библиотекой.</p>
<p>По большому счёту никто не мешает вам при добавлении нового документа прямо из <code>map()</code> осуществить геокодинг адреса вашего добавляемого в базу клиента с помощью внешнего сервиса (Google Maps API например) и посчитать для него геоиндекс другой внешней библиотекой. Или просто взять и проиндексировать ваш документ с помощью Sphinx, получив ещё и супербыстрый полнотекстовый индекс вашей БД (если недостаточно хорошей интеграции с Apache Lucene). В общем? простор для творчества ограничен только фантазией.</p>
<p>Если нужно больше скорости, то все ваши view-функции можно переписать на C, воспользовавшись тем фактом, что интерфейс view-сервера прост как лопата, а view в CouchDB — это точно такой же документ, а точнее design-документ со специальным ID. Поэтому ему совсем не обязательно содержать непосредственно код функций — можно положить туда в том числе любой идентификатор, который будет понятен вашему view-серверу. В общем заметно, что вот это идейное единство данных и инструкций по их обработке в виде точно таких же данных сродни идеологии Lisp.</p>
<p>Пусть говорят, что map/reduce парадигма не обеспечивает такой мощи как SQL-запросы, но на практике просто нужно научиться мыслить её категориями. Так например заблуждение, что JOIN нельзя сделать без SQL, т.к. джойны не масштабируются и так далее. Это всё не лишено смысла, тем не менее заявление слишком общее. Во-первых документ можно содержать не только пары ключ-значение, но и коллекции, другие объекты и всё остальное, что можно описать пользуясь JSON, ну а во-вторых даже более сложные join-ы можно реализовывать, зная основные паттерны — реализация map/reduce в CouchDB очень мощная и в то же время понятная и логичная.</p>
<h3>Веб как он есть</h3>
<p>В отличие от большинства альтернатив, CouchDB разрабатывался в первую очередь как база данных для нужд веб-приложений. Отсюда корни такого нетривиального решения как доступ к базе через REST-интерфейс. Да, у HTTP в чистом виде, есть оверхед, но он полностью компенсируется тем, насколько элегантным является это решение. Во-первых вам не нужно искать драйвер для любимого языка программирования — любой HTTP-клиент справится (все примеры — это чаще всего curl прямо из командной строки). Более того, таким клиентом может быть веб-браузер. Можно написать веб-приложение вобще не используя какой-либо middleware на сервере — с базой можно работать при помощи Javascript через Ajax (например <a href="http://couchapp.org/">CouchApp</a> — фреймворк на базе jQuery от создателей CouchDB).</p>
<p><img src="http://softwarepeople.ru/files/2010/08/post-9-127205087262_thumb.png" alt="post-9-127205087262_thumb" title="post-9-127205087262_thumb" width="600" height="294" class="alignnone size-full wp-image-3020" /></p>
<p>После старта Couch ведёт себя словно обычный HTTP-сервер, вы можете зайти на него с помощью вашего браузера и выполнять GET-запросы просто используя строку адреса вашего браузера, получая JSON в качестве результата. А также сразу будет доступен Futon — административный интерфейс CouchDB-инстанса. Кстати он реализован полностью на Javascript без серверного middleware, расширяем и умеет много всего интересного несмотря на свою простоту.</p>
<p>Едва ли стоит говорить о том, что HTTP-протокол реализован правильно, поддерживается кеширование и Couch знает когда отдать 304. Аналогично документ может содержать бинарные вложения (attachments — эквивалент (B)LOB), которые Couch хранит нативными файлами и отдаёт просто как статический контент. Design-документы могут также содержать <code>show()</code> и <code>list()</code>, которые позволяют преобразовывать возвращаемые результаты как угодно, например в HTML-страницы и отдавать их непосредственно браузеру. И если ранее вы придерживались мнения, что хранить аватары пользователей и картинки от товаров вашего Интернет-магазина прямо в вашей [реляционной] БД плохо, то с CouchDB всё обстоит по-другому — иногда даже данные без жесткой схемы могут оказаться в определённых случаях более структурированными и целостными.</p>
<p>Как известно, всё гениальное просто. В CouchDB масса таких вот несложных вещей, которые делались с расчётом именно на Веб-приложения, а не на абстрактные данные, которые необходимо как-то обрабатывать. В итоге всё выглядит настолько последовательно, что теперь даже непонятно, как это можно было сделать по-другому.</p>
<h3>Масштабирование</h3>
<p>О CouchDB раньше обычно говорили, что он не масштабируется. Действительно не так давно это было правдой, но только на половину. Обо всём по порядку.</p>
<p>Одна из ключевых и самых интересных особенностей CouchDB — его репликации. Читатель возможно удивится, как репликации могут быть интересными в принципе, воспринимая их как своего рода костыль. В Couch-е всё не так, его репликации проектировались изначально при создании БД. Во-первых они умеют master-to-master, что позволяет вам делать все инстансы одинаково функциональными, а не делить их на master/slave. Проблемой такой репликации в «обычных» базах данных являются потенциальные конфликты. Поэтому Couch (обладающий свойством MVCC), при возникновении конфликта сохраняет все конфликтующие версии и умеет эти конфликты разрешать, по сконфигурированным правилам (либо отдать это дело в руки вашего приложения — как вы захотите этим воспользоваться, зависит только от вашей фантазии). Сама по себе репликация сводится к дёрганию URL из REST-ового API CouchDB (или воспользовавшись Futon, можно просто ввести URL другой базы и нажать кнопку) вот так вот это всё сложно.</p>
<p>Так что вот едете вы в транспорте, пописываете что-то там во всякие твиттеры с вашего Nexus One (я разве не упомянул, что CouchDB полностью функционален на телефонах с Android, а также Maemo/MeeGo?), и тут въезжаете в туннель — коннект теряется. Вы можете спокойно продолжать пользоваться приложением, которое по возвращению коннекта сможет слить новые сообщения и залить то, что вы написали одним API-вызовом, не изобретая велосипедов. Например, если вы пользуетесь Ubuntu One, то вы уже используете CouchDB именно таким образом.</p>
<p><img src="http://softwarepeople.ru/files/2010/08/couchdb-android-qr.png" alt="couchdb-android-qr" title="couchdb-android-qr" width="230" height="230" class="alignnone size-full wp-image-3021" /></p>
<p>Но не будем отвлекаться от темы. Такие репликации — это конечно хорошо (особенно в свете HTTP-природы CouchDB: можно поставить перед кластером Couch-ей обычный балансер и не переживать), но это не является «настоящим» масштабированием. Репликациями и реляционные БД умеют масштабироваться (хоть и далеко не так элегантно), а что насчёт шардинга? Ведь все хотят размазать данные по кластеру и просто путём добавления нода увеличить объём доступного дискового пространства, максимальную нагрузку, пиковое количество пользователей и так далее, не теряя при этом в скорости. CouchDB делать этого из коробки не умеет. Пока. Но это лишь вопрос времени. </p>
<p>А вот <a href="http://cloudant.com/">Cloudant</a> умеет. Cloudant — это новый сервис, который буквально пару дней назад завершил Beta-тестирование и теперь доступен каждому. Это хостинг вашей CouchDB-базы данных (на облаке от Amazon), а то и всего приложения, учитывая, что CouchDB может служить не только БД, но и middleware. Ребята воспользовались заложенным в CouchDB потенциалом, и развивают свой fork (который в скором времени имеет шансы стать частью trunk-а), который неограниченно масштабируется шардингом, в который в любой момент можно добавить новый node, также он обеспечивает избыточность — каждый документ хранится в трёх экземплярах на разных node-ах на тот случай, если один из node-ов отвалится. Более того, помимо полной поддержки стандартного API, Cloudant позволяет осуществлять map/reduce по результатам другого map/reduce и имеет ещё много интересных особенностей.</p>
<p><img src="http://softwarepeople.ru/files/2010/08/couchdb-android-qr1.png" alt="couchdb-android-qr1" title="couchdb-android-qr1" width="230" height="230" class="alignnone size-full wp-image-3022" /></p>
<p>Весь код открыт, так что можете поднять и использовать Cloudant на приватном облаке. А ещё можно зарегистрировать <a href="https://cloudant.com/#/solutions/cloud/signup/oxygen">бесплатный</a> аккаунт (до 250 мегабайт дискового пространства без учёта старых ревизий документов) и попробовать CouchDB вживую — все основные возможности доступны, в т.ч. Futon.</p>
<h3>Сегодня</h3>
<p>CouchDB в июле дорос до версии 1.0, чем разработчики подчёркивают его стабильность и готовность к production-использованию. Также релиз Cloudant является знаковым для всего CouchDB-комьюнити. Если вы ещё не пробовали Couch, потратьте полчаса вашего времени — можете сэкономить намного больше времени в итоге, хотя это, конечно же, будет зависит от специфики вашего конкретного проекта. Продукт делает именно то, для чего он создавался, но не более. Так что не ждите чуда, но надеюсь, что после прочтения, кто-нибудь расслабится, как рекомендуют разработчики (особенно, если есть красный диван).</p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/20/couchdb_today/feed/</wfw:commentRss>
		</item>
		<item>
		<title>SWP - дайджест №29</title>
		<link>http://softwarepeople.ru/blog/2010/08/18/swp-digest-%e2%84%9629/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/18/swp-digest-%e2%84%9629/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 13:44:07 +0000</pubDate>
		<dc:creator>Software People Team</dc:creator>
		
		<category><![CDATA[SWP Дайджест]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=3011</guid>
		<description><![CDATA[От того, насколько быстро работает ваш сайт, зависит его посещаемость, а в конце концов и будущее вашего бизнеса. Что нужно сделать, чтобы увеличить скорость web-сайта? Какие существуют секреты «разгона» web-сайта? Об одном из таких приемов рассказывается в статье Николая Мациевского «Проблемы сжатия и объединения Javascript»
Читать статью 

UML – язык, давно нашедший свое уникальное место в [...]]]></description>
			<content:encoded><![CDATA[<p>От того, насколько быстро работает ваш сайт, зависит его посещаемость, а в конце концов и будущее вашего бизнеса. Что нужно сделать, чтобы увеличить скорость web-сайта? Какие существуют секреты «разгона» web-сайта? Об одном из таких приемов рассказывается в статье Николая Мациевского «Проблемы сжатия и объединения Javascript»<br />
<a href="http://softwarepeople.ru/blog/2010/08/08/javascript_compression_and_gluing/?utm_source=webdigest_29">Читать статью </a></p>
<hr />
<p>UML – язык, давно нашедший свое уникальное место в процессе проектирования IT-систем. Он облегчает рутинную работу и улучшает понимание между различными членами проектной команды – от системных аналитиков до архитекторов и разработчиков. Первый вопрос, с которым сталкиваются те, кто решил использовать моделирование на UML в своей работе – это какой инструмент выбрать. Обзор существующих инструментов приводится в статье Александра Краковецкого «Инструменты для рисования UML-диаграмм»<br />
<a href="http://softwarepeople.ru/blog/2010/08/08/uml_drawing_tools/?utm_source=webdigest_29">Читать статью </a></p>
<hr />
<p>Проблемам управления рисками посвящены две статьи в этом выпуске: статья Владислава Балина «Инженерная деятельность, ошибки и риски», которая является вступлением к его докладу об управлении рисками в софтверных и инженерных проектах, и статья Константина Кондратюка «Риски, паникеры и негодяи». Первая дает целостный взгляд на проблему управления рисками в проектах, относящихся к IT-индустрии, а вторая представляет различные подходы к управлению рисками и рассказывает о результатах их применения.<br />
<a href="http://softwarepeople.ru/blog/2010/08/08/risksandmistakes/?utm_source=webdigest_29">Читать статью «Инженерная деятельность, ошибки и риски» </a></p>
<p><a href="http://softwarepeople.ru/blog/2010/08/10/risks/?utm_source=webdigest_29">Читать статью «Риски, паникеры и негодяи» </a></p>
<hr />
<p><strong>События:</strong></p>
<p><strong>7-8 октября в Москве</strong> состоится самое грандиозное в России событие в области юзабилити –<a href="http://userexperience.ru/2010/?utm_source=webdigest_29"> User Experience Russia 2010</a>, которая пройдет в этом году в четвертый раз и будет посвящена вопросам юзабилити, проектированию и взаимодействию с пользователем услуг в интернете.<br />
В этом году конференция пройдет при поддержке европейской ассоциации  юзабилистов UPA Europe.  </p>
<p>В программе конференции ожидается 40 докладов ведущих экспертов области, а также множество подарков и сюрпризов! К примеру, американская компания Розенфельд Медиа выступила спонсором конференции и проведет розыгрыш книг от Розенфельд Медиа. Также каждый участник получит 20%-скидку на всю продукцию компании. </p>
<p>Торопитесь зарегистрироваться на  <a href="http://userexperience.ru/2010/?utm_source=webdigest_29">User Experience 2010</a>! Стоимость участия при оплате до 1 сентября составляет 10 000 руб., при оплате до 7 октября – 12 500 руб. </p>
<hr />
<p><strong>Новость от Спанч Боба</strong></p>
<p>Как программисту рассказать о том, чем он занимается? Можно уныло перечислять свои заслуги, а можно подойти к решению проблемы творчески. Например, так: </p>
<p><object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/zV0OgsRK0Bc?fs=1&amp;hl=ru_RU"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/zV0OgsRK0Bc?fs=1&amp;hl=ru_RU" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></embed></object></p>
<p>Лично я думаю использовать этот прогрессивный метод при проведении собраний рабочих групп и презентаций. По-моему, впечатляюще. А вам как кажется?</p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/18/swp-digest-%e2%84%9629/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Версия Ubuntu 10.10 Maverick Meerkat Alpha 3</title>
		<link>http://softwarepeople.ru/blog/2010/08/18/ubuntu1010/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/18/ubuntu1010/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 20:48:39 +0000</pubDate>
		<dc:creator>Software People Team</dc:creator>
		
		<category><![CDATA[Технологии]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=2999</guid>
		<description><![CDATA[Автор: Dmitry Kann
5 августа 2010 г. вышла третья альфа-версия Убунту 10.10 — Maverick Meerkat Alpha 3, — вобравшая в себя функциональность, подготавливаемую для следующей стабильной версии системы, которая выйдет 10 октября этого года (10.10.10).
Обновление с Ubuntu 10.04 LTS

Обновиться до третьей альфы с Ubuntu 10.04 LTS на десктопной версии можно с помощью команды:
update-manager -d
Запустившийся Update Manager [...]]]></description>
			<content:encoded><![CDATA[<p>Автор: <a href="http://yktoo.habrahabr.ru/">Dmitry Kann</a></p>
<p>5 августа 2010 г. вышла третья альфа-версия Убунту 10.10 — Maverick Meerkat Alpha 3, — вобравшая в себя функциональность, подготавливаемую для следующей стабильной версии системы, которая выйдет 10 октября этого года (10.10.10).</p>
<h4>Обновление с Ubuntu 10.04 LTS</h4>
<p>
Обновиться до третьей альфы с Ubuntu 10.04 LTS на десктопной версии можно с помощью команды:<br />
<code>update-manager -d</code></p>
<p>Запустившийся Update Manager сообщит о наличии новой версии <b>10.10</b>. Нажмите «Обновить» и следуйте указаниям программы.</p>
<p>Чтобы обновить серверную Ubuntu 10.04 LTS, необходимо:</p>
<ol>
<li>Установить пакет <code>update-manager-core</code> (если он ещё не установлен);</li>
<li>Отредактировать <code>/etc/update-manager/release-upgrades</code> и установить <code>Prompt=normal</code>;</li>
<li>Запустить менеджер обновлений командой <code>sudo do-release-upgrade -d</code>;</li>
<li>Следовать указаниям программы.</li>
</ol>
<h4>Что нового в Maverick Meerkat</h4>
<p>
Началась разработка функциональности для Maverick, подробности доступны в <a href="https://blueprints.launchpad.net/ubuntu/maverick/+specs">спецификациях Maverick</a>.</p>
<p>Среди прочего, она содержит <a href="http://www.markshuttleworth.com/archives/359">глобальное меню приложения</a> (<a href="http://www.webupd8.org/2010/08/une-1010-unity-update-brings-lots-of.html">здесь</a> есть много скриншотов Unity, а также видео).</p>
<p>Индикатор даты/времени теперь предоставляет настоящий виджет календаря:</p>
<p><img src="http://softwarepeople.ru/files/2010/08/desk-1_019.png" alt="desk-1_019" title="desk-1_019" width="372" height="289" class="alignnone size-full wp-image-3002" /><br />
Просьба тестировать релиз и <a href="http://help.ubuntu.com/community/ReportingBugs">сообщать о багах</a>.</p>
<h5>Обновления пакетов</h5>
<p>Как обычно бывает при подготовке новой версии, пакеты (приложения и прочее ПО) обновляются очень часто. Многие из этих пакетов поступают автоматически при синхронизации с веткой Debian Unstable. В данный момент период автоматической синхронизации окончен, поэтому теперь изменений будет не так много.</p>
<p>Список пакетов, принятых для 10.10 Maverick Meerkat, вы можете получить, подписавшись на <a href="https://lists.ubuntu.com/mailman/listinfo/maverick-changes">maverick-changes</a>.</p>
<h5>Ubuntu</h5>
<p>
GNOME обновлён до текущей версии 2.31. Она, в частности, включает API <a href="http://live.gnome.org/dconf">dconf и gsettings</a>. Evolution обновлена до версии 2.30, и работает теперь намного быстрее по сравнению с версией, вошедшей в Ubuntu 10.04 LTS.</p>
<h5>Ubuntu Netbook Edition</h5>
<p>
По умолчанию оболочкой в нетбучной редакции Убунту теперь является <a href="http://www.markshuttleworth.com/archives/383">Unity</a>.</p>
<p><img src="http://softwarepeople.ru/files/2010/08/unity-apps-menu.png" alt="unity-apps-menu" title="unity-apps-menu" width="288" height="282" class="alignnone size-full wp-image-3001" /></p>
<p>Также стоит отметить и редизайн меню регулятора громкости, впервые появившийся в прошлой альфе:</p>
<p><img src="http://softwarepeople.ru/files/2010/08/desk-1_048.png" alt="desk-1_048" title="desk-1_048" width="350" height="311" class="alignnone size-full wp-image-3003" /></p>
<p>В качестве стандартного менеджера фотографий теперь используется <a href="http://yorba.org/shotwell/">Shotwell</a>.</p>
<h5>Kubuntu</h5>
<p>
KDE обновлена до 4.5 release candidate. Веб-браузер по умолчанию теперь Rekonq, основанный на Webkit. Qt обновлена до текущей версии <a href="http://qt.nokia.com/about/news/betas-of-qt-4.7-and-qt-creator-2.0-now-available">4.7 beta</a>.</p>
<h5>Xubuntu</h5>
<p>
Xfce4 обновлена до текущей версии 4.6.2, в которой исправлено множество багов и обновлены многие программы, использующиеся в Xubuntu. Новые программы по умолчанию: медиаплеер Parole вместо Totem Movie Player, программа для записи дисков Xfburn вместо Brasero, менеджер процессов xfce4-taskmanager вместо Gnome-Task-Manager.</p>
<h5>Edubuntu</h5>
<p>
Edubuntu наследует все изменения из Ubuntu. Пакет edubuntu-artwork был разделён на несколько меньших пакетов, чтобы упростить установку обновлений и уменьшить размеры загружаемых файлов.</p>
<h5>Software-Center</h5>
<p>
<img src="http://softwarepeople.ru/files/2010/08/ubuntu-software-center-216.png" alt="ubuntu-software-center-216" title="ubuntu-software-center-216" width="542" height="277" class="alignnone size-full wp-image-3004" /></p>
<p>На стартовой странице software-center появились разделы «Лучшее» («Featured») и «Новое» («What&#8217;s New»). Приложение стало работать быстрее, интерфейс стал отзывчивее, добавлена функция «История» («History»), где представлен список того, что было установлено, удалено и обновлено. Добавлена поддержка расширений (плагинов), по умолчанию специфические технические записи не отображаются.</p>
<h5>Ядро 2.6.35</h5>
<p>
Alpha 3 поставляется с <a href="http://kernel.org/">ядром</a> 2.6.35-14.19, основанным на финальной версии 2.6.35.<br />
Это ядро содержит ряд <a href="https://wiki.ubuntu.com/SecurityTeam/Roadmap/KernelHardening">улучшений</a>, связанных с безопасностью. Одно из самых важных нововведений изменяет стандартное поведение <a href="https://wiki.ubuntu.com/SecurityTeam/Roadmap/KernelHardening#ptrace">PTRACE</a>, используемого gdb, strace, ltrace и т. д. Начиная с Убунту 10.10, только дочерние процессы могут быть оттрассированы, что обусловлено исходным значением 1 в <code>/proc/sys/kernel/ptrace_scope</code>. В некоторых системах такое значение может вызывать проблемы, например, в системах, используемых для разработки, и серверах, где имеются только администраторские учётные записи. Если использование <code>sudo</code> для PTRACE нежелательно, необходимо установить это значение в 0.</p>
<h5>Образы Ubuntu Server Cloud</h5>
<p>
<code>cloud-init</code>, настраиваемый процесс инициализации облака Ubuntu Server, приобрёл новые вохможности ещё в Maverick Alpha 2, среди которых pluggable hooks, ebsmount, поддержка ext4 и новые параметры в формате cloud-config.<br />
Начиная с Alpha 3, экземпляры облака могут управлять собственным ядром, включая обновление ядра с помощью <code>apt</code>. Это делается с помощью предоставляемой Амазоном утилиты <a href="http://aws.typepad.com/aws/2010/07/use-your-own-kernel-with-amazon-ec2.html">pv-grub</a>.</p>
<h5>Установка</h5>
<p>
Теперь при установке можно использовать новую файловую систему <a href="http://ru.wikipedia.org/wiki/Btrfs">btrfs</a> (при ручном разбиении), если раздел <code>/boot</code> поместить на другой системе.</p>
<h5>Загрузка Alpha 3</h5>
<p>
Налетай, пока не остыло! ISO-образы и торренты доступны:</p>
<p><a href="http://cdimage.ubuntu.com/releases/maverick/alpha-3/">Ubuntu Desktop, Server и Netbook</a><br />
<a href="http://uec-images.ubuntu.com/releases/maverick/alpha-3/">Ubuntu Server для UEC и EC2</a><br />
<a href="http://cdimage.ubuntu.com/kubuntu/releases/maverick/alpha-3/">Kubuntu Desktop и Netbook</a><br />
<a href="http://cdimage.ubuntu.com/xubuntu/releases/maverick/alpha-3/">Xubuntu</a><br />
<a href="http://cdimage.ubuntu.com/edubuntu/releases/maverick/alpha-3">Edubuntu DVD</a><br />
<a href="http://cdimage.ubuntu.com/ubuntustudio/releases/maverick/alpha-3/">Ubuntu Studio</a></p>
<p><a href="http://cdimage.ubuntu.com/ubuntu-netbook/ports/releases/maverick/alpha-3/">Ubuntu ARM</a></p>
<h5>Известные проблемы</h5>
<p>
На данной стадии подготовки к релизу является закономерным наличие некоторых известных проблем, с которыми пользователи могут столкнуться в Maverick Alpha 3. Здесь собраны описания таких проблем, а также возможные исправления их, чтобы вы не теряли времени, вновь сообщая об этих багах.</p>
<ul>
<li>Установка в режиме OEM завершается неудачно при отсутствии подключения к Интернету вследствие неудачной установки пакета <code>oem-config</code> из установочного образа. Если вам это требуется для тестирования, обеспечьте постоянное подключение к Сети в течение всей установки (<a href="https://bugs.launchpad.net/bugs/613008">613008</a>)</li>
<li>Установщик для Windows Wubi завершается со сбоем. Проводится изучение проблемы (<a href="https://bugs.launchpad.net/bugs/600578">600578</a>, <a href="https://bugs.launchpad.net/bugs/613288">613288</a>).</li>
<li>Ubuntu Netbook Edition с оболочкой Unity в настоящее время не предоставляет обходной возможности для систем с видеодрайвером, не поддерживающим 3D-ускорения, как, например, NVidia (<a href="https://bugs.launchpad.net/bugs/600567">600567</a>).</li>
<li>В системах с малым количеством памяти (256 МБ или меньше), ureadahead вызывает ошибки недостатка памяти, что может привести к невозможности загрузки (<a href="https://bugs.launchpad.net/bugs/600359">600359</a>).</li>
<li>Приложения, использующие sqlite3, сталкиваются с множеством проблем, связанных с производительностью и правильностью выполнения запросов, например, banshee (<a href="https://bugs.launchpad.net/bugs/612370">612370</a>).</li>
<li>Пререлизная версия Eucalyptus 2.0 включена в состав Alpha 3, хотя в ней до сих пор имеется ряд проблем. Например, регистрация после установки работает ненадёжно (<a href="https://bugs.launchpad.net/bugs/609112">609112</a>), сложные топологии (такие, например, как отделяющие CLC от Walrus) пока не поддерживаются (<a href="https://bugs.launchpad.net/bugs/613033">613033</a>). При установке узловой («node») системы будьте готовы получить две проблемы с grub, которые могут быть проигнорированы без последствий (<a href="https://bugs.launchpad.net/bugs/613463">613463</a>).</li>
<li>KDM выдаёт таймаут при загрузке с образа Kubuntu Live, после чего запуск отказоустойчивой X-сессии должен быть возможен (<a href="https://bugs.launchpad.net/bugs/613574">613574</a>).</li>
</ul>
<h5>Сообщения об ошибках</h5>
<p>
Не следует сильно удивляться также, что в альфа-версии Maverick Meerkat могут присутствовать прочие ошибки. Ваши комментарии, отчёты об ошибках, патчи и предложения помогут внести необходимые исправления и улучшить будущие версии. Чтобы сообщить об ошибке, воспользуйтесь <a href="http://help.ubuntu.com/community/ReportingBugs">стандартными средствами</a>.</p>
<p>Если же вы хотите помочь в исправлении ошибок, то вам надо в <a href="http://wiki.ubuntu.com/BugSquad">Bug Squad</a>, где всегда рады новым силам.</p>
<h5>Помощь Убунту</h5>
<p>
Если вы хотите внести свой вклад в будущее Убунту, ознакомьтесь со <a href="http://www.ubuntu.com/community/participate/">списком возможных способов участия</a> в её судьбе.</p>
<h5>Прочая информация</h5>
<p>
Вы можете найти дополнительную информацию об Убунту на <a href="http://www.ubuntu.com/">веб-сайте</a> и в <a href="http://wiki.ubuntu.com/">Ubuntu wiki</a>.</p>
<p>Можно также подписаться на рассылку для разработчиков Убунту (<a href="http://lists.ubuntu.com/mailman/listinfo/ubuntu-devel-announce">Ubuntu&#8217;s development announcement list</a>).</p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/18/ubuntu1010/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Постепенное вовлечение пользователей вместо формы регистрации</title>
		<link>http://softwarepeople.ru/blog/2010/08/18/gradual_engagement/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/18/gradual_engagement/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 20:30:53 +0000</pubDate>
		<dc:creator>lexxscorp</dc:creator>
		
		<category><![CDATA[Usability & UX]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=2989</guid>
		<description><![CDATA[Перевод статьи Luke Wroblewski Gradual Engagement Boosts Twitter Sign-Ups by 29%
Недавно (весной этого года) Твитер перепроектировал процесс регистрации, чтобы увеличить количество новых пользователей. И хотя в новой версии в регистрацию добавилась ещё одна страница, то есть дополнительный шаг, конверсия всё равно выросла на 29%. Почему это произошло? Благодаря постепенному вовлечению.
Постепенное вовлечение — это процесс перемещения [...]]]></description>
			<content:encoded><![CDATA[<p>Перевод статьи Luke Wroblewski <em><a href="http://www.lukew.com/ff/entry.asp?1128">Gradual Engagement Boosts Twitter Sign-Ups by 29%</a></em></p>
<p>Недавно (весной этого года) Твитер перепроектировал процесс регистрации, чтобы увеличить количество новых пользователей. И хотя в новой версии в регистрацию добавилась ещё одна страница, то есть дополнительный шаг, <strong>конверсия всё равно выросла на 29%</strong>. Почему это произошло? Благодаря <strong>постепенному вовлечению</strong>.</p>
<p><strong>Постепенное вовлечение</strong> — это процесс перемещения пользователя по приложению или сайту, фактически “пробуя” его и видя все его преимущества. В обычном процессе регистрации пользователю показывают форму, которую необходимо заполнить. Здесь наоборот, регистрация или отложена на потом, или происходит в фоне, а первый опыт пользователя сфокусирован на том, чтобы показать, как использовать сервис и зачем он вообще нужен.</p>
<p>Перевод статьи </p>
<p>Правильное постепенное вовлечение рассказывает пользователю об основной сущности сервиса путём простых взаимодействий. Если вы при этом осчастливите человека — даже лучше. Уилл Райт, создатель Sims &#038; Spore, верит, что игры должны позволять человеку выигрывать в течении первых 5 секунд. Это хорошая философия, чтобы добиться постепенного вовлечения. На самом деле вы можете позволить людям за одно-два простых взаимодействия сделать то, в чём смысл вашего сервиса. Это наилучший вариант.</p>
<p><em>Термин «gradual engagement» я перевожу как «постепенное вовлечение». По-моему он точно отражает суть, но вы можете указать в комментариях свой вариант</em>.</p>
<p>Исследуя своих пользователей, Твитер обнаружил, что пока знаменитости со своими твитами были единственной причиной прихода людей в Твитер, было очень трудно сохранить аудиторию. На самом деле людей в Твитере удерживали их страсти: хобби, разговоры с экспертами в той или иной области и друзья. Это и есть та основная сущность сервиса, на которую должно опираться постепенное вовлечение.</p>
<p><strong>Вот как выглядела регистрация в Твитере до изменений</strong></p>
<p><img src="http://softwarepeople.ru/files/2010/08/twitter_gradualengagement11.gif" alt="twitter_gradualengagement11" title="twitter_gradualengagement11" width="600" height="1188" class="alignnone size-full wp-image-2990" /></p>
<p>Она не попала в цель. Если человек решал зарегистрироваться, то его приветствовала форма, где он:</p>
<p>   1. должен был создать акаунт,<br />
   2. мог найти друзей через свой почтовый акаунт,<br />
   3. просмотреть список самых популярных твитерян, которых мог зафоловить, и<br />
   4. наконец, если не смог ничего найти или пропустил предыдущие два шага, то видел пустую страницу с вопросом «что вы делаете».</p>
<p>В новой версии после создания акаунта пользователь видит список тем, которые могут его заинтересовать. Темы разбиты по самым популярным категориям (музыка, развлечения, мода, искусство и дизайн), а также включают текущие события, заполненные редакторами твитера.</p>
<p>В предыдущей версии регистрации пользователи видели список популярных твитерян, которые лишь случайно могли их интересовать. Сейчас же они сами могут выбрать аккурат то, что им нужно. Это и есть основная суть Твитера и как результат отличный подход к постепенному вовлечению. В новой версии люди начинают фоловить то, что им интересно, и у них меньше шансов оказаться перед пустой домашней страницей.</p>
<p><strong>Новая версия регистрации в Твитере</strong></p>
<p><img src="http://softwarepeople.ru/files/2010/08/twitter_gradualengagement21.gif" alt="twitter_gradualengagement21" title="twitter_gradualengagement21" width="600" height="1384" class="alignnone size-full wp-image-2991" /></p>
<p>И хотя новый процесс регистрации состоит из 4 шагов вместо 3-х и занимает больше времени, его полностью завершают на 29% больше людей, которые становятся гораздо более вовлечёнными в Твитер, чем раньше.</p>
<p>Лично мне (переводчику тоже) очень любопытно посмотреть, что произошло бы, если бы создание акаунта происходило после того, как люди начали фоловить интересующие их темы и друзей. Сейчас оно идёт до того, как люди получат личные выгоды от Твитера. Как я заметил ранее, настоящее постепенное вовлечение отложит создание акаунта на потом или проведёт его в фоне.</p>
<h3>Ещё несколько мыслей</h3>
<p>Заставлять людей заполнять формы — это один из способов получить информацию. На сайтах это стандарт де-факто. <strong>Но так быть не должно. Вместо того, чтобы каждый раз показывать людям формы, лучше обратиться к принципам постепенного вовлечения.</strong></p>
<p>Оно позволяет нам собирать информацию от людей так, чтобы вовлекать их в использование приложения. <strong>Фактически мы обучаем людей его преимуществам и возможностям.<br />
</strong><br />
Постепенное вовлечение — это задача информационной архитектуры, потому что оно заставляет нас задуматься о главной сути приложения и <strong>разработать процесс, знакомящий людей с программой, одновременно собирая нужную информацию</strong>. Последовательность информационных запросов через взаимодействия позволяет делать первое знакомство с приложением более полезным и запоминающимся.</p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/18/gradual_engagement/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Версионирование схемы MySQL в PHP проектах.</title>
		<link>http://softwarepeople.ru/blog/2010/08/16/versioning_mysql_php/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/16/versioning_mysql_php/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 17:56:27 +0000</pubDate>
		<dc:creator>idler</dc:creator>
		
		<category><![CDATA[web-разработка]]></category>

		<category><![CDATA[Разработки]]></category>

		<category><![CDATA[Технологии]]></category>

		<category><![CDATA[новые продукты]]></category>

		<category><![CDATA[MySQL]]></category>

		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=2974</guid>
		<description><![CDATA[История эта началась в ноябре 2009го, когда я, получив новую работу по организации команды разработчиков, задумался над тем, как публиковать на тестовые и продакшн-сервера изменения в схеме базы данных.

Я испробовал несколько инструментов, существующих на рынке, но пришел к выводу, что ни один из них меня не удовлетворяет. Позже я начал разработку собственного инструмента для версионирования схемы БД, но об этом в конце статьи, а пока я хотел бы рассказать о том, что я пытался использовать и почему начал изобретать велосипед.]]></description>
			<content:encoded><![CDATA[<p>История эта началась в ноябре 2009го, когда я, получив новую работу по организации команды разработчиков, задумался над тем, как публиковать на тестовые и продакшн-сервера изменения в схеме базы данных.</p>
<p>Я испробовал несколько инструментов, существующих на рынке, но пришел к выводу, что ни один из них меня не удовлетворяет. Позже я начал разработку собственного инструмента для версионирования схемы БД, но об этом в конце статьи, а пока я хотел бы рассказать о том, что я пытался использовать и почему начал изобретать велосипед.</p>
<p>Для начала опишу требования к инструменту, которые у меня на тот момент были.</p>
<ul>
<li>Минимум зависимостей 	— желательно только PHP (без дополнительных 	расширений) и MySQL.</li>
<li>Возможность производить 	произвольные изменения схемы 	непосредственно, используя для этого 	любой доступный клиент (mysql или PHPMyAdmin, например)</li>
<li>Полностью 	автоматизированная генерация миграций.</li>
<li>Возможность 	использовать инструмент в скриптах или в cron.</li>
</ul>
<p>В идеале сценарий таков:  После экспериментов со структурой БД разработчик запускает генератор миграций, который создает некоторый миграционный файл (миграцию), затем этот файл добавляется под контроль версий. Когда тестовый сервер получает обновление по крону, он также запускает процесс миграции на последнюю версию структуры БД.</p>
<p><strong>Итак, претендент первый: Doctrine 1.2</strong></p>
<p>Это ORM   (Object-relational mapping или Объектно-реляционное отображение), написанный на PHP, но тянет за собой достаточно большую библиотеку классов, и требует установленного PDO. Инструмент этот не попадает под первое же требование, но я решил, что можно использовать и его.</p>
<p>Что же предлагает разработчику Doctrine? Для начала нужно сгенерировать конфигурационный файл схемы — это будет описание схемы БД в YAML-формате. Менять схему придется там же, а значит придется ознакомиться с документацией на формат описания схемы.</p>
<p>Мы меняем конфиг-файл, затем даем задачу сгенерировать миграцию, затем должны перестроить модели (Да-да, все равно придется иметь классы моделей, даже если мы не используем Doctrine в основном проекте), и только потом накатить миграцию на текущую рабочую базу.</p>
<p>В итоге мы получаем слишком много телодвижений в момент, когда разработчик только экспериментирует со схемой БД, т. к. он не может менять ее непосредственно. Результатом таких сложностей станет игнорирование конфиг-файла схемы, а после первого такого прецедента система миграций станет бесполезна.</p>
<p>Итог: инструмент меня не устроил. Я считаю этот инструмент подходит только для тех проектов,  где используется Doctrine. Позже работая с Symfony + Doctrine я нашел еще пару неприятных моментов использования Doctrine Migration, но статья не об этом.</p>
<p><strong>Претендент второй: MySQL Workbench</strong></p>
<p>Это инструмент от Sun(Oracle) с графическим пользовательским интерфейсом. Он позволяет соединиться с базой и построить на ее основе диаграмму таблиц и их связей. В эту диаграмму мы можем вносить любые изменения, при помощи графического интерфейса. Когда изменения внесены мы можем снова соединиться с БД и опубликовать сделанные изменения. Очень удобный инструмент, когда разработка ведется на одной машине и не очень опытным программистом.</p>
<p>Мне же этот инструмент не подошел по причине слишком большого количества ручного труда.</p>
<p>Да и в процессе использования возникали вопросы:</p>
<p>А что если тестовых серверов несколько?</p>
<p>Как наладить обмен ALTER-TABLE-скриптами внутри команды разработчиков?</p>
<p><strong>Еще один вариант:</strong></p>
<p>К этому моменту обмен изменениями БД уже был кое-как налажен. Был написан скрипт ( <span style="color: #000080;"><span lang="zxx"><span style="text-decoration: underline;"><a href="http://www.antonoff.info/phps/db_migration_tool">http://www.antonoff.info/phps/db_migration_tool</a></span></span></span> )   который  исполнял только новые *.sql файлы, появляющиеся в определенной папке проекта. Новизну он определял сравнивая дату  в имени файла с датой последнего обновления, хранящегося в БД. SQL-скрипты разработчики писали и именовали вручную. Файлы писались уже после того, как изменения внесены в БД на локальной машине разработчика, а потому здесь снова большую роль играл человеческий фактор: забыли написать файл, забыли добавить в файл некоторые жизненно необходимые изменения, наделали синтаксических ошибок и т. п.</p>
<p>От человеческого фактора надо избавляться, но как? Конечно же полностью автоматической генерацией миграций, но возможность подправить что-то вручную обязательно нужно оставить, и при  этом нужно сделать так, чтобы это было просто и без чтения дополнительной документации.</p>
<p>С этого момента поиски мои шли только в направлении полностью автоматизированного процесса.</p>
<p>Следующим претендентом стал проект, найденный на Google Code:</p>
<p><strong>Mysql PHP Migrations</strong></p>
<p><span style="color: #000080;"><span lang="zxx"><span style="text-decoration: underline;"><a href="http://code.google.com/p/mysql-php-migrations/wiki/Installation">http://code.google.com/p/mysql-php-migrations/wiki/Installation</a></span></span></span></p>
<p>Инструмент умел генерировать только пустые классы миграций, внутри которых SQL-код для миграций вперед и назад приходилось писать вручную. Но этот инструмент послужил для меня прототипом моего будущего инструмента, что отразилось даже в названии.</p>
<p><strong>Ruby on Rails</strong></p>
<p>Перед тем как начать разработку я решил еще проверить как обстоят дела в Ruby on Rails. Там ситуация оказалась такой же печальной: Нужно запустить генератор, чтобы получить на выходе пустой класс миграции, в который опять же стоит добавить код для миграции вперед и назад. К тому же код на ruby, а его в моей команде никто не знал.</p>
<p><strong>Теперь о моей разработке:</strong></p>
<p><span style="color: #000080;"><span lang="zxx"><span style="text-decoration: underline;"><a href="http://www.antonoff.info/development/mysql-migration-with-php-project">http://www.antonoff.info/development/mysql-migration-with-php-project</a></span></span></span></p>
<p><span style="color: #000080;"><span lang="zxx"><span style="text-decoration: underline;"><a href="http://bitbucket.org/idler/mmp">http://bitbucket.org/idler/mmp</a></span></span></span></p>
<p>Вот требования которые были предъявлены к ней на старте:</p>
<ul>
<li>Минимум зависимостей 	— желательно только PHP (без дополнительных 	расширений) и MySQL.</li>
<li>Возможность производить 	произвольные изменения схемы 	непосредственно, используя для этого 	любой доступный клиент (mysql или PHPMyAdmin 	например)</li>
<li>Полностью автоматизированная генерация миграций.</li>
<li>Возможность 	использовать инструмент в скриптах 	или в cron.</li>
<li>Возможность мигрировать на произвольную версию схемы</li>
<li>Возможность произвольно именовать таблицу, хранящую версию схемы ( в Doctrine и в MPM имя этой таблицы жестко прошито в коде)</li>
<li>Возможность вывести список доступных миграций с датами</li>
<li>Возможность изменять имя каталога в котором хранятся файлы миграций.</li>
<li>Читабельность кода, который будет создан при генерации класса миграции</li>
<li>Command Line-интерфейс (другого мне и не нужно)</li>
<li>Возможность легко добавлять под-команды утилиты  (плагины? -	Скорее отдельные классы как плагины)</li>
</ul>
<p><strong>Что мы умеем?</strong></p>
<ul>
<li>Создать начальную миграцию.</li>
<li>Накатить начальную миграцию, т. е. инициализировать 	первую версию БД</li>
<li>Создать миграцию, самостоятельно сгенерив весь SQL-код.</li>
<li>Показать список миграций, пометив текущую звездочкой.</li>
<li>Мигрировать на указанную дату-время.</li>
</ul>
<p>Дата-время на которые будет произведена миграция указываются в формате, понимаемом PHP-функцией strtotime.</p>
<p><strong>Как это работает?</strong></p>
<p>При генерации нового миграционного класса MMP создает временную базу, в которую по очереди накатывает все существующие миграции, получая в итоге последнюю версию схему до ваших локальных изменений. Далее MMP сравнивает таблицы и поля внутри таблиц между двумя базами и создает SQL-запросы, которые приведут к тому, что временная база станет такой же как и рабочая. SQL-запросы пишутся в файл-класс миграции. При осуществлении миграции на определенную дату MMP определяет в какую сторону нужно мигрировать (вперед или назад) от текущего состояния, определяет миграции, которые нужно исполнить и их порядок. Далее в прямом или обратном порядке запускает эти миграции с нужным методом (up или down), который в свою очередь исполняет нужные запросы к базе.</p>
<p><strong>Зависимости:</strong></p>
<p>Консольная версия PHP &gt;= 5.3.0</p>
<p>Расширение MySQLi (обычно статически слинковано в PHP)</p>
<p>MySQL &gt;= 5.0 (возможно будет работать и на 4.1)</p>
<p><strong>Как использовать?</strong></p>
<p><em>Три раза в день, по чайной ложке после еды — до полного просветления <img src='http://softwarepeople.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </em></p>
<p>Поместите папку с MMP внутрь проекта.</p>
<p>Создайте внутри нее файл config.ini (описание конфига:   <span style="color: #000080;"><span lang="zxx"><span style="text-decoration: underline;"><a href="http://www.antonoff.info/development/mysql-migration-with-php-project">http://www.antonoff.info/development/mysql-migration-with-php-project</a></span></span></span> )</p>
<p>Создайте начальную миграцию ( ./migration.php schema )</p>
<p>В других установках вашего проекта накатите начальную миграцию ( ./migration.php init )</p>
<p>Изменяйте БД, и создавайте новые миграции ( ./migration.php create )</p>
<p>Чтобы мигрировать на последнюю версию, при получении новых миграций выполните (./migration.php migrate)</p>
<p>Просматривайте список доступных миграций (./migration.php list)</p>
<p>Мигрируйте на произвольную версию ( ./migration.php migrate 2 August 2010 )</p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/16/versioning_mysql_php/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Риски, паникеры и негодяи</title>
		<link>http://softwarepeople.ru/blog/2010/08/10/risks/</link>
		<comments>http://softwarepeople.ru/blog/2010/08/10/risks/#comments</comments>
		<pubDate>Mon, 09 Aug 2010 21:06:25 +0000</pubDate>
		<dc:creator>Константин</dc:creator>
		
		<category><![CDATA[Project Management]]></category>

		<guid isPermaLink="false">http://softwarepeople.ru/?p=2960</guid>
		<description><![CDATA[Тони Хейворд как исполнительный директор BP, безусловно, является главным ответственным за разлив нефти в Мексиканском заливе. Другой вопрос, является ли тем негодяем, каким из него хочет сделать пресса? Эмоциоанльный ответ – да. Разумный – нет.
Из тех фактов, которые были озвучены в СМИ, можно восстановить следующую картину. За две недели до аварии на скважение Deepwater Horizon [...]]]></description>
			<content:encoded><![CDATA[<p>Тони Хейворд как исполнительный директор BP, безусловно, является главным ответственным за разлив нефти в Мексиканском заливе. Другой вопрос, является ли тем негодяем, каким из него хочет сделать пресса? Эмоциоанльный ответ – да. Разумный – нет.<br />
Из тех фактов, которые были озвучены в СМИ, можно восстановить следующую картину. За две недели до аварии на скважение Deepwater Horizon инженеры обнаружили проблемы в оборудовании для предотвращения разрывов труб. Их надо было бы устранить, но для этого надо было остановить добычу на несколько дней – о чем и доложили менеджменту. Менеджмент, конечно же,  «проигнорировал», т.е. принял решение – продолжать добычу нефти. Что стало после – уже история. Чего не хватает в этой картине?<br />
Не хватает одной детали: обнаруженные инженерами проблемы оказались бы существенными только в случае наступления «катострафического, но маловероятного события». Делала ли BP нечто экстраординарное? Наверное, не более того, что делают все, когда речь идет о том, что мы считаем (или хотим считать) маловероятным. Мой коллега любит шутить, что проблема со статистикой начинаеится, когда ты сам становишся её частью. BP не повезло, что это маловероятное событие впервые наступило именно для них, а не для, скажем, Shell или Chevron.<br />
Особенность ИТ то, что риски и их последствия не только умозрительны, но и слишком редко материализуются на практие в что-то действительно болезненное. На основании чего определяются риски с точки зрения бизнес-менеджера без опыта в ИТ? На основании тыканья пальцем в небо. Какими могут оказаться реальные последствия, например, решения нагнать съехавший график важного проекта, урезав тестирование по самый минимум? Ведь номинально продукт будет работать в срок, а что еще надо? А 99,9% страхов из «анализа рисков» не только ни разу не случались в реальной жизни, но и не произойдут вообще.<br />
Давайте посмотрим, как оцениваются потенциальные убытки от простоев ИТ системы за один рабочий день (назовем это L). В самом простом (и поэтому чаще всего и используемом) случае это количество пользователей (u), умноженное на коэффициент использования системы в день (k), умноженное на стоимость работы в час (p). <br />
L = u * k * p.<br />
В чем «физический смысл» значения p? Можно долго рассуждать на эту тему, но по правде говоря это всего лишь число в таблице Эксель, которое используется в расчетах.<br />
Можно соглашаться или не соглашаться с приведенными выше наблюдением. Давайте представим, что руководство попросило Вас как менеджера в ИТ сделать нечто, выходящие за Ваши представления об максимально допустимом уровне риска. Естествнно, что Вы постараетесь переложить риски сврех того, что Вы считаете разумным, на руководство. Вы подготовились, сделали расчёты, такие красивые цифры получились&#8230; А руководство Вам говорит: не верю! Не верю, что реальные убытки будут вот столько, сколько Вы тут насчитали! Прекратите паниковать; лучше займитесь работой, вместо того, чтобы тратить время на бесполезную ерунду! Вы говорите, что у Вас не хватает людей в команде? Наверное, их у Вас слишком много, раз у Вас есть время делать бумажки. И, кстати, постарайтесь без этих убытков, на дворе и так кризис!<br />
Что ж, так совпали звезды, что Вам приходится выбирать, кем быть. Паникером – пытаясь убедить окружающих в реальности рисков, в которые никто, кроме Вас, не верит. Или негодяям – принимать на себя рискованные решения, чтобы выполнить поставленную задачу. Есть еще третий вариант: оценить, сколько времени есть до того, как у предполагаемых Вами рисков появится более-менее внятные шансы стать реальностью.<br />
Мы привыкли рассматривать риски по размеру последствий и вероятности их наступления. Хотя честнее было бы рассматривать риски с точки зрения времени и способа материализации. Сделать такую оценку не просто. Поэтому мы чаще слышим, что «это авария ждала, чтобы случиться», и совсем не слышим, что «эту аварию ждали с 25ой на 26ую неделю этого года, но она почему-то случилось на 24ой неделе». Однако и не так сложно, как может показаться на первый взгляд. Для этого надо а) найти слабое место, б) определить, что по этому место может «ударить» и в) оценить, когда сработает триггер «ударного механизма».<br />
Итак, заказчик решил сэкономить и решил исключить функционал контроля качества из продукта. Что ж, действительно, отсутствие контроля качества не сделает погоды после запуска продукта. Но если посмотреть более длительный период эксплуатации, то после 3го месяца пользователи ошибки и неточностей из-за отсутствия контроя качества будет заметны, но не будут сказаться на ежедневной работе. После года работы из-за количество неточностей и ошибок в данных персонал будет заметно не справляться с поставленным SLA. После этого проблемы будут разрастаться экспоненциально. Достоверно определить возможные сценарии развития на втором году можно будет только после 9ти месяцев работы продукта. Вам система нужна на 5ть лет. Если мы сделаем то, что мы просим, мы Вам можем гарантировать только первые три месяца работы. Остальное – в зависимости от того, как именно будут материализоваться риски&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://softwarepeople.ru/blog/2010/08/10/risks/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
