<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>FractalizeR's WebSite</title>
	
	<link>http://ru.fractalizer.ru</link>
	<description>Часть моего сайта, содержащая контент, специфичный для России</description>
	<lastBuildDate>Tue, 01 Nov 2011 06:57:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/FractalizersWebsiteRU" /><feedburner:info uri="fractalizerswebsiteru" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>JetBrains PHPStorm VS NetBeans</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/IKZDO1fSHAw/</link>
		<comments>http://ru.fractalizer.ru/frpost_194/jetbrains-phpstorm-vs-netbeans/#comments</comments>
		<pubDate>Tue, 01 Nov 2011 06:57:59 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=194</guid>
		<description><![CDATA[Читая статью на Хабре про скидки на PHPStorm, которым я давно уже пользуюсь и очень доволен, набрел в комментах на отличный список преимуществ PHPStorm перед Netbeans. Не могу удержаться от цитирования: подсветка и автокомплит например, CSS внутри HTML внутри JS внутри PHP. навигация по CSS именованные пачки вкладок (tasks) интегрированные с контролем версий и багтрекером [...]]]></description>
			<content:encoded><![CDATA[<p>Читая <a href="http://habrahabr.ru/blogs/php/131610/">статью на Хабре про скидки на PHPStorm</a>, которым я давно уже пользуюсь и очень доволен, набрел в комментах на отличный список преимуществ PHPStorm перед Netbeans. Не могу удержаться от цитирования:</p>
<p><span id="more-194"></span></p>
<ul>
<li>подсветка и автокомплит например, CSS внутри HTML внутри JS внутри PHP.</li>
<li>навигация по CSS</li>
<li>именованные пачки вкладок (tasks) интегрированные с контролем версий и багтрекером</li>
<li>лучший в мире GUI к Git (насколько вообще возможен GUI к этому поделию) и интеграция с Github.</li>
<li>Несколько VCS в проекте в любых сочетаниях любой вложенности с несколькими &laquo;корнями&raquo;</li>
<li>PhpStorm работает быстрее NetBeans for PHP.</li>
<li>поддержка PHPUnit (Status GUI, Go to test итп)</li>
<li>лучший в мире commit dialog (ввод коммента и полноценная правка исходников прямо из просмотра diffа)</li>
<li>рефакторинги вроде rename var/field/class (последний переименовывает заодно и файлы с классом и тестами), extract|inline variable, extract method итп.</li>
<li>идеальная реализация VCS history</li>
<li>лучший в мире редактор Javascript (автокомплит, рефакторинг, поддержка популярных фреймворков ипр.)</li>
<li>лучшая в мире реализация local history</li>
<li>визуальное слияние изменений файла внешней программой</li>
<li>управление кодировкой на уровнях проек/папка/файл (netbeans — кодировка одна на весь проект);</li>
<li>быстрое форматирование кода на больших файлах</li>
<li>цветные вкладки, раскрашиваемые по путям, которые можно задавать регулярками. Контроллеры, модели и вьюхи разными цветами</li>
<li>в результатах поиска можно тыкнуть на строчку — в окне рядом появится участок кода. Не надо открывать файл, чтобы посмотреть</li>
<li> подсветка неиспользуемых переменных</li>
<li>куча клавиатурных сочетаний</li>
</ul>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/IKZDO1fSHAw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_194/jetbrains-phpstorm-vs-netbeans/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_194/jetbrains-phpstorm-vs-netbeans/</feedburner:origLink></item>
		<item>
		<title>Jooq – «LINQ» для Java, типобезопасный построитель SQL запросов в Java коде</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/H86AqMdhFj0/</link>
		<comments>http://ru.fractalizer.ru/frpost_178/jooq-linq-%d0%b4%d0%bb%d1%8f-java-%d1%82%d0%b8%d0%bf%d0%be%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d1%8b%d0%b9-%d0%bf%d0%be%d1%81%d1%82%d1%80%d0%be%d0%b8%d1%82%d0%b5%d0%bb%d1%8c-sql/#comments</comments>
		<pubDate>Fri, 22 Apr 2011 10:26:09 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[jooq]]></category>
		<category><![CDATA[linq]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=178</guid>
		<description><![CDATA[Недавно, в поисках золотой середины между JDBC и ORM, я натолкнулся на интересную open source библиотеку (лицензия Apache Software License), с помощью которой можно строить SQL прямо в Java-коде достаточно удобно и безопасно. Библиотека называется jooq. jooq включает в себя генератор кода, который парсит структуру вашей базы данных и создает необходимые Java-классы. На деле получается [...]]]></description>
			<content:encoded><![CDATA[<p>Недавно, <a href="http://stackoverflow.com/questions/5620985/is-there-any-good-dynamic-sql-builder-library-in-java" target="_blank">в поисках</a> золотой середины между JDBC и ORM, я натолкнулся на интересную open source библиотеку (лицензия <a href="http://en.wikipedia.org/wiki/Apache_Software_License">Apache Software License</a>), с помощью которой можно строить SQL прямо в Java-коде достаточно удобно и безопасно. Библиотека называется jooq. jooq включает в себя генератор кода, который парсит структуру вашей базы данных и создает необходимые Java-классы. На деле получается примерно такой код:</p>
<div id="wpshdo_1" class="wp-synhighlighter-outer"><div id="wpshdt_1" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_1"></a><a id="wpshat_1" class="wp-synhighlighter-title" href="#codesyntax_1"  onClick="javascript:wpsh_toggleBlock(1)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_1" onClick="javascript:wpsh_code(1)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_1" onClick="javascript:wpsh_print(1)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_1" class="wp-synhighlighter-inner" style="display: block;"><pre class="java" style="font-family:monospace;"><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Ainteger+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Integer</span></a> taskId <span class="sy0">=</span> sqlFactory.<span class="me1">select</span><span class="br0">&#40;</span>ID<span class="br0">&#41;</span>.<span class="me1">from</span><span class="br0">&#40;</span>TASK<span class="br0">&#41;</span>.<span class="me1">where</span><span class="br0">&#40;</span>STATUS.<span class="me1">equal</span><span class="br0">&#40;</span>TaskStatus.<span class="me1">QUEUED</span><span class="br0">&#41;</span><span class="br0">&#41;</span>.
    <span class="me1">orderBy</span><span class="br0">&#40;</span>LAST_UPDATED<span class="br0">&#41;</span>.<span class="me1">limit</span><span class="br0">&#40;</span>1<span class="br0">&#41;</span>.<span class="me1">fetchOne</span><span class="br0">&#40;</span>ID<span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>
<p>Как видите, конструирование запроса и его выполнение для простых типов занимает одну строку. Немного о jooq:<br />
<span id="more-178"></span></p>
<h2>Что у нас хорошего?</h2>
<ul>
<li>Поддержка MySQL 5.1.41 / 5.5.8, Oracle XE 10.2.0.1.0, DB2 9.7, PostGreSQL 9.0, H2 1.3.154, HSQLDB 2.1.0, SQLite, Derby 10.7</li>
<li>Планируется поддержка Sybase, MSSQL, Ingres, Firebird</li>
<li>Поддержка генерации кода не только для таблиц / полей, но и представлений, хранимых процедур, UDF, сложных типов вроде ENUM в MySQL, Blob (можно представить их в виде обычных byte[])</li>
<li>Поскольку вся схема базы данных представлена классами, в <a href="http://www.jetbrains.com/idea/" target="_blank">нормальных IDE</a> (и даже <a href="http://www.eclipse.org/" target="_blank">в тех</a>, что <a href="http://netbeans.org/" target="_blank">не очень</a>) <img src='http://ru.fractalizer.ru/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  работает автозавершение языковых конструкций</li>
<li>Отсутствие уязвимости SQL Injection при правильном использовании &#8211; jooq пользуется шаблонами параметров в запросах</li>
<li>По большей части независимый от базы данных синтаксис</li>
<li>Использование обобщенных типов обеспечивает достаточное количество проверок еще при компиляции кода. Плюс невозможно забыть исправить какой-либо кусочек кода, если вы вдруг переименовали столбец в таблице БД. После повторного парсинга БД некорректный код просто не скомпилируется</li>
<li>Базовая поддержка ActiveRecord (полученную из базы данных запись можно изменить и записать назад одним-двумя строчками)</li>
<li>Поддержка не только SELECT запросов, но и INSERT, UPDATE.</li>
<li>Поддержка вложенных запросов, произвольных полей, агрегатных функций, UNION запросов, арифметических и других операций</li>
<li>Удобные методы получения результатов выполнения запроса &#8211; fetch(), fetchAny(), fetchLazy(), fetchMap() и другие.</li>
<li>Хорошая поддержка <a href="http://www.slf4j.org/" target="_blank">SLF4J</a> в том числе и для профайлинга внутреннего устройства Jooq.</li>
<li><a href="https://sourceforge.net/apps/trac/jooq/roadmap" target="_blank">Много чего запланировано</a></li>
<li>Автор постоянно в интернете, очень оперативно отвечает на вопросы в <a href="http://groups.google.com/group/jooq-user" target="_blank">jooq Google Group</a> и на <a href="https://sourceforge.net/apps/trac/jooq/report" target="_blank">тикеты в баг-трекере</a>.</li>
<li>Поддержка <a href="http://maven.apache.org/" target="_blank">Maven</a>. Дистрибутивы jooq доступны через <a href="http://maven.apache.org/guides/mini/guide-central-repository-upload.html" target="_blank">Maven Central</a>.</li>
<li>Поддержка как DSL синтаксиса <em>(select().from().where())</em> конструирования запросов, так и ООП <em>(a=new Query(); a.addSelect(); a.addFrom())</em></li>
<li>Результаты запросов и сами объекты запросов сериализуемы.</li>
</ul>
<h2>Что у нас плохого?</h2>
<ul>
<li><a href="https://sourceforge.net/apps/trac/jooq/ticket/420" target="_blank">Пока нет</a> непосредственной поддержки некоторых специфичных языковых возможностей вроде &laquo;FOR UPDATE&raquo; или &laquo;index usage hints&raquo;конструкций в SELECT. Но есть <a href="https://groups.google.com/forum/#!topic/jooq-user/Xoiy4vWODK0" target="_blank">workaround</a>.</li>
<li>Если вы работаете в одном классе более чем с одной таблицей, import static в некоторых случаях использовать затруднительно, что приводит к некоторому усложнению внешнего вида запроса (пример по отношению к тому, что указан сверху):</li>
</ul>
<div id="wpshdo_2" class="wp-synhighlighter-outer"><div id="wpshdt_2" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_2"></a><a id="wpshat_2" class="wp-synhighlighter-title" href="#codesyntax_2"  onClick="javascript:wpsh_toggleBlock(2)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_2" onClick="javascript:wpsh_code(2)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_2" onClick="javascript:wpsh_print(2)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_2" class="wp-synhighlighter-inner" style="display: block;"><pre class="java" style="font-family:monospace;"><a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Ainteger+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Integer</span></a> taskId <span class="sy0">=</span> sqlFactory.<span class="me1">select</span><span class="br0">&#40;</span>Task.<span class="me1">ID</span><span class="br0">&#41;</span>.<span class="me1">from</span><span class="br0">&#40;</span>Task.<span class="me1">TASK</span><span class="br0">&#41;</span>.<span class="me1">where</span><span class="br0">&#40;</span>Task.<span class="me1">STATUS</span>.<span class="me1">equal</span><span class="br0">&#40;</span>TaskStatus.<span class="me1">QUEUED</span><span class="br0">&#41;</span><span class="br0">&#41;</span>.
    <span class="me1">orderBy</span><span class="br0">&#40;</span>Task.<span class="me1">LAST_UPDATED</span><span class="br0">&#41;</span>.<span class="me1">limit</span><span class="br0">&#40;</span>1<span class="br0">&#41;</span>.<span class="me1">fetchOne</span><span class="br0">&#40;</span>Task.<span class="me1">ID</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>
<ul>
<li>Небольшой оверхед при исполнении запросов и обходе результата (думаю, он небольшой, десятки-сотни микросекунд, может быть?)</li>
<li><a href="https://sourceforge.net/apps/trac/jooq/ticket/416" target="_blank">Пока нет</a> непосредственной поддержки LAST_INSERT_ID() в MySQL. Но есть <a href="https://groups.google.com/d/topic/jooq-user/bCTfnqnS1zU/discussion" target="_blank">workaround</a>. Sequences <a href="http://sourceforge.net/apps/trac/jooq/wiki/Manual/META/SEQUENCE" target="_blank">поддерживаются</a>.</li>
</ul>
<p>&nbsp;</p>
<h2>Субъективности</h2>
<ul>
<li>Кода пока нет на GitHub  <img src='http://ru.fractalizer.ru/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> , основная разработка ведется в Subversion</li>
<li>SourceForge страницы проекта слегка тормозят, что немного раздражает.</li>
<li>Мануал вроде бы достаточно подробен, но некоторые простые, но полезные вещи в нем отсутствуют. Он также показался мне не слишком удобным. В нем описано только самое основное без &laquo;фишек&raquo;, &laquo;плюшек&raquo; и удобностей. Впрочем, если у вас большой стаж Java, наверное, до всего можно и самому быстро дойти. Кроме того, мне показалось, что он не слишком хорошо структурирован. Информация по нему размазана. Я всегда тороплюсь и хороший мануал для меня must-have&#8230;</li>
<li>Не слишком удобный синтаксис для работы с агрегированными полями (во всяком случае, я по-другому пока не придумал, как можно это сделать удобно)</li>
</ul>
<div id="wpshdo_3" class="wp-synhighlighter-outer"><div id="wpshdt_3" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_3"></a><a id="wpshat_3" class="wp-synhighlighter-title" href="#codesyntax_3"  onClick="javascript:wpsh_toggleBlock(3)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_3" onClick="javascript:wpsh_code(3)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_3" onClick="javascript:wpsh_print(3)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_3" class="wp-synhighlighter-inner" style="display: block;"><pre class="java" style="font-family:monospace;">Field<span class="sy0">&lt;</span>Integer<span class="sy0">&gt;</span> jobTypeCountField <span class="sy0">=</span> Job.<span class="me1">JOBTYPE_ID</span>.<span class="me1">count</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">as</span><span class="br0">&#40;</span><span class="st0">&quot;JOBTYPE_ID_COUNT&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
Result<span class="sy0">&lt;</span>Record<span class="sy0">&gt;</span> jobTypeCountRecord <span class="sy0">=</span> <span class="kw2">null</span><span class="sy0">;</span>
jobTypeCountRecord <span class="sy0">=</span> sqlFactory.<span class="me1">select</span><span class="br0">&#40;</span>Job.<span class="me1">JOBTYPE_ID</span>, jobTypeCountField<span class="br0">&#41;</span>.<span class="me1">from</span><span class="br0">&#40;</span>Job.<span class="me1">JOB</span><span class="br0">&#41;</span>
    .<span class="me1">where</span><span class="br0">&#40;</span>Job.<span class="me1">STATUS</span>.<span class="me1">equal</span><span class="br0">&#40;</span>JobStatus.<span class="me1">EXECUTING</span><span class="br0">&#41;</span><span class="br0">&#41;</span>.<span class="me1">groupBy</span><span class="br0">&#40;</span>Job.<span class="me1">JOBTYPE_ID</span><span class="br0">&#41;</span>.<span class="me1">fetch</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="kw1">for</span> <span class="br0">&#40;</span>Record record <span class="sy0">:</span> jobTypeCountRecord<span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Asystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">System</span></a>.<span class="me1">out</span>.<span class="me1">println</span><span class="br0">&#40;</span>record.<span class="me1">getValue</span><span class="br0">&#40;</span>Job.<span class="me1">JOBTYPE_ID</span><span class="br0">&#41;</span> <span class="sy0">+</span> <span class="st0">&quot; - &quot;</span> <span class="sy0">-</span> record.<span class="me1">getValue</span><span class="br0">&#40;</span>jobTypeCountField<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></div></div>
<p>Впрочем, мнения на этот счет могут быть разными. Кому-то такой код покажется более понятным.</p>
<ul>
<li>В версии 2.0 запланированы <a href="https://sourceforge.net/apps/trac/jooq/query?status=assigned&amp;status=new&amp;status=accepted&amp;status=reopened&amp;group=status&amp;milestone=Version+2.0+The+far+away+future" target="_blank">очень интересные плюшки</a>.</li>
<li>Не-wiki документация (Trac) и не слишком удобная по ней навигация. Впрочем, в коде достаточно javadoc чтобы все понимать по Ctrl-Q. Впрочем, просто я считаю Trac не слишком удобным, вот и придираюсь&#8230;</li>
<li>Пока <a href="https://sourceforge.net/projects/jooq/files/Release/stats/timeline?dates=2011-01-01+to+2011-04-22" target="_blank">сравнительно</a> <a href="http://stackoverflow.com/questions/5625832/java-jooq-persistence-framework-performance-and-feed-back" target="_blank">небольшое</a> количество пользователей.</li>
</ul>
<h2><a href="http://stackoverflow.com/questions/5620985/is-there-any-good-dynamic-sql-builder-library-in-java" target="_blank">Аналоги</a> jooq</h2>
<ul>
<li><a rel="nofollow" href="http://www.querydsl.com/">Querydsl</a></li>
<li><a rel="nofollow" href="https://github.com/fuzzylollipop/sqlck">SQL Construction Kit</a> (документации по нему найти не удалось)</li>
</ul>
<p>&nbsp;</p>
<h2>Контакты:</h2>
<ul>
<li>Сайт проекта &#8211; <a href="http://www.jooq.org" target="_blank">http://www.jooq.org</a></li>
<li>Мануал: <a href="http://sourceforge.net/apps/trac/jooq/wiki/Manual" target="_blank">http://sourceforge.net/apps/trac/jooq/wiki/Manual</a></li>
<li>Форум &#8211; <a href="http://groups.google.com/group/jooq-user" target="_blank">http://groups.google.com/group/jooq-user</a></li>
<li>SVN Info: <a href="https://sourceforge.net/scm/?type=svn&amp;group_id=283484" target="_blank">https://sourceforge.net/scm/?type=svn&amp;group_id=283484</a></li>
</ul>
<p>&nbsp;</p>
<h2>Несколько примеров из исходников Jooq (работа с базой information_schema в MySQL)</h2>
<div id="wpshdo_4" class="wp-synhighlighter-outer"><div id="wpshdt_4" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_4"></a><a id="wpshat_4" class="wp-synhighlighter-title" href="#codesyntax_4"  onClick="javascript:wpsh_toggleBlock(4)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_4" onClick="javascript:wpsh_code(4)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_4" onClick="javascript:wpsh_print(4)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_4" class="wp-synhighlighter-inner" style="display: block;"><pre class="java" style="font-family:monospace;">select<span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">CONSTRAINT_NAME</span>, KeyColumnUsage.<span class="me1">TABLE_NAME</span>, KeyColumnUsage.<span class="me1">COLUMN_NAME</span><span class="br0">&#41;</span>
                .<span class="me1">from</span><span class="br0">&#40;</span>KEY_COLUMN_USAGE<span class="br0">&#41;</span>.<span class="me1">join</span><span class="br0">&#40;</span>TABLE_CONSTRAINTS<span class="br0">&#41;</span>
                .<span class="me1">on</span><span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">TABLE_SCHEMA</span>.<span class="me1">equal</span><span class="br0">&#40;</span>TableConstraints.<span class="me1">TABLE_SCHEMA</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">and</span><span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">TABLE_NAME</span>.<span class="me1">equal</span><span class="br0">&#40;</span>TableConstraints.<span class="me1">TABLE_NAME</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">and</span><span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">CONSTRAINT_NAME</span>.<span class="me1">equal</span><span class="br0">&#40;</span>TableConstraints.<span class="me1">CONSTRAINT_NAME</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">where</span><span class="br0">&#40;</span>TableConstraints.<span class="me1">CONSTRAINT_TYPE</span>.<span class="me1">equal</span><span class="br0">&#40;</span>constraintType<span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">and</span><span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">TABLE_SCHEMA</span>.<span class="me1">equal</span><span class="br0">&#40;</span>getSchemaName<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">orderBy</span><span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">TABLE_NAME</span>.<span class="me1">ascending</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, KeyColumnUsage.<span class="me1">ORDINAL_POSITION</span>.<span class="me1">ascending</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>.<span class="me1">fetch</span><span class="br0">&#40;</span><span class="br0">&#41;</span></pre></div></div>
<div id="wpshdo_5" class="wp-synhighlighter-outer"><div id="wpshdt_5" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_5"></a><a id="wpshat_5" class="wp-synhighlighter-title" href="#codesyntax_5"  onClick="javascript:wpsh_toggleBlock(5)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_5" onClick="javascript:wpsh_code(5)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_5" onClick="javascript:wpsh_print(5)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_5" class="wp-synhighlighter-inner" style="display: block;"><pre class="java" style="font-family:monospace;"><span class="kw1">for</span> <span class="br0">&#40;</span>Record record <span class="sy0">:</span> create<span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">select</span><span class="br0">&#40;</span>
                    ReferentialConstraints.<span class="me1">CONSTRAINT_NAME</span>,
                    ReferentialConstraints.<span class="me1">TABLE_NAME</span>,
                    ReferentialConstraints.<span class="me1">REFERENCED_TABLE_NAME</span>,
                    ReferentialConstraints.<span class="me1">UNIQUE_CONSTRAINT_NAME</span>,
                    KeyColumnUsage.<span class="me1">COLUMN_NAME</span><span class="br0">&#41;</span>
                .<span class="me1">from</span><span class="br0">&#40;</span>REFERENTIAL_CONSTRAINTS<span class="br0">&#41;</span>
                .<span class="me1">join</span><span class="br0">&#40;</span>KEY_COLUMN_USAGE<span class="br0">&#41;</span>
                .<span class="me1">on</span><span class="br0">&#40;</span>ReferentialConstraints.<span class="me1">CONSTRAINT_SCHEMA</span>.<span class="me1">equal</span><span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">CONSTRAINT_SCHEMA</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">and</span><span class="br0">&#40;</span>ReferentialConstraints.<span class="me1">CONSTRAINT_NAME</span>.<span class="me1">equal</span><span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">CONSTRAINT_NAME</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">where</span><span class="br0">&#40;</span>ReferentialConstraints.<span class="me1">CONSTRAINT_SCHEMA</span>.<span class="me1">equal</span><span class="br0">&#40;</span>getSchemaName<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">orderBy</span><span class="br0">&#40;</span>
                    KeyColumnUsage.<span class="me1">CONSTRAINT_NAME</span>.<span class="me1">ascending</span><span class="br0">&#40;</span><span class="br0">&#41;</span>,
                    KeyColumnUsage.<span class="me1">ORDINAL_POSITION</span>.<span class="me1">ascending</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
                .<span class="me1">fetch</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp;
            <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> foreignKey <span class="sy0">=</span> record.<span class="me1">getValue</span><span class="br0">&#40;</span>ReferentialConstraints.<span class="me1">CONSTRAINT_NAME</span><span class="br0">&#41;</span><span class="sy0">;</span>
            <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> foreignKeyColumn <span class="sy0">=</span> record.<span class="me1">getValue</span><span class="br0">&#40;</span>KeyColumnUsage.<span class="me1">COLUMN_NAME</span><span class="br0">&#41;</span><span class="sy0">;</span>
            <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> foreignKeyTableName <span class="sy0">=</span> record.<span class="me1">getValue</span><span class="br0">&#40;</span>ReferentialConstraints.<span class="me1">TABLE_NAME</span><span class="br0">&#41;</span><span class="sy0">;</span>
            <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> referencedKey <span class="sy0">=</span> record.<span class="me1">getValue</span><span class="br0">&#40;</span>ReferentialConstraints.<span class="me1">UNIQUE_CONSTRAINT_NAME</span><span class="br0">&#41;</span><span class="sy0">;</span>
            <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> referencedTableName <span class="sy0">=</span> record.<span class="me1">getValue</span><span class="br0">&#40;</span>ReferentialConstraints.<span class="me1">REFERENCED_TABLE_NAME</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
            TableDefinition foreignKeyTable <span class="sy0">=</span> getTable<span class="br0">&#40;</span>foreignKeyTableName<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
            <span class="kw1">if</span> <span class="br0">&#40;</span>foreignKeyTable <span class="sy0">!=</span> <span class="kw2">null</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
                ColumnDefinition column <span class="sy0">=</span> foreignKeyTable.<span class="me1">getColumn</span><span class="br0">&#40;</span>foreignKeyColumn<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
                <a href="http://www.google.com/search?hl=en&amp;q=allinurl%3Astring+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">String</span></a> key <span class="sy0">=</span> getKeyName<span class="br0">&#40;</span>referencedTableName, referencedKey<span class="br0">&#41;</span><span class="sy0">;</span>
                relations.<span class="me1">addForeignKey</span><span class="br0">&#40;</span>foreignKey, key, column<span class="br0">&#41;</span><span class="sy0">;</span>
            <span class="br0">&#125;</span>
        <span class="br0">&#125;</span></pre></div></div>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/H86AqMdhFj0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_178/jooq-linq-%d0%b4%d0%bb%d1%8f-java-%d1%82%d0%b8%d0%bf%d0%be%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d1%8b%d0%b9-%d0%bf%d0%be%d1%81%d1%82%d1%80%d0%be%d0%b8%d1%82%d0%b5%d0%bb%d1%8c-sql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_178/jooq-linq-%d0%b4%d0%bb%d1%8f-java-%d1%82%d0%b8%d0%bf%d0%be%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d1%8b%d0%b9-%d0%bf%d0%be%d1%81%d1%82%d1%80%d0%be%d0%b8%d1%82%d0%b5%d0%bb%d1%8c-sql/</feedburner:origLink></item>
		<item>
		<title>Используем CDN Яндекса для jQuery в XenForo</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/ROHx7vPiN9g/</link>
		<comments>http://ru.fractalizer.ru/frpost_171/%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d1%83%d0%b5%d0%bc-cdn-%d1%8f%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d0%b0-%d0%b4%d0%bb%d1%8f-jquery-%d0%b2-xenforo/#comments</comments>
		<pubDate>Wed, 09 Mar 2011 13:27:19 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[XenForo]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=171</guid>
		<description><![CDATA[Если форум предназначен для России, можно использовать CDN Яндекса. Только нужно немного форум подпатчить. 1. Открываем library\XenForo\Dependencies\Public.php и заменяем метод getJquerySource на такой (просто добавляем еще один case фактически): 2. В Debug режиме идем в панель управления, находим там опцию jQuery Source (CDNjQuery) в разделе Performance (Производительность) и нажимаем карандашик справа (редактирование). Format Parameters (Параметры [...]]]></description>
			<content:encoded><![CDATA[<p>Если форум предназначен для России, можно использовать CDN Яндекса. Только нужно немного форум подпатчить.</p>
<p>1. Открываем library\XenForo\Dependencies\Public.php и заменяем метод  getJquerySource на такой (просто добавляем еще один case фактически):</p>
<div id="wpshdo_6" class="wp-synhighlighter-outer"><div id="wpshdt_6" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_6"></a><a id="wpshat_6" class="wp-synhighlighter-title" href="#codesyntax_6"  onClick="javascript:wpsh_toggleBlock(6)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_6" onClick="javascript:wpsh_code(6)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_6" onClick="javascript:wpsh_print(6)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_6" class="wp-synhighlighter-inner" style="display: block;"><pre class="php" style="font-family:monospace;"><span class="co4">/**
	 * Fetch the path / URL to the jQuery core library
	 *
	 * @param boolean $forceLocal If true, forces the local version of jQuery
	 *
	 * @return string
	 */</span>
	<span class="kw2">public</span> static <span class="kw2">function</span> getJquerySource<span class="br0">&#40;</span><span class="re0">$forceLocal</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="br0">&#41;</span>
	<span class="br0">&#123;</span>
		<span class="re0">$jQueryVersion</span> <span class="sy0">=</span> XenForo_Application<span class="sy0">::</span><span class="re0">$jQueryVersion</span><span class="sy0">;</span>
		<span class="re0">$min</span> <span class="sy0">=</span> <span class="st_h">'.min'</span><span class="sy0">;</span>
&nbsp;
		<span class="co1">// CDN sources from http://docs.jquery.com/Downloading_jQuery#CDN_Hosted_jQuery</span>
		<span class="re0">$source</span> <span class="sy0">=</span> <span class="br0">&#40;</span><span class="re0">$forceLocal</span> ? <span class="st_h">'local'</span> <span class="sy0">:</span> XenForo_Application<span class="sy0">::</span><span class="me2">get</span><span class="br0">&#40;</span><span class="st_h">'options'</span><span class="br0">&#41;</span><span class="sy0">-&gt;</span><span class="me1">jQuerySource</span><span class="br0">&#41;</span><span class="sy0">;</span>
		<span class="kw1">switch</span> <span class="br0">&#40;</span><span class="re0">$source</span><span class="br0">&#41;</span>
		<span class="br0">&#123;</span>
			<span class="kw1">case</span> <span class="st_h">'jquery'</span><span class="sy0">:</span>
			<span class="kw1">case</span> <span class="st_h">'mt'</span><span class="sy0">:</span>
				<span class="kw1">return</span> <span class="st0">&quot;http://code.jquery.com/jquery-<span class="es4">{$jQueryVersion}</span><span class="es4">{$min}</span>.js&quot;</span><span class="sy0">;</span>
&nbsp;
			<span class="kw1">case</span> <span class="st_h">'google'</span><span class="sy0">:</span>
				<span class="kw1">return</span> <span class="st0">&quot;http://ajax.googleapis.com/ajax/libs/jquery/<span class="es4">{$jQueryVersion}</span>/jquery<span class="es4">{$min}</span>.js&quot;</span><span class="sy0">;</span>
&nbsp;
			<span class="kw1">case</span> <span class="st_h">'microsoft'</span><span class="sy0">:</span>
				<span class="kw1">return</span> <span class="st0">&quot;http://ajax.microsoft.com/ajax/jquery/jquery-<span class="es4">{$jQueryVersion}</span><span class="es4">{$min}</span>.js&quot;</span><span class="sy0">;</span>
&nbsp;
			<span class="kw1">case</span> <span class="st_h">'yandex'</span><span class="sy0">:</span>
				<span class="kw1">return</span> <span class="st0">&quot;http://yandex.st/jquery/<span class="es4">{$jQueryVersion}</span>/jquery<span class="es4">{$min}</span>.js&quot;</span><span class="sy0">;</span>
&nbsp;
			<span class="kw1">default</span><span class="sy0">:</span>
				<span class="kw1">return</span> <span class="st0">&quot;js/jquery/jquery-<span class="es4">{$jQueryVersion}</span><span class="es4">{$min}</span>.js&quot;</span><span class="sy0">;</span>
		<span class="br0">&#125;</span>
	<span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></div></div>
<p>2. В <a href="http://www.xf-russia.ru/forum/threads/%D0%9A%D0%B0%D0%BA-%D0%B2%D1%8B%D0%B2%D0%B5%D1%81%D1%82%D0%B8-%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B8-%D1%84%D0%BE%D1%80%D1%83%D0%BC%D0%B0-%D0%B2%D0%B2%D0%B5%D1%81%D1%82%D0%B8-%D1%84%D0%BE%D1%80%D1%83%D0%BC-%D0%B2-%D1%80%D0%B5%D0%B6%D0%B8%D0%BC-%D0%BE%D1%82%D0%BB%D0%B0%D0%B4%D0%BA%D0%B8.304/#post-9177" target="_blank">Debug режиме</a> идем в панель управления, находим там опцию jQuery  Source (CDNjQuery) в разделе Performance (Производительность) и нажимаем  карандашик справа (редактирование). Format Parameters (Параметры  формата) заменяем на:</p>
<pre>local=Local
google=Google Ajax API CDN
jquery=jQuery CDN
microsoft=Microsoft CDN
yandex=Яндекс CDN</pre>
<p>Вот и все.  Теперь в настройках форума можно выбрать Яндекс CDN и jQuery будет загружаться с Яндекса. Только не забудьте отключить Debug режим.</p>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/ROHx7vPiN9g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_171/%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d1%83%d0%b5%d0%bc-cdn-%d1%8f%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d0%b0-%d0%b4%d0%bb%d1%8f-jquery-%d0%b2-xenforo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_171/%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d1%83%d0%b5%d0%bc-cdn-%d1%8f%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d0%b0-%d0%b4%d0%bb%d1%8f-jquery-%d0%b2-xenforo/</feedburner:origLink></item>
		<item>
		<title>Регулярка для ника: либо по-русски, либо по-английски, но не смешивая</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/OrnGht3WInI/</link>
		<comments>http://ru.fractalizer.ru/frpost_166/%d1%80%d0%b5%d0%b3%d1%83%d0%bb%d1%8f%d1%80%d0%ba%d0%b0-%d0%b4%d0%bb%d1%8f-%d0%bd%d0%b8%d0%ba%d0%b0-%d0%bb%d0%b8%d0%b1%d0%be-%d0%bf%d0%be-%d1%80%d1%83%d1%81%d1%81%d0%ba%d0%b8-%d0%bb%d0%b8%d0%b1%d0%be/#comments</comments>
		<pubDate>Mon, 22 Nov 2010 14:02:05 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=166</guid>
		<description><![CDATA[Недавно меня попросили написать регулярное выражение, которое бы пропускало ники на форуме написанные либо целиком русскими буквами, либо целиком английскими (чтобы не допускала смешение букв). На форуме используется кодировка UTF-8. ^(([a-zA-Z0-9_\-\?]+)&#124;(((\xD0[\x80-\xBF])&#124;(\xD1[\x80-\xBF])&#124;([0-9_\-\?]))+))$ Вот она такая получилась. Обратите внимание, что пробелы запрещены. Если требуется их разрешить, можно добавить после 0-9 \x20.]]></description>
			<content:encoded><![CDATA[<p>Недавно меня попросили написать регулярное выражение, которое бы пропускало ники на форуме написанные либо целиком русскими буквами, либо целиком английскими (чтобы не допускала смешение букв). На форуме используется кодировка UTF-8.</p>
<pre><code>^(([a-zA-Z0-9_\-\?]+)|(((\xD0[\x80-\xBF])|(\xD1[\x80-\xBF])|([0-9_\-\?]))+))$
</code></pre>
<p>Вот она такая получилась. Обратите внимание, что пробелы запрещены. Если требуется их разрешить, можно добавить после 0-9 <strong>\x20</strong>.</p>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/OrnGht3WInI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_166/%d1%80%d0%b5%d0%b3%d1%83%d0%bb%d1%8f%d1%80%d0%ba%d0%b0-%d0%b4%d0%bb%d1%8f-%d0%bd%d0%b8%d0%ba%d0%b0-%d0%bb%d0%b8%d0%b1%d0%be-%d0%bf%d0%be-%d1%80%d1%83%d1%81%d1%81%d0%ba%d0%b8-%d0%bb%d0%b8%d0%b1%d0%be/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_166/%d1%80%d0%b5%d0%b3%d1%83%d0%bb%d1%8f%d1%80%d0%ba%d0%b0-%d0%b4%d0%bb%d1%8f-%d0%bd%d0%b8%d0%ba%d0%b0-%d0%bb%d0%b8%d0%b1%d0%be-%d0%bf%d0%be-%d1%80%d1%83%d1%81%d1%81%d0%ba%d0%b8-%d0%bb%d0%b8%d0%b1%d0%be/</feedburner:origLink></item>
		<item>
		<title>Регулярное выражение для русских букв в UTF-8</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/aSY8g06Jh_8/</link>
		<comments>http://ru.fractalizer.ru/frpost_162/%d1%80%d0%b5%d0%b3%d1%83%d0%bb%d1%8f%d1%80%d0%bd%d0%be%d0%b5-%d0%b2%d1%8b%d1%80%d0%b0%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d1%83%d1%81%d1%81%d0%ba%d0%b8%d1%85-%d0%b1%d1%83%d0%ba/#comments</comments>
		<pubDate>Mon, 22 Nov 2010 09:23:07 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=162</guid>
		<description><![CDATA[(\xD0[\x80-\xBF])&#124;(\xD1[\x80-\xBF]) &#8211; одна любая русская буква]]></description>
			<content:encoded><![CDATA[<p>(\xD0[\x80-\xBF])|(\xD1[\x80-\xBF]) &#8211; одна любая русская буква</p>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/aSY8g06Jh_8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_162/%d1%80%d0%b5%d0%b3%d1%83%d0%bb%d1%8f%d1%80%d0%bd%d0%be%d0%b5-%d0%b2%d1%8b%d1%80%d0%b0%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d1%83%d1%81%d1%81%d0%ba%d0%b8%d1%85-%d0%b1%d1%83%d0%ba/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_162/%d1%80%d0%b5%d0%b3%d1%83%d0%bb%d1%8f%d1%80%d0%bd%d0%be%d0%b5-%d0%b2%d1%8b%d1%80%d0%b0%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d1%83%d1%81%d1%81%d0%ba%d0%b8%d1%85-%d0%b1%d1%83%d0%ba/</feedburner:origLink></item>
		<item>
		<title>Примеси VS делегирование: преимущества и недостатки при реализации «плагинов»</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/sIR6RLT0wNI/</link>
		<comments>http://ru.fractalizer.ru/frpost_154/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%81%d0%b8-vs-%d0%b4%d0%b5%d0%bb%d0%b5%d0%b3%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%b5%d0%b8%d0%bc%d1%83%d1%89%d0%b5%d1%81%d1%82%d0%b2%d0%b0/#comments</comments>
		<pubDate>Sat, 13 Nov 2010 18:22:46 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Без рубрики]]></category>
		<category><![CDATA[Общие вопросы программирования]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=154</guid>
		<description><![CDATA[В данной статье я предлагаю вам свой взгляд на выбор использования примесей или делегирования в проектах для внесения в класс нового функционала. Начальные условия такие: мы рассматриваем примеси, имеющие свое состояние и имеющие доступ ко всем членам класса-агрегатора. Все публичные члены класса примеси становятся частью агрегатора. Мы оставляем за кадром вопрос быстродействия. В основном данная [...]]]></description>
			<content:encoded><![CDATA[<p>В данной статье я предлагаю вам свой взгляд на выбор использования примесей или делегирования в проектах для внесения в класс нового функционала.</p>
<p>Начальные условия такие: мы рассматриваем примеси, имеющие свое состояние и имеющие доступ ко всем членам класса-агрегатора. Все публичные члены класса примеси становятся частью агрегатора. Мы оставляем за кадром вопрос быстродействия.</p>
<p>В основном данная статья относится к PHP, но с некоторыми оговорками подходит и для многих других динамических языков, позволяющих тем или иным способом реализовывать примеси.</p>
<p><span id="more-154"></span></p>
<p>Данная статья в некотором роде является логическим продолжением <a href="http://ru.fractalizer.ru/frpost_128/%d0%be%d0%be%d0%bf-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d1%83%d0%bc-php5-%d1%8d%d0%bc%d1%83%d0%bb%d1%8f%d1%86%d0%b8%d1%8f-%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%81%d0%b5%d0%b9-mixin-%d0%b2-%d1%8f/" target="_blank">этой</a> статьи о реализации примесей в PHP. Если вам интересно &#8211; прочтите. Если нет, это не будет проблемой для понимания излагаемого тут материала.</p>
<h1></h1>
<h1>Образцы кода</h1>
<p>Сначала рассмотрим различия двух подходов на примере кода, делающего одно и то же.</p>
<h2>Примесь</h2>
<div id="wpshdo_7" class="wp-synhighlighter-outer"><div id="wpshdt_7" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_7"></a><a id="wpshat_7" class="wp-synhighlighter-title" href="#codesyntax_7"  onClick="javascript:wpsh_toggleBlock(7)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_7" onClick="javascript:wpsh_code(7)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_7" onClick="javascript:wpsh_print(7)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_7" class="wp-synhighlighter-inner" style="display: block;"><pre class="php" style="font-family:monospace;"><span class="kw2">class</span> Aggregator <span class="br0">&#123;</span> <span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> Mixin <span class="br0">&#123;</span>
    <span class="kw2">public</span> <span class="kw2">function</span> doSomething<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
Mixins<span class="sy0">::</span><span class="me2">mix</span><span class="br0">&#40;</span><span class="st0">&quot;Aggregator&quot;</span><span class="sy0">,</span> <span class="st0">&quot;Mixin&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp;
<span class="re0">$a</span> <span class="sy0">=</span> <span class="kw2">new</span> Aggregator <span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">doSomething</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>
<h2>Делегирование</h2>
<div id="wpshdo_8" class="wp-synhighlighter-outer"><div id="wpshdt_8" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_8"></a><a id="wpshat_8" class="wp-synhighlighter-title" href="#codesyntax_8"  onClick="javascript:wpsh_toggleBlock(8)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_8" onClick="javascript:wpsh_code(8)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_8" onClick="javascript:wpsh_print(8)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_8" class="wp-synhighlighter-inner" style="display: block;"><pre class="php" style="font-family:monospace;"><span class="kw2">Class</span> Aggregator <span class="br0">&#123;</span><span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> Mixin <span class="br0">&#123;</span>
    <span class="kw2">public</span> <span class="kw2">function</span> doSomething<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">class</span> AggregatorMixed <span class="kw2">extends</span> Aggregator <span class="br0">&#123;</span>
    <span class="kw2">private</span> <span class="re0">$mixin</span><span class="sy0">;</span>
&nbsp;
    <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="re0">$mixin</span> <span class="sy0">=</span> <span class="kw2">new</span> Mixin<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span class="kw2">public</span> <span class="kw2">function</span> doSomething<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span class="re0">$mixin</span><span class="sy0">-&gt;</span><span class="me1">doSomething</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="re0">$a</span> <span class="sy0">=</span> <span class="kw2">new</span> AggregatorMixed <span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
<span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">doSomething</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></pre></div></div>
<p>Обратите внимание, что в некоторых случаях вы можете избежать наследования, если вы можете включить делегируемые методы прямо в класс Aggregator. Но это не всегда возможно и я привел здесь пример именно в таком виде из-за рассмотрения примесей и делегирования в контексте реализации плагинов к ORM, которую вы найдете ниже.</p>
<h1>Технические различия</h1>
<p>Чем же отличаются два фрагмента с технической точки зрения? Они обеспечивают одинаковый функционал, как видите.</p>
<p>1.       Вызов методов примеси осуществляется динамически по имени, а в случае с делегированием компилятор может осуществить проверку до исполнения кода.</p>
<p>Динамические вызовы привносят в программу гибкость, которая дается ценой отсутствия проверки типов на этапе компиляции. В случае использования примесей дополнительные юнит-тесты вам пригодятся.</p>
<p>2.       В случае примеси для добавления функционала мы его просто подмешиваем в тот же класс в любой момент времени, а в случае с делегированием для добавления функционала мы должны создать подкласс с новыми методами, делегирующими требуемый функционал.</p>
<p>Создание и поддержка подкласса требует определенных трудозатрат, объем его собственного кода немного возрастает, но в итоге вы видите целостный класс, в котором видны все предоставляемые им возможности. Примеси же подключаются к классам очень быстро безо всякого дополнительного кодирования, но в итоге вы видите класс-агрегат отдельно и все примеси отдельно.</p>
<p>Еще одно небольшое следствие состоит в том, что в случае с делегированием, решение по объему делегируемого функционала принимает класс-агрегатор, в случае с примесями – сама примесь.</p>
<p>3.       Примесь автоматически имеет доступ ко всем членам класса-агрегатора и может им произвольно манипулировать, при условии, что знает, как он устроен.  В случае делегирования этого доступа нет.</p>
<p>Доступ к членам класса-агрегатора из примеси дает нам возможность изменять внутреннее состояние объекта. Это удобно, но добавляет в примесь необходимость знания внутреннего устройства класса-агрегатора. С другой стороны, при разработке интерфейса класса-агрегатора с использованием примесей нам не нужно планировать уровень видимости членов класса, как это необходимо в случае делегирования, если при расширении поведения нужно манипулировать состоянием класса-агрегатора. Впрочем, у примеси легко отнять данную привилегию.</p>
<p>Теперь давайте посмотрим, как одни и те же возможности можно реализовать примесями и делегированием.</p>
<h1>Пример «Поведение в ORM».</h1>
<p>Мы сделали на нашем вымышленном фреймворке небольшой сайт. На этом сайте есть каталог статей. Наш фреймворк содержит ORM, в котором есть модель «статьи». В наш ORM также входят классы, поддерживающие распространенные модели поведения: дерево, версионность, мягко-удаляемость и так далее.</p>
<p>Предположим, что нам нужно сделать каталог статей древовидным в следующей версии нашего фреймворка. Что мы делаем? Мы добавляем модель поведения «дерево» в класс модели «статья». Мы можем выбрать либо примесь, либо делегирование в этом случае. Результаты будут напоминать те примеры, что мы рассматривали в самом начале. Обратите внимание на один момент. В случае использования примеси видимый интерфейс основного класса не изменился совсем, а в случае делегирования он только расширился, но все равно остался совместимым.</p>
<p>В следующей версии фреймворка нам нужно добавить в модель версионность и мягкоудаляемость. Что мы с легкостью и делаем либо подмешивая в модель соответствующие примеси, либо расширяя класс модели с помощью делегирования.</p>
<p>Обратите внимание, что в этом примере возможно использование как примесей, так и делегирования.</p>
<p>Теперь давайте рассмотрим аналогичный пример, только теперь в модель функционал добавляем не мы, а плагины к нашему фреймворку, которые пишутся сторонними разработчиками. От нас требуется только предоставить удобный API, чтобы для интеграции плагина в систему не пришлось переписывать большую ее часть.</p>
<p>Плагин хочет добавить функционал в нашу модель. В случае если плагин построен на примеси он просто регистрирует себя для класса модели. А в случае с делегированием мы могли бы, например, хранить имя класса модели в реестре. Тогда плагин добавления древовидности статьям наследует себя от базового класса модели фреймворка, добавляет функционал и заменяет в реестре моделей имя оригинального класса модели на свое. Либо разработчик плагина предоставляет пользователю системы инструкцию по дописыванию класса модели нужным плагину образом (как вы понимаете, для обычных пользователей это менее предпочтительно). Схема немного усложнилась, но пока это терпимо. И наш фреймворк в обоих случаях продолжит работу, поскольку интерфейс класса модели остался совместимым (внимательные читатели наверняка заметили, что существуют и другие решения для расширения функционала класса модели в нашем проекте. Но их рассмотрение станет темой отдельной статьи).</p>
<p>Но авторы плагинов «версионности» и «мягкоудаляемости» хотят, чтобы эти возможности добавлялись в модель статей не «вместо», а «вместе»! Как это можно реализовать? В случае примесей все по-прежнему просто. Мы подмешиваем в класс модели новый и новый фунционал. А с делегированием? По-видимому, тут схема начинает усложняться. Нам нужно, чтобы классы плагинов наследовались друг от друга, а класс первого плагина – от оригинального класса модели. С определенными затратами такой функционал тоже можно добавить. Что для вас предпочтительнее, должны решить вы сами.</p>
<p>В данном случае выбор следует делать исходя из ваших профессиональных навыков и предпочтений. В серьезном, не учебном проекте следует использовать только ту технику, которая вам наиболее знакома и привычна в профессиональном плане (или ту, которая наиболее знакома и привычна большинству программистов, которые в будущем будут работать над проектом). Если вы пренебрежете данной рекомендацией и выберете то, что вам в настоящий момент кажется просто более удобным, позаботьтесь о том, чтобы использование незнакомого подхода не стало критичным для здоровья кода проекта. Если же вы считаете, что одинаково хорошо владеете использованием и примесей и делегирования, соображения по выбору того и другого приведены выше. Решайте, что вам больше нравится.</p>
<p>При выходе контроля над кодом из ваших рук, очевидно, вам придется перейти к примесям, либо искать другие пути решения проблемы, поскольку очевидно, что приведенное решение с использованием делегирования будет выглядеть сложновато.</p>
<p>Я сожалению, что, возможно, разочаровал любителей техно-клубнички, которые, скорее всего, ожидали увидеть меня в числе яростных сторонников одного из подходов, защищающим родной бастион. Мне жаль, если это так.</p>
<p>Помните, что любой выбор в жизни всегда нужно делать, руководствуясь двумя вещами: максимальным количеством информации, которое вы можете собрать по данному вопросу и собственной головой. Я постарался предоставить первое. Второе – за вами. С опасением относитесь к ссылкам на авторитеты. Руководствуйтесь изречением Спинозы: «ссылки на авторитет – не есть довод». Все и всегда проверяйте.</p>
<p>P.S. Если данная статья показалась вам интересной, предложите в комментариях тему для следующей.</p>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/sIR6RLT0wNI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_154/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%81%d0%b8-vs-%d0%b4%d0%b5%d0%bb%d0%b5%d0%b3%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%b5%d0%b8%d0%bc%d1%83%d1%89%d0%b5%d1%81%d1%82%d0%b2%d0%b0/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_154/%d0%bf%d1%80%d0%b8%d0%bc%d0%b5%d1%81%d0%b8-vs-%d0%b4%d0%b5%d0%bb%d0%b5%d0%b3%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%b5%d0%b8%d0%bc%d1%83%d1%89%d0%b5%d1%81%d1%82%d0%b2%d0%b0/</feedburner:origLink></item>
		<item>
		<title>ООП практикум в PHP5: Анализ ошибок, преимуществ и недостатков двух реализаций примесей в PHP</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/onOL7WzPnQc/</link>
		<comments>http://ru.fractalizer.ru/frpost_148/%d0%be%d0%be%d0%bf-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d1%83%d0%bc-%d0%b2-php5-%d0%b0%d0%bd%d0%b0%d0%bb%d0%b8%d0%b7-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d0%bf%d1%80%d0%b5%d0%b8%d0%bc%d1%83/#comments</comments>
		<pubDate>Fri, 12 Nov 2010 07:40:55 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=148</guid>
		<description><![CDATA[После выхода моей статьи о примесях мы продолжали дискуссии и в комментариях к статье и в личных сообщениях. Сегодня увидел в моем блоге комментарий от читателя, который попросил объяснить, в чем я вижу преимущество своей реализации перед реализацией Леонида Шлейхера. Я собирался было ответить в комментарии к посту своем же сайте, но неожиданно оказалось, что [...]]]></description>
			<content:encoded><![CDATA[<p>После выхода <a href="http://ru.fractalizer.ru/frpost_128/%D0%BE%D0%BE%D0%BF-%D0%BF%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D1%83%D0%BC-php5-%D1%8D%D0%BC%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D1%8F-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%81%D0%B5%D0%B9-mixin-%D0%B2-%D1%8F/">моей статьи о примесях</a> мы продолжали дискуссии и в комментариях к статье и в личных сообщениях. Сегодня увидел в моем блоге комментарий от читателя, который попросил объяснить, в чем я вижу преимущество своей реализации перед реализацией <a href="http://schleicher.ru/blog/183.html">Леонида Шлейхера</a>.</p>
<p>Я собирался было ответить в комментарии к посту своем же сайте, но неожиданно оказалось, что вопрос довольно интересен. Вернее, не сам вопрос, а анализ, который я провел, подготавливая ответ.</p>
<p><span id="more-148"></span>Я сомневаюсь, чтобы кто-то из нас двоих с Леонидом ставил себе задачу универсальной реализации примесей в проектах любой величины. Обе наши реализации, мне кажется, не выходят далеко за уровень домашних фреймворков и представляют собой скорее концепт реализации примеси без eval(), нежели рабочий инструмент. Но, тем не менее, давайте попробуем погрузиться в сравнение.</p>
<p>Мой вариант более производителен за счет использования так называемого реестра для хранения кэшированной информации о примесях. Но использованный мной вариант кэширования эффективен только при многократном обращении к методу / свойству примеси.  Если доступ одноразовый – в моем варианте он, скорее всего, будет прилично более медленным, чем у Леонида, потому что нужно сначала построить кэш. Для ликвидации этого недостатка в моем случае следует перейти от модели статического класса реестра к модели реестра-синглтона, инициализируемому через абстрактную фабрику или реализовать стандартный паттерн «реестр» уровня фреймворка. Это позволит варьировать реализацию реестра в зависимости от требований проекта и, например, заменить кэширование прямыми вызовами для ускорения одноразовых обращений к методам.</p>
<p>Как заметил мой читатель, реализация кэширования усложнила код и сделала его более подверженным ошибкам (это не пустые слова, я не один баг выловил, пока отлаживал, а тесты лень писать было) и несколько более сложным для понимания, конечно.</p>
<p>И я, и Леонид, похоже, допустили одну и ту же ошибку в реализации, связанную со сборкой мусора. Обратите внимание на циклические ссылки: в классе-агрегаторе хранятся ссылки на экземпляры классов примесей, и в примесях, в свою очередь, хранятся ссылки на экземпляры классов агрегаторов. В PHP версиях младше 5.3 произойдет утечка памяти, потому что сборщик мусора не умеет работать с циклическими ссылками. В 5.3 можно активировать специальный сборщик мусора для этой цели, но он замедляет работу скрипта в целом, так что это нежелательно. Что в этом плохого? Все зависит от того, для чего и как используются примеси. Если объектов-агрегаторов со своими примесями много, они большие и сложные, часто создаются / разрушаются – все будет очень плохо. Если же примеси подмешиваются к агрегаторам, существующим на всей протяженности жизни скрипта, ничего страшного не будет, так как вся занимаемая скриптом память при его завершении будет освобождена принудительно.</p>
<p>Как исправить эту ошибку? В обеих реализациях сделать это довольно просто, воспользовавшись не слишком часто используемой возможностью PHP – деструктором. Нужно добавить деструктор, принудительно обнуляющий ссылку на владеющий класс, в примесь и деструктор в класс-агрегатор, очищающий список примесей данного класса.</p>
<p>Сейчас вот оказалось, что вариант Леонида вообще не компилируется, потому что магический метод __call() в классе Caller не может быть защищенным. Исправил, заработало. В 5.3 варианте из <a href="http://schleicher.ru/blog/183.comments.html">комментария</a> этой ошибки уже нет.</p>
<p>Леонид реализовал в примеси магические методы, чтобы примесь могла обращаться к членам класса-агрегатора как к своим собственным. Я этого сделать не догадался. Впрочем, я подумаю, реализовывать ли эту идею у себя. Пока что мне не очень нравится граф вызовов, который при этом получается, и некоторая расплывчатость области видимости.</p>
<p>Вариант Леонида статический. Код почему-то написан так, что примеси нужно создавать в конструкторе агрегатора, что, в общем-то, слегка противоречит концепции примесей.  В моем варианте примеси к классам подсоединяются динамически, причем для этого не требуется даже загрузка самих классов (ни агрегаторов, ни примесей). То есть, все примеси можно подсоединять в одном месте проекта без ущерба для производительности. В этом есть и свой недостаток: ошибку в имени класса-агрегатора или примеси сложнее отследить. Ведь классы не загружаются, пока не начнут реально использоваться.</p>
<p>Примеси в варианте Леонида реализуются исключительно наследованием. В моем варианте композиция, наряду с наследованием, тоже доступна. Иногда это полезно, если класс невозможно унаследовать от класса-агрегатора.</p>
<p>За счет «подсоединения» в моем варианте примеси можно подсоединять к классам прямо в процессе исполнения основного кода. То есть, если потерять осторожность, может оказаться так, что в один экземпляр класса данная примесь подмешана, а в другой нет. Мы получили чрезмерную гибкость, которую легко устранить, если это необходимо. Кстати,  это можно сделать, исследуя кэш (реестр).</p>
<p>Вариант Леонида реализует не все магические методы у класса-агрегатора (основной акцент сделан на методах), но это легко исправить.</p>
<p>Оба наших варианта на ситуацию с наличием методов примесей с одинаковыми именами реагируют одинаково: будет вызван метод примеси, зарегистрированной первой. На мой взгляд, тоже не совсем корректный вариант. Однако реализация проверки несколько затратна, особенно в случаях, где от примесей требуется быстродействие: ведь проверить наличие дубликатов без загрузки всех классов примесей для данного агрегатора невозможно. Так что, похоже, мы оба решили с этим смириться.</p>
<p>Леонид забыл добавить проверку на ошибки в ситуации, если в примеси будет сделана попытка через себя вызывать метод агрегатора с несуществующим именем. Это плоховато, поскольку в получившейся реализации не возникает ошибочной ситуации и просто ничего не происходит. А может, так предполагалось? В общем, с моей точки зрения это плохо. Лучше получить ошибку. Впрочем, все легко исправляется.</p>
<p>У Леонида возникает еще одна любопытная ситуация, если в примеси определить защищенный или приватный метод с каким-либо именем, а затем попытаться вызвать метод с этим именем на агрегаторе. Обратите внимание на граф вызовов. У агрегатора вызывается __call(), идет поиск метода с заданным именем среди методов примесей с помощью method_exists(). Совпадение обнаруживается, поскольку method_exists() для скрытых и защищенных членов тоже возвращает true. Производится попытка вызова этого метода уже на экземпляре примеси. Поскольку метод все же защищенный и из данной области видимости недоступен, вызывается уже магический метод примеси __call(), который, в свою очередь, вызывает псевдо-магический метод агрегатора __access_call, в который Леонид забыл добавить проверку ошибок. Поскольку проверка ошибок отсутствует, ничего не происходит и никакой ошибки мы не получаем, хотя мне лично хотелось бы. Да и сам граф сложноват получился, на мой взгляд, для реализации примесей на 80 строк… Ошибку исправить, конечно, легко.</p>
<p>В комментарии к статье автор упоминает, что «каждый родительский класс должен создать экземпляры всех своих примесей. Впрочем, он может использовать общие для всех экземпляры, получая их с помощью Registry». Получать готовые экземпляры в этом случае удобно через реестр только, если примеси не имеют собственного состояния. В противном случае идея теряет смысл и нужно искать другой способ.</p>
<p>В комментариях на сайте автор упоминает, что добавил поддержку статических методов примесей. В моем варианте для этого требуется сделать для статических методов дополнительный кэш в реестре. Чуть больше телодвижений. Пока воздержусь, наверное.</p>
<p>Нужно обратить внимание, что в реализации Леонида присутствуют псевдомагические методы агрегатора, фактически открывающие доступ к скрытым и защищенным членам класса в публичном интерфейсе. Плохо это или хорошо – зависит от проекта. В принципе, нормальные программисты и  так должны понимать, что методы, начинающиеся с двух подчеркиваний делают системные, внутренние вещи и должны вызываться только внутренностями фреймворка. Так что, особой проблемы это не несет.</p>
<p>Я активно пользуюсь тайпхинтингом в PHP для дополнительных проверок. У Леонида не заметил, но это пустяки.</p>
<p>В PHP 5.3 варианте <a href="http://schleicher.ru/blog/183.comments.html">на странице комментариев</a> добавлено статическое свойство со списком примесей для статических вызовов. Думаю, выглядит несколько оторвано от контекста, так как на первый взгляд кажется, что примеси делятся на статические и экземплярные, что не соответствует действительности.</p>
<p>Кстати, вариант автора уже работает в проекте, а мой еще нет. Лежит себе на компе без дела…</p>
<p>Из не относящегося к делу, могу отметить, когда на сайте читаешь код, хотелось бы видеть если уж не выделение синтаксиса цветом, то хотя бы, чтобы отступы были нормальные. Код Леонида для анализа пришлось в Zend Studio форматировать J. Приношу свои извинения, если код на сайте не предназначался для анализа посторонними. Меня оправдывает разве что то, что все же он получен из открытых источников.</p>
<p>На сайте Леонида в комментариях также был задан вопрос о преимуществах примесей перед обычным делегированием, но это уже тема для моей следующей статьи, которая не заставит себя долго ждать. Объем не позволяет изложить мою точку зрения на этот вопрос тут.</p>
<p>Огромная просьба в комментариях не сравнивать две реализации с точки зрения «плохая/хорошая». Уважайте себя. Говоря о достоинствах и недостатках, воздержитесь от демагогии. Факты, факты и еще раз факты. Троллей, обожающих кричать «УГ» и «КГ/АМ» даже не разобравшись в вопросе, просят <a href="http://lleo.aha.ru/na/">пройти на посадку</a>, поезд скоро отправится.</p>
<p>Спасибо за внимание.</p>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/onOL7WzPnQc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_148/%d0%be%d0%be%d0%bf-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d1%83%d0%bc-%d0%b2-php5-%d0%b0%d0%bd%d0%b0%d0%bb%d0%b8%d0%b7-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d0%bf%d1%80%d0%b5%d0%b8%d0%bc%d1%83/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_148/%d0%be%d0%be%d0%bf-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d1%83%d0%bc-%d0%b2-php5-%d0%b0%d0%bd%d0%b0%d0%bb%d0%b8%d0%b7-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d0%bf%d1%80%d0%b5%d0%b8%d0%bc%d1%83/</feedburner:origLink></item>
		<item>
		<title>Моя статья в журнале ВебАналитикИнфо</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/Cmvl3iinG7A/</link>
		<comments>http://ru.fractalizer.ru/frpost_146/%d0%bc%d0%be%d1%8f-%d1%81%d1%82%d0%b0%d1%82%d1%8c%d1%8f-%d0%b2-%d0%b6%d1%83%d1%80%d0%bd%d0%b0%d0%bb%d0%b5-%d0%b2%d0%b5%d0%b1%d0%b0%d0%bd%d0%b0%d0%bb%d0%b8%d1%82%d0%b8%d0%ba%d0%b8%d0%bd%d1%84%d0%be/#comments</comments>
		<pubDate>Thu, 11 Nov 2010 13:28:20 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[Без рубрики]]></category>
		<category><![CDATA[Новости]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=146</guid>
		<description><![CDATA[С удовольствием сообщаю, что в ноябрьском номере ВебАналитикИнфо вышла моя статья Архитектура XenForo.]]></description>
			<content:encoded><![CDATA[<p>С удовольствием сообщаю, что в <a href="http://www.web-analitik.info/magazine/download/268/" target="_blank">ноябрьском номере ВебАналитикИнфо</a> вышла моя статья Архитектура XenForo.</p>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/Cmvl3iinG7A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_146/%d0%bc%d0%be%d1%8f-%d1%81%d1%82%d0%b0%d1%82%d1%8c%d1%8f-%d0%b2-%d0%b6%d1%83%d1%80%d0%bd%d0%b0%d0%bb%d0%b5-%d0%b2%d0%b5%d0%b1%d0%b0%d0%bd%d0%b0%d0%bb%d0%b8%d1%82%d0%b8%d0%ba%d0%b8%d0%bd%d1%84%d0%be/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_146/%d0%bc%d0%be%d1%8f-%d1%81%d1%82%d0%b0%d1%82%d1%8c%d1%8f-%d0%b2-%d0%b6%d1%83%d1%80%d0%bd%d0%b0%d0%bb%d0%b5-%d0%b2%d0%b5%d0%b1%d0%b0%d0%bd%d0%b0%d0%bb%d0%b8%d1%82%d0%b8%d0%ba%d0%b8%d0%bd%d1%84%d0%be/</feedburner:origLink></item>
		<item>
		<title>Краткий очерк истории объектно-ориентированного программирования</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/Pw9Cfywjypw/</link>
		<comments>http://ru.fractalizer.ru/frpost_142/%d0%ba%d1%80%d0%b0%d1%82%d0%ba%d0%b8%d0%b9-%d0%be%d1%87%d0%b5%d1%80%d0%ba-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d0%b8-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%bd%d0%be-%d0%be%d1%80%d0%b8%d0%b5%d0%bd/#comments</comments>
		<pubDate>Thu, 11 Nov 2010 07:43:46 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[Общие вопросы программирования]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=142</guid>
		<description><![CDATA[Эта статья была написана под влиянием впечатлений, полученных автором в ходе одного хабрасрача дискуссии, и представляет небольшую серию переводов материалов из свободных источников об истории объектно-ориентированного программирования, основным из которых является Википедия, плюс абсолютно предвзятые выводы автора из прочитанного материала. Если вам интересно узнать, какой язык в действительности был первым ООП-языком на свете, могут ли [...]]]></description>
			<content:encoded><![CDATA[<p>Эта статья была написана под влиянием впечатлений, полученных автором в ходе <span style="text-decoration: line-through;">одного хабрасрача</span> дискуссии, и представляет небольшую серию переводов материалов из свободных источников об истории объектно-ориентированного программирования, основным из которых является Википедия, плюс абсолютно предвзятые выводы автора из прочитанного материала.</p>
<p>Если вам интересно узнать, какой язык в действительности был первым ООП-языком на свете, могут ли Java и C# называться чистыми ООП-языками, а также проникнуться некоторыми другими деталями, приглашаю вас под кат..</p>
<p><span id="more-142"></span>Сначала перевод об истории ООП из Википедии:</p>
<p>«Термины «объектно-» и «ориентированный» в современном смысле этих слов появились в MIT в конце 1950 начале 1960 годов. В среде специалистов по искусственному интеллекту термин «объект» мог относиться к идентифицированным элементам (атомы Lisp) со свойствами (атрибутами). Алан Кэй позже писал, что понимание внутреннего устройства Лиспа оказало серьезное влияние на его мышление в 1966 г. Другим ранним примером ООП в MIT был <a title="Sketchpad" href="http://en.wikipedia.org/wiki/Sketchpad">Sketchpad</a> созданный <a title="Ivan Sutherland" href="http://en.wikipedia.org/wiki/Ivan_Sutherland">Иваном</a> Сазерлендом в 1960-61. В глоссарии подготовленного в 1963 г. технического отчета, основанного на его диссертации о <a title="Sketchpad" href="http://en.wikipedia.org/wiki/Sketchpad">Sketchpad</a>, Сазерленд определяет понятия «объект» и «экземпляр» с концепцией классов на основе «мастера» или «определения», хотя все эти термины относились к графическому представлению объектов [вкратце, в <a title="Sketchpad" href="http://en.wikipedia.org/wiki/Sketchpad">Sketchpad</a> было основное изображение, на основе которого строились копии. При изменении основного – копии тоже менялись. Прим. пер.].</p>
<p>В ранней MIT-версии ALGOL AED-0 структуры данных («плексы» на диалекте Алгола) напрямую были связаны с процедурами, которые впоследствии были названы сообщениями, методами или функциями-членами.</p>
<p>Объекты, как формализованный концепт появились в программировании в 1960-х в <a title="Simula" href="http://en.wikipedia.org/wiki/Simula">Simula</a> 67, модернизированной версии Simula I, языка программирования, ориентированного на дискретно-событийное моделирование. Авторы Simula &#8211; Оле-Йохан Даль и Кристен Нюгорд из Норвежского компьютерного центра в Осло. Simula разрабатывалась под влиянием <a title="SIMSCRIPT" href="http://en.wikipedia.org/wiki/SIMSCRIPT">SIMSCRIPT</a> и предложенной Чарльзом Хоаром концепцией записей-классов. Simula включала в себя понятие классов и экземпляров (или объектов), а также подклассов, виртуальных методов, сопрограмм и дискретно-событийное моделирование как часть собственной парадигмы программирования. В языке использовался автоматический сборщик мусора, который был изобретен ранее для функционального языка Lisp. Simula использовалась тогда преимущественно для физического моделирования. Идеи Simula оказали серьезное влияние на более поздние языки, такие как Smalltalk, варианты Lisp (<a title="CLOS" href="http://en.wikipedia.org/wiki/CLOS">CLOS</a>), <a title="Object Pascal" href="http://en.wikipedia.org/wiki/Object_Pascal">Object Pascal</a>, и  <a title="C++" href="http://en.wikipedia.org/wiki/C%2B%2B">C++</a>.</p>
<p>Язык <a title="Smalltalk" href="http://en.wikipedia.org/wiki/Smalltalk">Smalltalk</a>, который был изобретен в компании <a title="Xerox PARC" href="http://en.wikipedia.org/wiki/Xerox_PARC">Xerox PARC</a> Аланом Кэем (<a title="Alan Kay" href="http://en.wikipedia.org/wiki/Alan_Kay">Alan Kay</a>) и некоторыми другими учеными, фактически навязывал использование «объектов» и «сообщений» как базиса для вычислений. Создателей Smalltalk вдохновляли некоторые идеи Simula, но Smalltalk разрабатывался как полностью динамичная система, в которой классы могут создаваться и изменяться динамически, а не только статически как в Simula. Smalltalk и ООП с его помощью были представлены широкой аудитории в журнале <a title="Byte (magazine)" href="http://en.wikipedia.org/wiki/Byte_%28magazine%29"><em>Byte </em><em>magazine</em></a> в августе 1981.</p>
<p>В 1970-х Smalltalk Кэя сподвиг сообщество Lisp внедрить в язык объектно-ориентированные техники, которые были представлены разработчикам с помощью <a title="Lisp machine" href="http://en.wikipedia.org/wiki/Lisp_machine">Lisp машины.</a><br />
Эксперименты с различными расширениями Lisp в конечном итоге привели к созданию <a title="Common Lisp Object System" href="http://en.wikipedia.org/wiki/Common_Lisp_Object_System">Common Lisp Object System</a> (CLOS, части первого стандартизованного объектно-ориентированного языка, <a title="ANSI" href="http://en.wikipedia.org/wiki/ANSI">ANSI</a> <a title="Common Lisp" href="http://en.wikipedia.org/wiki/Common_Lisp">Common Lisp</a>), который органично включал в себя как функциональное, так и объектно-ориентированное программирование и позволял расширять себя с помощью протокола <a title="Meta-object protocol" href="http://en.wikipedia.org/wiki/Meta-object_protocol">Meta-object protocol</a>. В 1980 было несколько попыток дизайна архитектур процессоров, которые включали бы в себя аппаратную поддержку работы с объектами в памяти, но все они были безуспешны. В качестве примеров можно привести <a title="Intel iAPX 432" href="http://en.wikipedia.org/wiki/Intel_iAPX_432">Intel iAPX 432</a> и <a title="Linn Products" href="http://en.wikipedia.org/wiki/Linn_Products">Linn Smart</a> <a title="Rekursiv" href="http://en.wikipedia.org/wiki/Rekursiv">Rekursiv</a>.</p>
<p>Объектно-ориентированное программирование развилось в доминирующую методологию программирования в начале и середине 1990 годов, когда стали широко доступны поддерживающие ее языки программирования, такие как Visual FoxPro 3.0, <a title="C++" href="http://en.wikipedia.org/wiki/C%2B%2B">C++</a>, и Delphi. Доминирование этой системы поддерживалось ростом популярности графических интерфейсов пользователя, которые основывались на техниках ООП. Пример тесной связи между динамической библиотекой GUI и объектно-ориентированного языка программирования можно найти посмотрев на фреймворк <a title="Cocoa (software)" href="http://en.wikipedia.org/wiki/Cocoa_%28software%29">Cocoa</a> на <a title="Mac OS X" href="http://en.wikipedia.org/wiki/Mac_OS_X">Mac OS X</a>, который был написан на <a title="Objective-C" href="http://en.wikipedia.org/wiki/Objective-C">Objective-C</a>, объектно-ориентированом расширении к С, основанном на Smalltalk с поддержкой динамических сообщений. Инструментарии ООП повлияли на популярность <a title="Event-driven programming" href="http://en.wikipedia.org/wiki/Event-driven_programming">событийно-ориентированного</a> программирования (хотя, эта концепция не ограничивается одним ООП). Некоторые даже думали, что кажущаяся или реальная связь с графическими интерфейсами – это то, что вынесло ООП на передний план технологий.</p>
<p>В <a title="ETH Z?rich" href="http://en.wikipedia.org/wiki/ETH_Z%C3%BCrich">ETH Z?rich</a>, <a title="Niklaus Wirth" href="http://en.wikipedia.org/wiki/Niklaus_Wirth">Никлаус</a> Вирт и его коллеги тоже исследовали такие предметы, как абстрация данных и модульное программирование, хотя эти подходы широко использовались и в 60-х и ранее. <a title="Modula-2" href="http://en.wikipedia.org/wiki/Modula-2">Modula-2</a> вышедшая в 1978 включала оба эти подхода, а ее последователь <a title="Oberon (programming language)" href="http://en.wikipedia.org/wiki/Oberon_%28programming_language%29">Oberon</a> имел собственный подход к объктно-ориентированности, классам и прочему, непохожий на подход Smalltalk и совсем не похожий на подход C++.</p>
<p>Возможности ООП добавлялись во многие языки того времени, включая <a title="Ada (programming language)" href="http://en.wikipedia.org/wiki/Ada_%28programming_language%29">Ada</a>, <a title="BASIC" href="http://en.wikipedia.org/wiki/BASIC">BASIC</a>, <a title="Fortran" href="http://en.wikipedia.org/wiki/Fortran">Fortran</a>, <a title="Pascal (programming language)" href="http://en.wikipedia.org/wiki/Pascal_%28programming_language%29">Pascal</a> и другие. Их добавление в языки, изначально не разрабатывавшиеся для поддержки ООП часто приводило к проблемам с совместимостью и поддержкой кода.</p>
<p>Позднее стали появляться языки, поддерживающие как объектно-ориентированный подход, так и процедурный вроде  <a title="Python (programming language)" href="http://en.wikipedia.org/wiki/Python_%28programming_language%29">Python</a> и  <a title="Ruby programming language" href="http://en.wikipedia.org/wiki/Ruby_programming_language">Ruby</a>. Пожалуй, самыми коммерчески успешными объектно-ориентированными языками можно назвать <a title="Visual Basic.NET" href="http://en.wikipedia.org/wiki/Visual_Basic.NET">Visual Basic.NET</a>, <a title="C Sharp (programming language)" href="http://en.wikipedia.org/wiki/C_Sharp_%28programming_language%29">C#</a> и <a title="Java (programming language)" href="http://en.wikipedia.org/wiki/Java_%28programming_language%29">Java</a>. И <a title=".NET Framework" href="http://en.wikipedia.org/wiki/.NET_Framework">.NET</a> и <a title="Java (programming language)" href="http://en.wikipedia.org/wiki/Java_%28programming_language%29">Java</a> демонстрируют превосходство ООП.»</p>
<p>Теперь я бы хотел привести перевод небольшой части статьи «Как начиналось объектно-ориентированное программирование» за авторством Оле-Йохана Даля и Кристена Нюгорда.</p>
<p>«SIMULA I (1962-65) и Simula 67 (1967) &#8211; два первых объектно-ориентированных языка программирования. Simula 67 включала в себя большую часть концепций объектно-ориентированного программирования: классы и объекты, подклассы (наследование), виртуальные функции, безопасные ссылки и механизмы, позволяющие внести в программу коллекцию программных структур, описанных общим заголовком класса (префиксные блоки).</p>
<p>Алан Кэй из Xerox PARC использовал Simula как платформу для его разработки Smalltalk (первых версий языка в 1970-х), расширяя объектно-ориентированное программирование с помощью интеграции пользовательского интерфейса и интерактивного исполнения. Бьерн Страусструпп начал разработку C++ (в 1980-х) by привнеся основные концепции Simula в С.»</p>
<p>Теперь небольшое обобщение и заключение.</p>
<p>Как видите, получается, что первым ООП языком была Simula. Но первым «чистым» ООП языком был именно Smalltalk. «Чистым» иногда называют ООП язык, все типы которого являются или могут быть прозрачно представленными классами. В этом смысле Java <strong>чистым</strong> ООП языком стала только в версии 5, когда появилась возможность Autoboxing. C#, если я правильно понимаю, был чистым ООП языком с самого начала. Предлагаю в комментариях поломать копья на темы вроде «А в C# есть неуправляемые указатели, которые не могут быть представлены объектами», «А вообще чистым ООП языком может считаться только Smalltalk, в котором объектами представлено все, вплоть до блоков самой программы, ну или, в крайнем случае, Ruby» и «Чистый – значит, медленный. Ишь чего удумали, int объектом представлять!»</p>
<p>Некоторое время назад <a href="http://tenshi.habrahabr.ru/">один странный хабраюзер</a> заявил в одном из комментариев, что ООП изобрел Алан Кэй, что <a href="http://habrahabr.ru/blogs/php/107682/#comment_3400271">в чистом ООП нет наследования</a>, <a href="http://habrahabr.ru/blogs/php/107682/#comment_3402521">что Java и C# по мнению автора термина «ООП» Алана Кэя ООП языками не являются и что Гослинг с Липпертом имеют… гм… проблемы</a>, поскольку совершенно неверно считают, что изобретенные ими языки являются нормальными объектно-ориентированными.</p>
<p>От такой чудовищной чуши у меня немедленно опухли все мои брови и я полез в гугл за аргументами, намереваясь вынырнуть оттуда через десять минут с кучей фактов. Оказывается, подобные опасные заблуждения все же разделяются, пусть и меньшинством читателей. Поэтому я хотел бы привести свою точку зрения на этот счет.</p>
<p>Объектно-ориентированное программирование – парадигма, научный подход к программированию, который разрабатывался не в вакууме, а большой группой ученых. Вклад  Кэя в ООП неоценим, но говорить, что ООП – целиком и полностью его изобретение будет несправедливо по отношению ко многим другим ученым, работавшим как вместе с ним, так и отдельно. Кэй действительно когда-то <a href="http://www.purl.org/stefan_ram/pub/doc_kay_oop_en">говорил</a>, “I didn&#8217;t like the way Simula I or Simula 67 did inheritance (though I thought Nygaard and Dahl were just tremendous thinkers and designers). So I decided to leave out inheritance as a built-in feature until I understood it better.” Как вы понимаете, монополия на изобретение ООП им не заявлялась.</p>
<p>Говорить, что в ООП нет наследования (и всяких прочих современных штучек) и что те, кто его туда привнес <strong>извратили</strong> смысл и суть ООП, это все равно, что говорить, что геометрия Лобачевского извратила геометрию, изобретенную Евклидом и ее срочно нужно переименовать в «шарометрию» или «гиперболометрию», чтобы грязные руки неофитов не смели касаться святого. Геометрия Римана – вообще тогда от сатаны, а бозонную струнную теорию нельзя преподавать в университетах потому, что это не то, что описывал Габриэле Венециано и его коллеги.</p>
<p>Если вы не согласны, приглашаю продолжить дискуссию в комментах.</p>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/Pw9Cfywjypw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_142/%d0%ba%d1%80%d0%b0%d1%82%d0%ba%d0%b8%d0%b9-%d0%be%d1%87%d0%b5%d1%80%d0%ba-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d0%b8-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%bd%d0%be-%d0%be%d1%80%d0%b8%d0%b5%d0%bd/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_142/%d0%ba%d1%80%d0%b0%d1%82%d0%ba%d0%b8%d0%b9-%d0%be%d1%87%d0%b5%d1%80%d0%ba-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d0%b8-%d0%be%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d0%bd%d0%be-%d0%be%d1%80%d0%b8%d0%b5%d0%bd/</feedburner:origLink></item>
		<item>
		<title>Автоинкрементные первичные ключи (суррогатные ключи) = зло?</title>
		<link>http://feedproxy.google.com/~r/FractalizersWebsiteRU/~3/mzlvHQ8FKew/</link>
		<comments>http://ru.fractalizer.ru/frpost_136/%d0%b0%d0%b2%d1%82%d0%be%d0%b8%d0%bd%d0%ba%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d1%82%d0%bd%d1%8b%d0%b5-%d0%bf%d0%b5%d1%80%d0%b2%d0%b8%d1%87%d0%bd%d1%8b%d0%b5-%d0%ba%d0%bb%d1%8e%d1%87%d0%b8-%d1%81%d1%83/#comments</comments>
		<pubDate>Tue, 09 Nov 2010 20:19:27 +0000</pubDate>
		<dc:creator>FractalizeR</dc:creator>
				<category><![CDATA[SQL и базы данных]]></category>
		<category><![CDATA[Статьи]]></category>

		<guid isPermaLink="false">http://ru.fractalizer.ru/?p=136</guid>
		<description><![CDATA[В этой статье я приведу взгляд (отрицательный по большей части) Джоша Беркуса, CEO компании PostgreSQL Experts Inc. на использование суррогатных ключей для таблиц базы данных, тех самых INT NOT NULL AUTO_INCREMENT PRIMARY KEY, к которым мы привыкли. Фактически, это будет вольный, сильно сокращенный перевод его статьи на ittoolbox. За статьей последует разбор моих собственных ошибок [...]]]></description>
			<content:encoded><![CDATA[<p>В этой статье я приведу взгляд (отрицательный по большей части) Джоша Беркуса, CEO компании PostgreSQL Experts Inc. на использование суррогатных ключей для таблиц базы данных, тех самых INT NOT NULL AUTO_INCREMENT PRIMARY KEY, к которым мы привыкли. Фактически, это будет вольный, сильно сокращенный перевод его статьи на ittoolbox.</p>
<p>За статьей последует разбор моих собственных ошибок по этой теме, допущенных в одном старом проекте. Я был молод и глуп, но это меня не извиняет.</p>
<p>Честно говоря, прочитав эту статью и не заметив, кто автор, я подумал, что он все же преувеличивает и вообще, я без него как-нибудь разберусь, где и какие ключи мне использовать. Потом я еще немного подумал и полез за дампом структуры базы моего старого проекта. Было интересно.</p>
<p>Если вы опытный DBA, наверное, вам стоит пройти мимо, чтобы не расстраиваться.</p>
<p>Но обо всем по порядку. Сначала ОЧЕНЬ сокращенный перевод:</p>
<p><span id="more-136"></span>«Суррогатные числовые ключи попали в стандарт SQL89 для сохранения со старыми приложениями, которым требовались номера строк. Впоследствии в разговоре с Джо Селко, Кодд сказал, что жалеет, что допустил это.</p>
<p>Неопытные разработчики, не понимая, что использование суррогатные ключей является прагматичным компромиссом с соображениями производительности, используют их везде. Даже авторы книг по базам данных советуют обязательно создавать их во всех таблицах в любом случае.</p>
<p>В теории реляционных баз данных нет понятия первичных ключей. Все ключи базы данных имеют одинаковую значимость. Понятие первичного ключа базируется на представлении, что один и только один ключ определяет  порядок кортежей на диске, а реляционная теория говорит нам о том, что как раз это мы должны игнорировать в логической модели наших данных. Так что, первичные ключи вообще – это нарушение реляционной теории.</p>
<p>Я не говорю о том, что суррогатные ключи нельзя использовать вообще, я говорю о том, что нельзя злоупотреблять их использованием.</p>
<p>Какие причины могут побудить нас использовать суррогатные ключи?</p>
<p><strong>Компромисс с многоколоночными ключами.</strong> Обычно, довольно убедительна. Синтаксис SQL запросов с использованием многоколоночных ключей и механизм соединений в настоящее время оставляет желать много лучшего, как и производительность запросов такого рода. Как только эти проблемы будут решены, данная причина отпадет.</p>
<p><strong>У данных нет реального ключа</strong>. Очень плохая причина. Ее появление иллюстрирует как плохой дизайн базы данных в целом, таки  и то, что разработчик на самом деле не понимает данных, с которыми работает.</p>
<p><strong>Внешние требования</strong>. Обычно убедительна. Как правило, среды разработки и инструменты для работы с базами данных поддерживают только суррогатные ключи. И если вы считаете, что данный инструмент незаменим в проблеме, которую вы решаете, что ж…</p>
<p><strong>Согласованность данных</strong>. Обычно убедительна. Но только в том случае, если вы действительно скрупулезно следуете плану и весь ваш дизайн тщательно спланирован.</p>
<p><strong>Следование </strong><strong>SQL стандарту и принципам дизайна</strong>. Очень плохая причина. Она полностью основана на невежестве. Обычно, ей следуют потому, что где-то услышали, как кто-то прочитал в блоге кого-то, кто учится в УНИВЕРСИТЕТЕ, что использование суррогатных ключей – это стандарт в индустрии. Имейте ввиду, что ни современные стандарты SQL, ни сама реляционная теория не содержит даже упоминания о суррогатных ключах.</p>
<p><strong>Возможность легкого изменения</strong>. Неясно. Действительно, некоторые СУБД не умеют выполнять ON UPDATE CASCADE или делают это слишком неэффективно (кстати, подумайте об этом как о причине смены СУБД). И в этом случае, данная причина может оказаться весомой. Однако иногда разработчики говорят о том, что ключи [первичные] для записи меняться не должны и должны оставаться одинаковыми на всей протяженности жизненного цикла записи. Имейте ввиду, что это утверждение яйца выеденного не стоит и уж, разумеется, полностью отсутствует в реляционной теории.</p>
<p><strong>Производительность</strong>. Обычно плохая причина. Да, действительно, могут возникать ситуации, в которых использование естественных ключей сильно замедляет работу системы по сравнению с суррогатными. Но в 80% случаев за этим утверждением не стоят реальные тесты и подобное утверждение остается безосновательным. Предварительная оптимизация – корень многих бед в дизайне баз данных.</p>
<p>Для баз данных мега-объема результирующий размер таблицы также может иметь значение. Но для этого база должна быть уж очень большой.</p>
<p>Производительность соединений или сортировки также имеет значение на большом количестве данных, в зависимости от типа первичного ключа и числа его компонентов. Однако мой опыт показывает, что когда называют эту причину, за ней очень редко стоят реальные расчеты или замеры производительности. Например, http://www.bricolage.cc использует 14-байтовые числовые первичные ключи для своих таблиц много лет. Однако и в этом случае, после появления пользователя с трехмиллионной записью в истории, когда встал вопрос об изменении первичных ключей ради производительности, эта проблема была решена переписыванием запросов. Было достигнуто примерно 10-кратное увеличение производительности.</p>
<p>Обратите внимание, что проблемы причиняет не использование суррогатных ключей, а злоупотребление ими».</p>
<p>Конец моего ОЧЕНЬ СОКРАЩЕННОГО перевода. Оригинал тут (Primary Keyvil называется): <a href="http://it.toolbox.com/home/search.aspx?r=%22Primary+kevill%22&amp;community=1&amp;contentType=5">http://it.toolbox.com/home/search.aspx?r=%22Primary+kevill%22&amp;community=1&amp;contentType=5</a></p>
<p>Если я упустил что-то важное в переводе, пожалуйста, скажите мне об этом. Добавлю.</p>
<p>Теперь немного о том, что я сам думаю. Все же статья показалось мне немного драматизирующей проблему. Мне кажется, что суррогатные ключи выбираются все чаще всего именно из-за того, чтобы избежать проблем с производительностью впоследствии и в последнее время все так к ним привыкли, что они насаждаются на уровне самих СУБД. Например, InnoDB, если вы не создадите первичный ключ, просто создаст его сама. Кстати, в случае с InnoDB выбор первичного ключа имеет серьезные последствия с точки зрения производительности, поскольку по нему производится кластеризация (соответственно, выбор естественного ключа может как улучшить, так и ухудшить ситуацию).</p>
<p>Несмотря на то, что статья звучит так, будто суррогатные ключи суть воплощенное зло, автор несколько раз подчеркивает, что проблему несет не их использование, а злоупотребление ими.</p>
<p>Эта статья открыла мне глаза в том плане, что я всегда считал естественным не искать себе особых кандидатов в первичные ключи, а просто создать INT NOT NULL AUTO_INCREMENT PRIMARY KEY поле и сидеть спокойно. Разумеется, я знал о том, что в качестве первичного ключа можно выбрать любой уникальный ключ, но я никогда на этом не акцентировался. Я никогда особо не задумывался о том, что вообще по-настоящему делает данную строку базы данных уникальной и почему это важно. Как выяснилось, зря.</p>
<p>В качестве примера я хочу вам привести свой небольшой старый проект. Там всего несколько таблиц. Вначале я хотел выбрать что-то побольше, но думаю, что это лишнее. Только напрасно отниму у вас время. Пусть каждый сам откроет какой-нибудь свой старый проект и посмотрит на него с точки зрения описанной позиции. Я там на самом деле добавил одну ошибку сейчас справедливости ради. Я бы ее все равно сделал. Меня спасла только случайность.</p>
<p>Проект представляет собой некоторый закрытый торрент-трекер. Я прошу вас не обращать сейчас внимание на проблемы с нормализацией и всякие другие. Если бы я писал его сейчас, может быть, кое-что я бы сделал по-другому. Давайте сосредоточимся на суррогатных ключах.</p>
<div id="wpshdo_9" class="wp-synhighlighter-outer"><div id="wpshdt_9" class="wp-synhighlighter-expanded"><table border="0" width="100%"><tr><td align="left" width="80%"><a name="#codesyntax_9"></a><a id="wpshat_9" class="wp-synhighlighter-title" href="#codesyntax_9"  onClick="javascript:wpsh_toggleBlock(9)" title="Нажмите, чтобы показать или скрыть блок кода">Исходный код</a></td><td align="right"><a href="#codesyntax_9" onClick="javascript:wpsh_code(9)" title="Показать код отдельно"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/code.png" /></a>&nbsp;<a href="#codesyntax_9" onClick="javascript:wpsh_print(9)" title="Напечатать код"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/printer.png" /></a>&nbsp;<a href="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/About.html" target="_blank" title="Показать информацию о плагине"><img border="0" style="border: 0 none" src="http://ru.fractalizer.ru/wp-content/plugins/wp-synhighlight/themes/default/images/info.gif" /></a>&nbsp;</td></tr></table></div><div id="wpshdi_9" class="wp-synhighlighter-inner" style="display: block;"><pre class="sql" style="font-family:monospace;"><span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`log`</span> <span class="br0">&#40;</span>
  <span class="st0">`log_id`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">AUTO_INCREMENT</span><span class="sy0">,</span>
  <span class="st0">`user_id`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`log_ip`</span> varchar<span class="br0">&#40;</span>15<span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`log_error_text`</span> text <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`log_occured_on`</span> datetime <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="kw1">PRIMARY</span> <span class="kw1">KEY</span> <span class="br0">&#40;</span><span class="st0">`log_id`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">KEY</span> <span class="st0">`user_id`</span> <span class="br0">&#40;</span><span class="st0">`user_id`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">KEY</span> <span class="st0">`log_occured_on`</span> <span class="br0">&#40;</span><span class="st0">`log_occured_on`</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span> TYPE<span class="sy0">=</span>InnoDB  <span class="kw1">AUTO_INCREMENT</span><span class="sy0">=</span>2 ;
&nbsp;
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`peer`</span> <span class="br0">&#40;</span>
  <span class="st0">`peer_id`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">PRIMARY</span> <span class="kw1">KEY</span><span class="sy0">,</span>
  <span class="st0">`peer_info_hash`</span> char<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">BINARY</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`torrent_id`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`user_id`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`peer_ip`</span> int<span class="br0">&#40;</span>11<span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`peer_port`</span> smallint<span class="br0">&#40;</span>5<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`peer_update_time`</span> timestamp <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`peer_expire_time`</span> timestamp <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0000-00-00 00:00:00'</span><span class="sy0">,</span>
  <span class="st0">`peer_left`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`peer_uploaded`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`peer_downloaded`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`peer_upload_speed`</span> int<span class="br0">&#40;</span>11<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`peer_download_speed`</span> int<span class="br0">&#40;</span>11<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="kw1">UNIQUE</span> <span class="kw1">KEY</span> hash<span class="br0">&#40;</span><span class="st0">`peer_info_hash`</span><span class="sy0">,</span><span class="st0">`peer_ip`</span><span class="sy0">,</span><span class="st0">`peer_port`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">KEY</span> <span class="st0">`torrent_id`</span> <span class="br0">&#40;</span><span class="st0">`torrent_id`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">KEY</span> <span class="st0">`peer_left`</span> <span class="br0">&#40;</span><span class="st0">`peer_left`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">KEY</span> <span class="st0">`peer_expire_time`</span> <span class="br0">&#40;</span><span class="st0">`peer_expire_time`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">KEY</span> <span class="st0">`peer_update_time`</span> <span class="br0">&#40;</span><span class="st0">`peer_update_time`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">KEY</span> <span class="st0">`user_id`</span> <span class="br0">&#40;</span><span class="st0">`user_id`</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span> TYPE<span class="sy0">=</span>HEAP;
&nbsp;
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`session`</span> <span class="br0">&#40;</span>
  <span class="st0">`session_id`</span> char<span class="br0">&#40;</span>40<span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`user_id`</span> int<span class="br0">&#40;</span>11<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`session_ip`</span> char<span class="br0">&#40;</span>15<span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`session_expire_time`</span> datetime <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="kw1">PRIMARY</span> <span class="kw1">KEY</span> <span class="br0">&#40;</span><span class="st0">`session_id`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">KEY</span> <span class="st0">`user_id`</span> <span class="br0">&#40;</span><span class="st0">`user_id`</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span> TYPE<span class="sy0">=</span>HEAP;
&nbsp;
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`torrent`</span> <span class="br0">&#40;</span>
  <span class="st0">`torrent_id`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">AUTO_INCREMENT</span><span class="sy0">,</span>
  <span class="st0">`torrent_info_hash`</span> char<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">BINARY</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`torrent_downloaded_last_month`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`torrent_downloaded_this_month`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`torrent_file_name`</span> char<span class="br0">&#40;</span>200<span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`torrent_file_path`</span> text <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`torrent_size`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="kw1">PRIMARY</span> <span class="kw1">KEY</span> <span class="br0">&#40;</span><span class="st0">`torrent_id`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">UNIQUE</span> <span class="kw1">KEY</span> <span class="st0">`torrent_info_hash`</span> <span class="br0">&#40;</span><span class="st0">`torrent_info_hash`</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span> TYPE<span class="sy0">=</span>InnoDB  <span class="kw1">AUTO_INCREMENT</span><span class="sy0">=</span>57 ;
&nbsp;
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`user`</span> <span class="br0">&#40;</span>
  <span class="st0">`user_id`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">AUTO_INCREMENT</span><span class="sy0">,</span>
  <span class="st0">`user_serial`</span> char<span class="br0">&#40;</span>40<span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`user_account_status`</span> enum<span class="br0">&#40;</span><span class="st0">'Active'</span><span class="sy0">,</span><span class="st0">'Suspended'</span><span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`user_access_levels`</span> text <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`user_torrent_uid`</span> char<span class="br0">&#40;</span>8<span class="br0">&#41;</span> <span class="kw1">BINARY</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span><span class="sy0">,</span>
  <span class="st0">`user_closure_reason`</span> text<span class="sy0">,</span>
  <span class="st0">`user_closure_reason_public`</span> text<span class="sy0">,</span>
  <span class="st0">`user_uploaded_total`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_uploaded_month`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_uploaded_week`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_uploaded_day`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_downloaded_total`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_downloaded_month`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_downloaded_week`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_downloaded_day`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_webdownloaded_total`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_webdownloaded_month`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_webdownloaded_week`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_webdownloaded_day`</span> bigint<span class="br0">&#40;</span>20<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_torrentfiles_total`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_torrentfiles_month`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_torrentfiles_week`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_torrentfiles_day`</span> int<span class="br0">&#40;</span>10<span class="br0">&#41;</span> <span class="kw1">UNSIGNED</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'0'</span><span class="sy0">,</span>
  <span class="st0">`user_no_traffic_limits`</span> enum<span class="br0">&#40;</span><span class="st0">'Y'</span><span class="sy0">,</span><span class="st0">'N'</span><span class="br0">&#41;</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">DEFAULT</span> <span class="st0">'N'</span><span class="sy0">,</span>
  <span class="kw1">PRIMARY</span> <span class="kw1">KEY</span> <span class="br0">&#40;</span><span class="st0">`user_id`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">UNIQUE</span> <span class="kw1">KEY</span> <span class="st0">`user_serial`</span> <span class="br0">&#40;</span><span class="st0">`user_serial`</span><span class="br0">&#41;</span><span class="sy0">,</span>
  <span class="kw1">UNIQUE</span> <span class="kw1">KEY</span> <span class="st0">`user_torrent_uid`</span> <span class="br0">&#40;</span><span class="st0">`user_torrent_uid`</span><span class="br0">&#41;</span>
<span class="br0">&#41;</span> TYPE<span class="sy0">=</span>InnoDB  PACK_KEYS<span class="sy0">=</span>0 <span class="kw1">AUTO_INCREMENT</span><span class="sy0">=</span>3 ;</pre></div></div>
<p>Первая таблица, о которой я бы хотел поговорить, это таблица логов. Вообще, именно этот случай меня немного ошарашил что ли, поскольку я неожиданно увидел ошибку. Совсем небольшую, не стоящую особого внимания, но, тем не менее, это ошибка, которой я не замечал много-много лет. Совсем не замечал. Отвлекитесь сейчас от текста и вернитесь к структуре этой таблицы. Видите? Я не видел.</p>
<p>В этой таблице хранится простая информация. IP, ID пользователя, дата возникновения события и его текст. Да, конечно, текст можно было заменить кодом и сделать много еще чего, но речь сейчас не об этом. После прочтения статьи, я посмотрел на эту таблицу и подумал, что, вот я создал суррогатный ключ. Но каков реальный ключ данных? Что делает конкретную строку таблицы уникальной?</p>
<p>Ответ очень простой. Комбинация из ID пользователя и времени возникновения события. И вот тут я неожиданно увидел ситуацию с другой стороны. Практически во всех моих старых проектах поле DATETIME используется для хранения времени в логах. Просто потому, что это удобно. Да, я знал, что оно хранится с точностью до секунды и меня это полностью устраивало. Сейчас, когда я начал искать естественные ключи, мне неожиданно пришло в голову, какие последствия это несет. Торрент-трекер, о котором идет речь, нагружен очень сильно и в течение секунды многое может произойти. Фактически, если в логе с этим чертовым суррогатным ключом окажется несколько событий с одним и тем же временем и они произошли друг за другом очень быстро, я смогу сказать, какое из них произошло первым, а какое последним только ориентируясь по автоинкременту суррогатного ключа. Само поле информации о дате, которое создано именно затем, чтобы сообщать такие вещи, мне ничем не поможет. А точно выяснить интервал между событиями я не смогу вообще.</p>
<p>В целом, это, конечно, неважно. Вероятность того, что мне потребуется выяснить интервал между двумя событиями, который в любом случае составляет менее секунды, весьма невелика. Но все свои проекты, и старые и новые, я всегда рассматриваю как учебные. Проект мог быть немного другим, и это могло стать важным.</p>
<p>Я хочу сказать, что рассмотрение проблемы с точки зрения поиска естественного ключа – это взгляд несколько с другой стороны. Попробуйте взглянуть на дизайн вашего проекта таким образом и посмотрите, что обнаружится.</p>
<p>Похоже, что мое объяснение получилось сумбурным. Надеюсь, все же, мне удалось донести до вас мою мысль.</p>
<p>Теперь таблица peer. У нее уже есть уникальный ключ, который просто просится на роль первичного. В таблицу peer производятся многие сотни вставок/удалений в секунду и держать там лишний индекс в виде первичного ключа просто накладно. Вот я его и ликвидировал.</p>
<p>Таблица session. По некоторой причине я не полагался на сессии PHP полностью, а частично реализовал свои. В качестве первичного ключа этой таблицы выступает случайное значение. Мало того, что это просто глупо использовать 40-символьные случайные последовательности, так оно тут вообще не очень нужно. Что выступает в качестве естественного ключа для записей в этой таблице? В этом проекте пользователю не позволялось быть залогиненым с нескольких компов одновременно.  Гм. user_id? Все остальное по отношению к данному значению вторично. Я не буду сейчас анализировать, что вытекает из этого простого утверждения. Много чего вплоть до удаления таблицы сессий и реализации другого механизма. Вариантов тут много.</p>
<p>Перейдем к таблице torrent.</p>
<p>Небольшое отступление для того, чтобы вы представляли себе предмет обсуждения. Торрент-трекер, который я разрабатывал, одновременно являлся и первым сидом для файлов, которые раздавались. В таблице torrent хранилась информация о файлах, которые сидировались. Эти файлы лежали в файловой системе сервера, для них создавались соответствующие .torrent файлы по схеме один файл = один торрент, которые и скачивались пользователями. Каждый торрент имеет так называемый info_hash, который его <strong>уникальным образом идентифицирует</strong>.</p>
<p>Это поле в таблице peer называется peer_info_hash. А в таблице torrent это поле torrent_info_hash. torrent_id там лишний. Совсем. Обратите внимание, что в таблице peer torrent_id тоже есть. Непонятно зачем.</p>
<p>Ну и таблица user. Казалось бы, тут я просто не мог сделать ошибки. Ошибался.</p>
<p>В системе авторизации, например, на rutracker.org, free-torrents.org и прочих используется GET параметр с уникальным для пользователя значением. В таблице это значение user_torrent_uid. Вот спросите меня, кто мешал использовать это значение в качестве естественного ключа в том или ином варианте? Да, оно может измениться. В очень редком случае. Ну и что? Если 8 байт – слишком длинно, можно было взять обычный случайный INT и конвертировать его в текст, как на Flickr делают умные люди. Можно было… Да много чего можно было.</p>
<p>Вот так. Все очевидно, не так ли?</p>
<img src="http://feeds.feedburner.com/~r/FractalizersWebsiteRU/~4/mzlvHQ8FKew" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://ru.fractalizer.ru/frpost_136/%d0%b0%d0%b2%d1%82%d0%be%d0%b8%d0%bd%d0%ba%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d1%82%d0%bd%d1%8b%d0%b5-%d0%bf%d0%b5%d1%80%d0%b2%d0%b8%d1%87%d0%bd%d1%8b%d0%b5-%d0%ba%d0%bb%d1%8e%d1%87%d0%b8-%d1%81%d1%83/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://ru.fractalizer.ru/frpost_136/%d0%b0%d0%b2%d1%82%d0%be%d0%b8%d0%bd%d0%ba%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d1%82%d0%bd%d1%8b%d0%b5-%d0%bf%d0%b5%d1%80%d0%b2%d0%b8%d1%87%d0%bd%d1%8b%d0%b5-%d0%ba%d0%bb%d1%8e%d1%87%d0%b8-%d1%81%d1%83/</feedburner:origLink></item>
	</channel>
</rss>

