<?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>developers.org.ua</title>
	
	<link>http://www.developers.org.ua</link>
	<description>сообщество программистов</description>
	<lastBuildDate>Tue, 09 Mar 2010 13:19:17 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<feedburner:info uri="developersorgua" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://developers.org.ua/feed/" /><feedburner:emailServiceId>DevelopersOrgUa</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:browserFriendly>This is an full-text XML content feed for developers.org.ua. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><item>
		<title>Интересные ссылки №205</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/ipKcIWsmDaI/</link>
		<comments>http://www.developers.org.ua/archives/max/2010/03/05/weekly-linkdump-205/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 07:05:31 +0000</pubDate>
		<dc:creator>Макс Ищенко</dc:creator>
				<category><![CDATA[Ссылки]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[дизайн]]></category>
		<category><![CDATA[интервью]]></category>
		<category><![CDATA[ФП]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=6156</guid>
		<description><![CDATA[Интересные ссылки за неделю: Getting Real about NoSQL, нестандартный UI-дизайн, свежий номер "журнала для 1% программистов", интервью с разработчиком GitHub, "кросс-платформенная" среда исполнения для современных смартфонов, онлайн-курсы по программированию, IE6 Funeral.]]></description>
			<content:encoded><![CDATA[<p>Интересные ссылки за неделю:</p>
<ul>
<li>Фантастическая статья о технологиях, <a href="http://www.yafla.com/dforbes/Getting_Real_about_NoSQL_and_the_SQL_Isnt_Scalable_Lie/">Getting Real about NoSQL and the SQL-Isn&#8217;t-Scalable Lie</a>. В продолжение темы: <a href="http://ria101.wordpress.com/2010/02/24/hbase-vs-cassandra-why-we-moved/">HBase vs Cassandra: why we moved</a> и <a href="http://www.julianbrowne.com/article/viewer/brewers-cap-theorem">Brewer&#8217;s CAP Theorem</a></li>
<li>Интересный пример как нестандартный UI-дизайн может быть эффективнее принятых best practices, <a href="http://www.lukew.com/ff/entry.asp?1007">LukeW | &#8220;Mad Libs&#8221; Style Form Increases Conversion 25-40%</a></li>
<li>Вышел свежий номер &#8220;журнала для 1% программистов&#8221;, <a href="http://fprog.ru/2010/issue4/">Журнал «Практика функционального программирования» Выпуск 4, февраль 2010</a></li>
<li>Интервью с разработчиком GitHub, <a href="http://thegeektalk.com/interviews/scott-chacon/">Scott Chacon | The Geek Talk</a>. Его чувство юмора напоминает <a href="http://torvalds-family.blogspot.com/2009/02/25-things-about-me.html">Линуса</a> <img src='http://www.developers.org.ua/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li>Попытка сделать  &#8220;кросс-платформенную&#8221; среду исполнения для современных смартфонов (iPhone, Blackberry, Android), <a href="http://www.phonegap.com/">PhoneGap | Cross platform mobile framework</a>. Об особенностях разработки веб-приложений для этих платформ есть пара интересных книжек, <a href="http://building-iphone-apps.labs.oreilly.com/">Building iPhone Apps with HTML, CSS, and JavaScript</a> и <a href="http://apress.com/book/view/1430228687">APRESS.COM : Pro Smartphone Cross-Platform Development</a></li>
<li><a href="http://www.guidetoonlineschools.com/online-classes/computer-science">Подборка ссылок на онлайн-курсы по программированию, типа МТИ</a></li>
<li>Похороны IE6, <a href="http://ie6funeral.com/">Announcement | IE6 Funeral</a></li>
</ul>
<br/><a href="http://www.developers.org.ua/archives/max/2010/03/05/weekly-linkdump-205/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/max/2010/03/05/weekly-linkdump-205/#comments">2 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/max/2010/03/05/weekly-linkdump-205/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/max/2010/03/05/weekly-linkdump-205/</feedburner:origLink></item>
		<item>
		<title>Отчет с Pycon 2010</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/kqUUESr6ivY/</link>
		<comments>http://www.developers.org.ua/archives/max/2010/03/02/pycon-2010/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 15:00:51 +0000</pubDate>
		<dc:creator>Макс Ищенко</dc:creator>
				<category><![CDATA[События]]></category>
		<category><![CDATA[PyCon]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Python 3]]></category>
		<category><![CDATA[конференция]]></category>
		<category><![CDATA[отчет]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=6144</guid>
		<description><![CDATA[На днях в Атланте (США) завершилась <a href="http://us.pycon.org/2010/about/">конференция</a> по языку программирования Python. В этом году мне впервые удалось на нее попасть и хочу поделиться своими впечатлениями.]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.developers.org.ua/wordpress/wp-content/uploads/2010/03/pycon.png" alt="pycon" title="pycon" width="81" height="105" align="right" />На днях в Атланте (США) завершилась <a href="http://us.pycon.org/2010/about/">конференция</a> по языку программирования Python. В этом году мне впервые удалось на нее попасть и хочу поделиться своими впечатлениями.</p>
<p>Мероприятие достаточно масштабное: три дня идут доклады (keynotes и lightning talks в большом зале и затем пять потоков для &#8220;обычных&#8221; докладов, <a href="http://us.pycon.org/2010/conference/schedule/">полная программа</a>). Плюс open spaces: неформальные &#8220;кружки по интересам&#8221;, где обсуждаются конкретные темы как например GIL, django или distribute. Плюс два дня мастер-классов, где за дополнительные деньги можно получить быстрое &#8220;погружение&#8221; по выбранной теме. Плюс четыре дня спринтов, где разработчики садятся вместе и программируют, например, новую реализацию того же GIL или закрывают тикеты в django.</p>
<p>Все доклады снимались на видео, которое уже доступно на <a href="http://pycon.blip.tv/">pycon.blip.tv</a>. Рекомендую начать с <a href="http://us.pycon.org/2010/conference/keynotes/">keynotes</a> и lightning talks (<a href="http://pycon.blip.tv/file/3264041/">1</a>, <a href="http://pycon.blip.tv/file/3245057/">2</a>, <a href="http://pycon.blip.tv/file/3261277/">3</a>), они интересные. Мне понравился доклад Threading not a model и <a href="http://pycon.blip.tv/file/3254256/">Understanding The Python GIL</a>. Хотелось бы больше докладов &#8220;продвинутого&#8221; уровня и вообще более качественной подготовки от докладчиков (ну да это камень и в <a href="http://pycon.blip.tv/file/3259574/">мой огород</a>). </p>
<p>Из услышанного и увиденного:</p>
<ul>
<li>В Python 3.2 был кардинально переделан алгоритм работы GIL, впервые за 15 (!) лет. Теперь не будет sys.setcheckinterval() и &#8220;check counter&#8221;, вместо этого используется ожидание с таймаут и принудительная передача при превышении таймаута.  Остается добавить логику по динамическому управлению приоритетами потоков, как это делает ОС</li>
<li>Переход на Python 3 понемногу становится реальностью. Идет работа над 2to3, появился и (альфа-качества) 3to2 для авто-сборки под Python 2. Появляется документация с описанием процесса перевода.</li>
<li>distutils &#038; setuptools идут в утиль, всех призывают переходить на <a href="http://pypi.python.org/pypi/pip/">pip</a>  (distribute) плюс <a href="http://pypi.python.org/pypi/virtualenv/">virtualenv</a>. Хорошая иллюстрация слов GvR,  &#8220;включенный в stdlib код перестает развиваться&#8221;</li>
<li>Бикинг взялся делать <a href="http://bitbucket.org/ianb/silverlining/">silver lining</a> (toppcloud), утилиту развертывания Python-приложений для унифицированного хостинг-окружения на базе Ubuntu+Apache+mod_wsgi</li>
<li><a href="http://nedbatchelder.com/code/coverage/">coverage.py</a> научилась понимать &#8220;условное покрытие&#8221; (т.е. когда ветка else не исполняется) и рисовать красивые html отчеты</li>
<li>У reddit 3 разработчика, при этом на новые фичи работает только &#8220;0.5 девелоперов&#8221;. Остальным видимо хватает работы в поддержке существующего. Весь деплоймент reddit происходит в Amazon cloud, ежемесячный счет за хостинг &#8211; около $20К. По словам разработчика, это значительно дешевле затрат сравнимых по посещаемости проектов</li>
</ul>
<p>Самое наверное ценное в такого рода мероприятиях это не сами доклады, которые есть на видео, а возможность знакомства и общения с другими разработчиками. Всегда приятно &#8220;развиртуализоваться&#8221; с человеком, с которым общался чуть ли не десяток лет в списках рассылки. Главное <a href="http://twitter.com/gvanrossum/statuses/9390451531">не переборщить</a>. Неожиданно для себя получил, например, пару серьезных разговоров насчет возможной контрактной работы.</p>
<p>Из Киева было аж четыре человека, один парень был из СПб, других людей из России/Украины замечено не было. Поляков и других европейцев было много. Для наших широт поездка на PyCon удовольствие не из дешевых, $1000 стоит перелет плюс еще примерно столько же на проживание и еду/развлечения. Вряд ли я поеду на следующий, вместо этого лучше попробуем провести EuroPython в Киеве.</p>
<p>Честно говоря не знаю, что еще написать. Кому интересен был ход событий, мог следить за ними <a href="http://twitter.com/#search?q=pycon">в твиттере</a>. Про видео написал. О впечатлениях от поездки в Штаты <a href="http://maxua.posterous.com/12150217">написал у себя в блоге</a>. Если есть еще вопросы &#8212; отвечу в комментариях.</p>
<br/><a href="http://www.developers.org.ua/archives/max/2010/03/02/pycon-2010/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/max/2010/03/02/pycon-2010/#comments">8 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/max/2010/03/02/pycon-2010/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/max/2010/03/02/pycon-2010/</feedburner:origLink></item>
		<item>
		<title>Пенсионное страхование для программистов</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/X68apR2FAWU/</link>
		<comments>http://www.developers.org.ua/archives/s-didenko/2010/02/18/retirement-insurance/#comments</comments>
		<pubDate>Wed, 17 Feb 2010 23:11:14 +0000</pubDate>
		<dc:creator>Станислав Диденко</dc:creator>
				<category><![CDATA[О работе]]></category>
		<category><![CDATA[IT-Ukraine]]></category>
		<category><![CDATA[пенсионное страхование]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=6122</guid>
		<description><![CDATA[Ассоциация «IT-Ukraine» в рамках работы по созданию долгосрочных мотиваций для работников ИТ-индустрии разработала следующую модель.]]></description>
			<content:encoded><![CDATA[<p>Ассоциация «IT-Ukraine» в рамках работы по созданию долгосрочных мотиваций для работников ИТ-индустрии разработала следующую модель.</p>
<p>Так как все это делается для Вас, нам важно узнать Ваши мысли.</p>
<p>Не секрет, что в данный момент существует проблема покупки жилья. Также, проблема с тем, что на пенсию, которую выплачивает государство выжить весьма проблематично. Есть вариант решения одновременно и первой и второй проблемы путем создания негосударственного пенсионного фонда ИТ-индустрии.</p>
<p>1. Пенсия. Участники фонда, ежемесячно отчисляя пенсионные взносы, в течение своего работоспособного возраста накапливают себе пенсию. Размер пенсии  в будущем (при расчете – 30 лет накапливаю, 15 лет получаю) будет в два раза больше чем ежемесячные отчисления в текущем. Это при условии, что доходность фонда покрывает только инфляцию. Т.е. отчисляя сейчас 1000 грн/мес пенсия будет 2000 грн (эквивалент этих денег по своей покупательной способности на момент выдачи).</p>
<p>2. Вопрос жилья. Пенсионный фонд обязан вкладывать деньги своих участников в доходные активы для того, чтобы эти деньги не обесценивались, а в идеале и приносили прибыль. Законодательство позволяет вкладывать деньги, в том числе в недвижимость, ипотечные ценные бумаги, депозиты.</p>
<p>Данная ситуация дает следующие возможности: </p>
<p>1) Фонд покупает недвижимость (условно – жилой дом) – это актив его вкладчиков, который ежегодно растет в цене (т.е. приносит прибыль для их пенсий). Однако этот дом стоит и в нем никто не живет. Фонд может сдавать его в аренду. Если речь идет о фонде индустрии, цель которого – создание условий для жизни вкладчиков, то стоимость такой аренды может быть, значительно ниже рыночной.</p>
<p>2) С помощью такого актива, как депозиты, Фонд может выдавать, в том числе ипотечные и потребительские кредиты вкладчикам. В данном случае, % по таким кредитам может быть ниже рыночного, тем более если определенная сумма уже есть. </p>
<p>По предварительным расчетам каждый из участников фонда в течение 10 лет сможет претендовать на получение жилья по одной из схем (при условии ежемесячных отчислений на уровне 1300-1500 грн).</p>
<p>Если коротко – это общая идея.</p>
<p>Актуальны ли для Вас перечисленные проблемы?<br />
Было бы Вам интересно участвовать в такой программе?<br />
Какие предостережения у Вас могут возникнуть?<br />
Иные вопросы?</p>
<br/><a href="http://www.developers.org.ua/archives/s-didenko/2010/02/18/retirement-insurance/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/s-didenko/2010/02/18/retirement-insurance/#comments">166 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/s-didenko/2010/02/18/retirement-insurance/feed/</wfw:commentRss>
		<slash:comments>166</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/s-didenko/2010/02/18/retirement-insurance/</feedburner:origLink></item>
		<item>
		<title>Интересные ссылки №204</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/S3Evm37pRhk/</link>
		<comments>http://www.developers.org.ua/archives/max/2010/02/12/weekly-linkdump-204/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 09:17:26 +0000</pubDate>
		<dc:creator>Макс Ищенко</dc:creator>
				<category><![CDATA[Ссылки]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[reddit]]></category>
		<category><![CDATA[xkcd]]></category>
		<category><![CDATA[книги]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=6110</guid>
		<description><![CDATA[Интересные ссылки за неделю: современная версия "RU.PROGRAMMING FAQ" на reddit, JavaScript на сервере, учебник по JavaScript, светлое будущее Java, подборка тулов для веб-разработки под Firefox, IE, Opera, Android vs. iPhone, Android Bug Reports, Songs, Rovers, как в компании Майкрософт "давят" творчество.]]></description>
			<content:encoded><![CDATA[<p>Интересные ссылки за неделю:</p>
<ul>
<li>Современная версия &#8220;RU.PROGRAMMING FAQ&#8221; на reddit, <a href="http://www.reddit.com/help/faqs/programming#Whatprogrammingblogsorwebsitesdoyouread">reddit.com: FAQ</a> &#8212; <a href="http://www.reddit.com/r/programming/comments/62dme/ask_programmingreddit_mustread_programming_books">Must-read programming books?</a> 220+ comments (best comment: &#8220;Yes, you must.&#8221;)</li>
<li>JavaScript на сервере, <a href="http://www.sitepen.com/blog/2010/01/19/commonjsjsgi-the-emerging-javascript-application-server-platform/">CommonJS/JSGI: The Emerging JavaScript Application Server Platform</a></li>
<li>Учебник по JavaScript, <a href="http://eloquentjavascript.net/contents.html">Contents &#8212; Eloquent JavaScript</a></li>
<li>Oracle, Sun, Java, <a href="http://itfreak.ru/news/bright-future-of-java/">Светлое будущее Java</a></li>
<li>Большая подборка тулов для веб-разработки под Firefox, IE, Opera, <a href="http://codefusionlab.blogspot.com/2010/02/43-in-browser-web-development-tools.html">Codefusion Lab: 43 In-Browser Web Development Tools That Will Make You A Better Web Developer</a></li>
<li>Разработка под Android sucks? oleg andreev &#8211; <a href="http://oleganza.tumblr.com/post/368520883/android-vs-iphone-the-good-the-bad-and-the-ugly">Android vs. iPhone: the good, the bad and the ugly</a></li>
<li>&#8220;Sometimes, when arranging home screen icons, you feel sad and you’re not sure why&#8221;, <a href="http://blog.xkcd.com/2010/02/08/android-bug-reports-songs-rovers/">Android Bug Reports, Songs, Rovers « xkcd</a></li>
<li>Вице-президент Майкрософт пишет о том, как в компании &#8220;давят&#8221; творчество. Почему-то пишет об этом в NYTimes, <a href="http://www.nytimes.com/2010/02/04/opinion/04brass.html?pagewanted=all">Op-Ed Contributor &#8211; Microsoft’s Creative Destruction &#8211; NYTimes.com</a></li>
</ul>
<br/><a href="http://www.developers.org.ua/archives/max/2010/02/12/weekly-linkdump-204/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/max/2010/02/12/weekly-linkdump-204/#comments">8 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/max/2010/02/12/weekly-linkdump-204/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/max/2010/02/12/weekly-linkdump-204/</feedburner:origLink></item>
		<item>
		<title>Интересные ссылки №203</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/gtrQnOCSGIo/</link>
		<comments>http://www.developers.org.ua/archives/max/2010/02/05/weekly-linkdump-203/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 10:30:51 +0000</pubDate>
		<dc:creator>Макс Ищенко</dc:creator>
				<category><![CDATA[Ссылки]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[DSL]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[md5]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[Марк Пилгрим]]></category>
		<category><![CDATA[опцион]]></category>
		<category><![CDATA[пароль]]></category>
		<category><![CDATA[стартап]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=6071</guid>
		<description><![CDATA[Интересные ссылки за неделю: How To Safely Store A Password, калькулятор для опционов, новая глава из книги Dive Into HTML5,  репликация в PostgreSQL, Nine Things Developers Want More Than Money, транслятор PHP->C++ от Facebook, javascript DSL for building async web apps.]]></description>
			<content:encoded><![CDATA[<p>Интересные ссылки за неделю:</p>
<ul>
<li>Оказывается, использовать хеш-функции типа md5 или даже sha1 для паролей это уже некомильфо &#8212; слишком быстро подбирается, <a href="http://codahale.com/how-to-safely-store-a-password/">How To Safely Store A Password | codahale.com</a></li>
<li>Если вас зовут в стартап, вот готовый &#8220;калькулятор&#8221; для ваших опционов, <a href="https://code.google.com/p/startupequitysimulator/source/browse/trunk/payout.py">payout.py &#8211; startupequitysimulator</a></li>
<li>Марк Пилгрим опубликовал новую главу из своей книги HTML5, на этот раз про geolocation, <a href="http://diveintohtml5.org/geolocation.html">You Are Here (And So Is Everybody Else) &#8211; Dive Into HTML5</a>. Прекрасно, как и всегда.</li>
<li>Следующий мажорный релиз PostgreSQL будет поддерживать репликацию, <a href="http://www.depesz.com/index.php/2010/02/01/waiting-for-9-0-streaming-replication/">Waiting for 9.0 – Streaming replication</a></li>
<li><a href="http://www.softwarebyrob.com/2006/10/31/nine-things-developers-want-more-than-money/">Nine Things Developers Want More Than Money | Software by Rob</a> &#8212; многовато слов, но в общем верно</li>
<li>Facebook выложил в Open Source свой транслятор PHP-&gt;C++, <a href="http://developers.facebook.com/news.php?story=358&amp;blog=1">HipHop for PHP: Move Fast</a></li>
<li>На JavaScript уже делают вещи, которые нормальному девелоперу не понять, <a href="http://www.fabjs.org/">(fab) &#8211; a pure javascript DSL</a></li>
<li>В прошлую субботу в Киеве прошел pycamp. Мои впечатления и отзывы других участников, <a href="http://maxua.posterous.com/-pycamp">http://maxua.posterous.com/-pycamp</a></li>
</ul>
<br/><a href="http://www.developers.org.ua/archives/max/2010/02/05/weekly-linkdump-203/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/max/2010/02/05/weekly-linkdump-203/#comments">6 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/max/2010/02/05/weekly-linkdump-203/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/max/2010/02/05/weekly-linkdump-203/</feedburner:origLink></item>
		<item>
		<title>Интересные ссылки №202</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/VLb84siIBYc/</link>
		<comments>http://www.developers.org.ua/archives/max/2010/01/29/weekly-linkdump-202/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 16:53:50 +0000</pubDate>
		<dc:creator>Макс Ищенко</dc:creator>
				<category><![CDATA[Ссылки]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[gamedev]]></category>
		<category><![CDATA[geek]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[usenet]]></category>
		<category><![CDATA[интерфейс]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=6057</guid>
		<description><![CDATA[Интересные ссылки за неделю: Linux performance basics, замечательные cookies из подписей Erik Naggum, Geek behaviors present during conversations, Amplifying C, Realism in UI Design, зачем Линус придумал концепцию staging для git.]]></description>
			<content:encoded><![CDATA[<ul>
<li><a href="http://spyced.blogspot.com/2010/01/linux-performance-basics.html">Linux performance basics</a> &#8212; если вы админите хотя бы простенький сайтик, это точно пригодится</li>
<li><a href="http://www.xach.com/naggum/usenet-sigs.txt">http://www.xach.com/naggum/usenet-sigs.txt</a> &#8212; замечательные cookies из подписей Erik Naggum</li>
<li><a href="http://www.stanford.edu/%7Epgbovine/geek-behaviors.htm">Philip Guo &#8211; Geek behaviors present during conversations</a> &#8212; какая-то заумь, но вроде интересно</li>
<li><a href="http://voodoo-slide.blogspot.com/2010/01/amplifying-c.html">voodoo slide: Amplifying C</a> &#8212; почему (некоторые?) гейм-девелоперы не любят С++</li>
<li><a href="http://ignorethecode.net/blog/2010/01/21/realism_in_ui_design/">ignore the code: Realism in UI Design</a> &#8212; излишняя реалистичность элементов интерфейса затрудняет их понимание пользователями</li>
<li><a href="http://plasmasturm.org/log/gitidxpraise/">In praise of git’s index // plasmasturm.org</a> &#8212; зачем Линус придумал концепцию staging для git</li>
</ul>
<br/><a href="http://www.developers.org.ua/archives/max/2010/01/29/weekly-linkdump-202/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/max/2010/01/29/weekly-linkdump-202/#comments">3 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/max/2010/01/29/weekly-linkdump-202/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/max/2010/01/29/weekly-linkdump-202/</feedburner:origLink></item>
		<item>
		<title>Что будет с зарплатами в 2010 году?</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/_ryaTUtI2Ts/</link>
		<comments>http://www.developers.org.ua/archives/max/2010/01/27/salaries-2010-forecast/#comments</comments>
		<pubDate>Wed, 27 Jan 2010 09:29:08 +0000</pubDate>
		<dc:creator>Макс Ищенко</dc:creator>
				<category><![CDATA[О работе]]></category>
		<category><![CDATA[зарплаты]]></category>
		<category><![CDATA[прогноз]]></category>
		<category><![CDATA[рынок]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=6042</guid>
		<description><![CDATA[Движение зарплат будет определяться спросом на рынке. С девальвацией гривны в 2009 ключевую роль будет играть рынок аутсорсинга и те компании, которые на нем работают.  Часть компаний вероятно попытается переориентировать на внешний рынок и, таким образом, будут увеличивать предложение, а значит снижать (удерживать) рейт для заказчика. ]]></description>
			<content:encoded><![CDATA[<p>В октябре мы проводили <a href="http://www.developers.org.ua/archives/max/2009/10/12/job-market-report/">исследования зарплат программистов в 2009 году</a> (по данным анкетирования пользователей сайта). Напомню, по данным опроса, долларовые зарплаты в 2009 оставались примерно на одном уровне с небольшими колебаниями. Наши данные это подтверждают:</p>
<p><img src="http://www.developers.org.ua/wordpress/wp-content/uploads/2010/01/salary-ukr-10-50-90.png" alt="график зарплат" width="832" height="455" style="padding:0;" /></p>
<p><small>Динамика изменений минимальной (10й перцентиль), средней (медиана), и максимальной (90й перцентиль) зарплаты.</small></p>
<p>Что же будет с зарплатами в этом году?</p>
<p>Движение зарплат будет определяться спросом на рынке. С девальвацией гривны в 2009 ключевую роль будет играть рынок аутсорсинга и те компании, которые на нем работают.  Часть компаний вероятно попытается переориентировать на внешний рынок и, таким образом, будут увеличивать предложение, а значит снижать (удерживать) рейт для заказчика. </p>
<p>Что будет в итоге &#8212; куда качнется баланс спроса и предложения &#8212; сказать пока сложно. Я думаю рост на уровне 10-15% в долларах вполне реален. Но только для тех компаний, которые получают доходы в валюте. Это вероятно приведет к тому, что эти компании будут &#8220;перетягивать&#8221; к себе сильных программистов, которые будут появляться на рынке. Для остальных &#8212; рост с небольшим опережением гривневой инфляции (т.е. до 20% в гривне). Точно плохо будет разве что тем, кто работает в госструктурах и бюджетных организациях &#8212; с госбюджетом на 2010 все очень мрачно.</p>
<p>По нашим инсайдерским данным, отдельные компании уже начали &#8220;охоту&#8221; за специалистами, &#8220;перебивая&#8221; встречные предложения по зарплате от конкурентов. Количество вакансий (по нашему сайту) растет, как бесплатных, так и платных. Безработица программистам в любом случае пока не грозит &#8212; спрос высокий. Даже если сменить работу &#8220;с прибавкой&#8221; получится не у всех, то найти работу, урезав свои притязания или согласившись на гривневую зарплату. </p>
<p><img src="http://www.developers.org.ua/wordpress/wp-content/uploads/2010/01/jobboard-stats.png" alt="количество вакансий" width="379" height="228" style="padding:0;" /></p>
<p><small>количество вакансий на нашем сайте</small></p>
<p>Чтобы ослабить давление на зарплаты и справиться с дефицитом кадров, компании будут снова запускать учебные центры. Ходят слухи, что несколько крупных компаний собираются &#8220;вскладчину&#8221; построить отдельный УЦ широкого профиля.</p>
<h3>Комментарии компаний</h3>
<h4>Земницкий Дмитрий, Pragmasoft (Харьков)</h4>
<p>Зарплаты в 2009 стали более реальными. В определенный момент, примерно весной, на рынке появилось определенное количество неплохих программистов из развалившихся компаний за вполне внятные деньги. Мы приняли на работу двух джавистов с опытом в этом году. В 2008 году такое было маловероятно, приходилось воспитывать самим.</p>
<p>Прогноз на 2010 очень сильно зависит от экономической ситуации в мире, прежде всего. Если пошатнется американская и европейская экономика, не будет заказов, зарплаты могут обвалиться вплоть до 50%. Думаю что так и будет, но не обязательно в 2010, возможно на год-два позже. Если все будет как сейчас, зависит от заказчиков. У компаний с успешными заказчиками возможно небольшое повышение зпл, и наоборот.</p>
<h4>Вадим Михневич, U-Wiss BV (Нидерланды)</h4>
<p>В 2009 компании не было смысла повышать зарплату в евро, поскольку за счет роста курса гривневый эквивалент увеличивался автоматически. В 2010 году за счет увеличения спроса из-за окончания кризисного периода, компаниям будет смысл немного увеличить зарплату, до 10% в евро. Есть общая тенденция роста курса, и давать более значительный прирост смысла нет &#8212; просто чтобы &#8220;отметить&#8221; лояльное отношение к сотрудникам и предотвратить &#8220;расползание&#8221; кадров (&#8221;О, зарплату подняли &#8212; ништяк, можно еще тут поработать, вдруг еще поднимут&#8221;). </p>
<h4>Артем Савотин, ameria.de (Германия)</h4>
<p>В целом, особенно по Киеву, в 2009 заметно упал спрос на высокие зарплаты в валюте и люди начали себя более адекватно оценивать. Можно спокойно договариваться о гривне учитывая индексацию к покупательской способности. По сравнению с другими специальностями, очень многие Project Manager-ы и Technical Writers находятся в поиске работы, несмотря на то, что у них есть постоянное рабочее место.</p>
<p>На 2010 прогнозируем рост +20-30% в гривне при условии, что национальная валюта останется на таком же уровне к иностранной, как сейчас. Если будет обвал, тогда мы будем очень оперативно реагировать и зарплаты в гривне могут вырасти намного выше. Мы видим очень большой спрос на опытных PHP разработчиков. Довольно сложно найти хороших и свободных специалистов по Plone/Zope на рынке Украины. По этому, возможно, что будем обучать ребят знающих Python.</p>
<h4>Дмитрий Сохач, ISD (Днепропетровск)</h4>
<p>Я считаю, что зарплаты по Киеву возрастут незначительно, но в регионах будет значительный в процентном отношении рост зарплат по сравнению с предыдущим годом, на 5-10% больше (в долларах).</p>
<h4> На условиях анонимности (Харьков)</h4>
<p>IT рынок в 2010 по-прежнему будет оставаться неоднородным. Какие-то компании усилят свое положение на рынке, будет оставаться часть компаний, которые не смогут дальше продолжить свой бизнес. Возможно, в 2010 году услышим о каких-то крупных слияниях или приобретении более мелких компаний. 2010 год ожидает быть более стабильным нежели уходящий. Наш прогноз &#8212; вырастут на 5-15% (в долларах) для разных категорий программистов. Общая тенденция рынка &#8212; з/п медленно будут продолжать расти. Сохранится большой спрос на профессионалов, который и будет двигать повышение з/п.</p>
<p>Востребованными программистами в этом году будут оставаться .Net Developers, Java Developers, на тестировщиков будет оставаться стабильный спрос. Возобновится интерес к менеджерам высшего звена. Как всегда будут востребованы менеджеры по продажам, маркетологи, которые смогут представить компанию в более выгодном свете, увеличить объемы продаж в перспективе. В 2010 году ожидается интерес к мобильным, переносным устройствам (и программистов, способных под них писать).</p>
<h4>Марина Вышгородских, Ciklum (Киев)</h4>
<p>Уже сейчас заметна тенденция к тому, что в 2010 запросы на специалистов будут более узкоспециализированными. Возможно, это связано с тем, что в результате кризиса с одной стороны появилась возможность найти экспертов в mainstream технологиях и в Европе, с другой – клиенты в меньшей мере готовы тратить время и ресурсы на обучение, хотят в Украине получить уже готовых специалистов.</p>
<p>В настоящий момент много запросов на iPhone and Android developers, IBM WebSphere supporters and developers, специалистов со знанием Drupal, МОSS, Google Web Toolkit, etc &#8212; причем, в качестве основных, а не «желательных» требований.</p>
<p>Я думаю, джуниорам имеет смысл заняться активным освоением относительно быстро изучаемых технологий &#8212; например, разработкой под мобильные платформы.<br />
Мы же планируем проводить курсы экспресс-подготовки узкоспециализированных специалистов, сейчас ищем партнеров для создания таких программ.</p>
<p>Что касается зарплат, думаю, возвращающийся после кризиса спрос их слегка подогреет, но не думаю, что в 2010 мы вернемся к временам зарплатного бума 2007-2008 годов. </p>
<br/><a href="http://www.developers.org.ua/archives/max/2010/01/27/salaries-2010-forecast/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/max/2010/01/27/salaries-2010-forecast/#comments">50 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/max/2010/01/27/salaries-2010-forecast/feed/</wfw:commentRss>
		<slash:comments>50</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/max/2010/01/27/salaries-2010-forecast/</feedburner:origLink></item>
		<item>
		<title>Обзор Alfresco WCM</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/oWljazKPR1c/</link>
		<comments>http://www.developers.org.ua/archives/jozh/2010/01/26/alfresco-wcm-overview/#comments</comments>
		<pubDate>Tue, 26 Jan 2010 12:34:43 +0000</pubDate>
		<dc:creator>Максим Михеенко</dc:creator>
				<category><![CDATA[Разработка]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[alfresco]]></category>
		<category><![CDATA[ecm]]></category>
		<category><![CDATA[freemarker]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[liferay]]></category>
		<category><![CDATA[wcm]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=5970</guid>
		<description><![CDATA[В статье описано, что такое Alfresco и с чем его едят. Интеграция с порталом Liferay, описание основных составляющих, таких как WCM, Web forms, Web-scripts, поиск, Metadata extraction. Подробнее всего описана работа с веб-содержимым.]]></description>
			<content:encoded><![CDATA[<p>Итак, прошло примерно 3 месяца со времени моего знакомства с Alfresco WCM, а если точнее &#8212; попытки быстро создать на нем сайт. Русскоязычных материалов по теме мало, и я постараюсь ответить на вопросы, которые возникали у меня в процессе изучения и ответы на которые не лежат на поверхности. Статья показывает возможности применения Alfresco и,  вероятно, поможет принять решение использовать эту CMS или нет.</p>
<h3>Что такое Alfresco?</h3>
<p>Зайдя на <a href="http://wiki.alfresco.com">wiki.alfresco.com</a> мы можем скачать Community-версию, она бесплатна, на момент написания статьи выпущена версия 3.2. Как система управления веб-контентом, она достаточно просто интегрируется с open-source порталом <a href="http://www.liferay.com">Liferay</a> и призвана взвалить на себя нагрузку по управлению сложным веб-содержимым. Скачав инсталлятор, можно быстро установить уже сконфигурированную связку MySQL + Alfresco server + Alfresco virtual server. Для портала Liferay можно скачать Alfresco portlet из репозитория и развернуть Alfresco server на том же сервере приложений, что и портал.</p>
<p>Alfresco &#8212; это файло-ориентированная CMS, которая может как представлять собой файловую систему, так и расширять общепринятую функциональность через мета-данные, закрепляемые за каждым файлом и папкой.</p>
<h4>Первое знакомство</h4>
<p>При старте запускается MySQL и Tomcat с Alfresco server (занимает порт 8080, 21), а еще можно запустить Virtual Server (занимает порт 8180). Виртуальный сервер &#8212; удобное средство для предпросмотра сайта с наполнением, он обязательно должен быть запущен при работе с WCM.</p>
<p>При изучении документации встречаются обе аббревиатуры ECM и WCM. Enterprise Content Management — это ядро системы. Здесь можно создавать собственные типы данных Custom Content Model, например, тип Сотрудник с полями Имя, Фамилия, Отчество, Кабинет и Дата рождения. Эту часть системы я рассматривал поверхностно, больше копаясь в WCM, который создан как настройка над ECM.</p>
<p>Alfresco имеет свой веб-интерфейс (http://localhost:8080/alfresco/), который на самом деле является клиентом к сервисам ECM и от того позволяет выполнять лишь наиболее популярные действия, 90% конфигурирования и управления системой выполняется в .xml файлах, расположенных в 2х местах: <em>&lt;alfresco_dir&gt;/tomcat/webapps/alfresco/WEB-йINF/classes/alfresco</em> и <em>&lt;alfresco_dir&gt;/tomcat/shared/classes/alfresco/extension. </em>Там же есть множество примеров, и чаще всего эти файлы &#8212; конфигурации Spring framework, что сразу означает, что они отнюдь не прозаичны и требуют понимания архитектуры всей системы.<em><br />
</em></p>
<h3>Web Content Management (WCM)</h3>
<p>Как сказано в документации &#8212; специально для управления веб-содержимым в Alfresco разработан AVM (Advanced Versioning Manager). Это специальная модель, созданная на основе ECM, и представляющая собой версионные Файлы и Папки, плюс дополнительные сервисы. Основная идея состоит в следующем. Есть сайт (Site) и его наполнение. Каждый автор создает содержимое в его собственном хранилище, которое как слой наложено на содержимое сайта. После того как автор создал статью, он делает ей Submit и она идет по потоку утверждения. Когда статья окончательно утверждается, она переносится в общее хранилище и становится видимой всем остальным участникам работы над сайтом. Таким же образом поддерживается версионность документов. Локальные изменения каждого пользователя только после утверждения попадают в общее хранилище.</p>
<p>Этот подход имеет огромные достоинства: каждый автор имеет свой репозиторий, который всегда содержит последние общие обновления и одновременно может видеть свои изменения прямо на сайте. Добавив новость, автор может увидеть ее сразу же на своем виртуальном сайте, а другие участники могут ее увидеть только после утверждения. Однако есть и минусы. На текущий момент не решена проблема конфликтов. При появлении конфликта нет понятия merge, можно только откатить свои изменения. Таким образом, кто первый засабмитил &#8212; того и тапки. В версии 3.2 налюдается еще и глюк, когда без отката изменений нельзя засабмитить и другие, не конфликтные, файлы и еще одна проблема сабмита большого количества файлов (опытным путем установлено, что первой волной надо засабмитить только .xml файлы, выждать время, а после &#8212; все остальные).</p>
<p>Общее хранилище не является финальным для отображения, для него предусмотрена еще и публикация (deployment) на production-сервер через FSR (File System Receiver). Работает это так. При выполнении команды Deploy, создается событие отправки последних изменений. Дальше не совсем прозаично. У вас должен быть настроен получатель события, а это отдельный java-процесс (.jar и все необходимое можно скачать с официального сайта), который подписывается на deployment-события и выкладывает полученные изменения в локальную файловую систему.</p>
<h4>Файловая структура</h4>
<p>Alfresco ECM после инсталляции сконфигурирована как продвинутая файловая система с возможностью добавления метаданных к файлам и папкам, спектр которых разнообразен. Это могут быть и события, происходящие при появлении новых файлов в папке, возможность сохранения версий изменений или возможность комментирования.</p>
<p>При использовании WCM eсть нюанс. Через CMIS (протокол SMB, подключение удаленной папки) не доступны репозитории WCM, а только ECM, что означает отсутствие возможности заливать веб-контент через удаленную папку в Windows. Удаленный доступ к репозиториям AVM возможен только через FTP (этот сервис автоматически доступен при старте Alfresco), который корректно работает с русскими буквами.</p>
<h4>Web Forms</h4>
<p>Главная функция для веб-CMS, это создание и отображение содержимого сайта. Для этого в Alfresco используются веб-формы. Структура контента определяется в xml-схемах (.xsd файлы), наполнение сохраняется в формате xml, соответствующим этим схемам, а представление может быть отрендерено в разные форматы, чаще всего в html.</p>
<p>А теперь важный архитектурный момент. Рендеринг введенных пользователем данных осуществляется в момент ввода, — то есть когда пользователь создал контент типа Новость и заполнил все поля, создается несколько файлов. Например, <em>novogodnie-skidki.xml, </em><em>novogodnie-skidki</em><em>.html, </em><em>novogodnie-skidki</em><em>-short.html</em>, где первый содержит наполнение в xml (исходные данные), второй — &#8220;новость подробно&#8221; и третий — &#8220;новость кратко&#8221;, скажем, для главной страницы. Для рендеринга используются FreeMarker template или XSLT преобразования. С успехом мы можем рендерить и .jsp страницы, располагать их в разных директориях и пр.</p>
<p>Процесс рендеринга — на удивление медленный и ресурсоёмкий. Если выполнить перегенерацию всего контента, это может происходить минут 5 для 100 элементов.</p>
<p>Существует возможность на этапе преобразования использовать любые средства &#8212; обрабатывать списки контента, делать включение других шаблонов, использовать .jsp файлы, вызывать alfresco web-scripts, другими словами, можно создать абсолютно любой контент.</p>
<p>Важно понимать, что рендеринг наполнения происходит на этапе создания контента, а это говорит о следующем: созданный .html контент статичен (исключение &#8212; рендеринг .jsp страниц).</p>
<p>Еще один минус &#8212; при работе с репозиторием через стандартный веб-клиент Alfresco автор видит как нужные ему файлы (.xml), так и их представление .html, а чаще &#8212; еще и вспомогательные, .jsp и другие ресурсы. Как этого избежать, я так и не нашел.</p>
<h4>Архитектура веб-приложения</h4>
<p>Alfresco создает статический контент. На этом ее функции по созданию веб-сайтов заканчиваются. Alfresco предлагает свой Web Framework, но он крайне сложный. Чтобы упростить работу с ним, выпущен визуальный построитель сайтов Alfresco Surf platform, но даже в релизе(!) он глючит и не может получить из Alfresco список веб-контента. За разумное время мне не удалось сделать ничего толкового и было принято решение отказаться от его использования. Дальше описаны несколько наиболее применимых архитектур веб приложений.</p>
<p>Первый вариант создания сайта &#8212; чистый plain text и отсутствие динамики, который хорошо подойдет к маленьким сайтам-визиткам, где достаточно отрендерить всё в html и, возможно, сделать часть динамических страниц через .jsp. При этом деплоиться сайт может, например, в /tomcat/webapps/ROOT. Списки новостей могут так же рендериться на этапе добавлении новости и отображаться как статическая страница. Скорость работы такого сайта стремится к первой космической, а нагрузка на сервер &#8212; к нулю.</p>
<p>Второй вариант &#8212; использование фреймворка, который хорошо бы работал с уже сгенерированными страницами, например <a href="http://www.opensymphony.com/sitemesh/index.html" target="_blank">SiteMesh</a>. В этом случае достаточно просто создавать страницы .html с уже сформированными на основе контента мета-данными (title, description, keywords).</p>
<p>Третий вариант &#8212; использование Alfresco web-scripts для формирования страниц.</p>
<h4>Поиск</h4>
<p>Поиск — это ключевой компонент Alfresco, потому что только с помощью поиска можно выполнить выборку контента. Вероятно по этому видов поиска достаточно много:</p>
<ul>
<li>Open Search — доступен из веб-интерфейса, ищет только по репозиторию ECM, поэтому даже не пытайтесь найти свой первый helloworld.html в WCM репозитории;</li>
<li>Lucene — наиболее мощный вид поиска, досупен только из web scripts или джавы;</li>
<li>XPath — последовательный обход дерева элементов, что означает низкую производительность</li>
<li>CQL — обещают возможность описывать поисковые запросы по модели данных ECM в синтаксисе SQL — практического применения не видел.</li>
</ul>
<p>Из всего списка реально применим только Lucene, у него широкие возможности поиска по атрибутам и метаданным документа, но по умолчанию содержимое всех документов (и даже xml) считается сплошным текстом, что создает сложности, если мы хотим найти наличие определенного поля в документе. С другой стороны, сразу можно искать по таким полям как имя, путь к файлу, дата создания/модификации и некоторым другим.</p>
<p>Ограничением поиска Lucene является возможность искать только в общем репозитории утвержденного контента, т.е. пользовательские хранилища не доступны для поиска.</p>
<h4>Web scripts</h4>
<p>Веб-скрипты в Alfresco заслуживают отдельного внимания. Это модель MVC, один из немногих удобных механизмов а Alfresco, который представляет собой связку javascript + FreeMarker templates. Каждый скрипт имеет привязку к шаблону URL, наподобие grails, например /news/{year}?/{newsName}?. При запросе этого адреса выполняется javascript, в котором доступны почти все сервисы Alfresco. Результат рендерится в шаблонах FreeMarker.</p>
<p>Производительность не замерял, но на взгляд она не плоха, учитывая даже что javascript и FreeMarker преобразования выполняются при каждом вызове url и являются скриптами.</p>
<p>Есть одна радость — эту связку можно хоть как-то тестировать, чего не скажешь об остальных средствах.</p>
<p>Самое время обрадоваться наличию такой технологии, но и тут ложка дегтя — очень тупо реализованный &lt;include&gt; джаваскрипта. Если хочется хоть какую-то архитектуру создать, то придется делать включения нескольких javascipt-файлов, что реализовано &#8230; простым добавлением всех скриптов в один большой StringBuffer в памяти и ошибки выполнения содержат неожиданные номера строк. В этой ситуации выручает имеющийся javascript-debugger — отдельное Swing приложение, где даже можно посмотреть все сигнатуры сервис-методов.</p>
<h4>Metadata extraction</h4>
<p>Представим такую ситуацию. У нас есть тип веб-контента Новости, нам необходимо указать отображать ли эту новость на главной странице сайта или же только в общем списке. Другими словами нам нужно добавить к контенту некий признак, наличие которого означало бы необходимость опубликовать новость на главной странице. Мы можем добавить этот признак в метаданные документа, либо сделать его полем xsd структуры Новости. Если мы добавим признак в метаданные, то он будет потерян при копировании через FTP или деплое в файловую систему через FSR. Если мы добавим поле в тип Новости, то его нельзя будет найти поиском. В этом случае на помощь приходит механизм Metadata extraction — возможность настроить Lucene таким образом, чтобы при индексации контента он изымал некоторые поля из xml, чтобы можно было написать в поисковом запросе что-то вроде &#8220;+ASPECT:{cm}showOnHomePage&#8221; и найти только те новости, которые нам нужны. Идея хороша, но достаточно сложна в реализации несмотря на наличие описаний.</p>
<h4>Alfresco + Liferay</h4>
<p>Alfresco, собранную для развертывания на сервере Liferay, можно скачать из репозитория Liferay. Эта сборка включает в себя Alfresco сервер, веб-клиент, портлеты для отображения контента, администрирования и задач пользователя. Сложностей с запуском &#8212; никаких, но интеграция не полная. Не поддерживается единый вход в систему SSO (Single Sign-on). В гугле можно найти примеры полной интеграции &#8212; при регистрации пользователя в портале, он создается в Alfresco и есть возможность отображать веб-скрипты и контент под правами текущего пользователя портала. Но как показывает практика, часто это и не нужно.</p>
<h3>Выводы</h3>
<p>Статья может содержать неточности, будем надеяться, что это я что-то не до понял и не до читал, и есть более верные и красивые способы работы с Alfresco. Резюмируя, можно отметить следующее:</p>
<ul>
<li>можно легко и быстро создавать контент, тяжело из него сделать сколь-нибудь удобный сайт;</li>
<li>автоматическое тестирование практически невозможно;</li>
<li>очень слабые возможности при работе с уже созданным содержимым — только обзор директорий, файлов и поиск;</li>
<li>заявлено много рекламных решений, которые на проверку оказываются пустышками</li>
<li>наличие большого количества багов в самой системе, что свидетельствует об отношении к тестам разработчиков, и сразу же о вашей возможности тестировать свой продукт, построенный на Alfresco.</li>
</ul>
<p>Мой личный рейтинг CMS Alfresco — 3/5.</p>
<br/><a href="http://www.developers.org.ua/archives/jozh/2010/01/26/alfresco-wcm-overview/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/jozh/2010/01/26/alfresco-wcm-overview/#comments">9 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/jozh/2010/01/26/alfresco-wcm-overview/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/jozh/2010/01/26/alfresco-wcm-overview/</feedburner:origLink></item>
		<item>
		<title>Интересные ссылки №201</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/qW5WCINIUfM/</link>
		<comments>http://www.developers.org.ua/archives/max/2010/01/22/weekly-linkdump-201/#comments</comments>
		<pubDate>Fri, 22 Jan 2010 18:50:23 +0000</pubDate>
		<dc:creator>Макс Ищенко</dc:creator>
				<category><![CDATA[Ссылки]]></category>
		<category><![CDATA[CoffeeScript]]></category>
		<category><![CDATA[Continuous deployment]]></category>
		<category><![CDATA[ESI]]></category>
		<category><![CDATA[HR]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[V8]]></category>
		<category><![CDATA[Varnish]]></category>
		<category><![CDATA[видео]]></category>
		<category><![CDATA[договор]]></category>
		<category><![CDATA[кеширование]]></category>
		<category><![CDATA[фриланс]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=6022</guid>
		<description><![CDATA[Интересные ссылки за неделю: выразительный язык высокого уровня, который компилируется в JavaScript, How to Find and Hire Amazing People, Continuous deployment makes releases non-events, кеширование страниц сайта при помощи Varnish + ESI, шаблон договора на оказание услуг по разработке ПО или веб-сайта, пятничное видео.]]></description>
			<content:encoded><![CDATA[<p>Интересные ссылки за неделю:</p>
<ul>
<li><a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> &#8212; попытка создать выразительный язык высокого уровня, который компилируется в JavaScript. Движок V8 дает <a href="http://shootout.alioth.debian.org/u64q/code-used-time-used-shapes.php">одну из самых быстрых реализаций</a> среди &#8220;скриптовых&#8221; языков (<a href="http://twitter.com/asolovyov/status/7903007805">via</a>)</li>
<li><a href="http://blog.adamsmith.cc/2010/01/how-to-find-and-hire-amazing-people-part-4.html?utm_source=feedburner">How to Find and Hire Amazing People, Part 4 &#8211; blog.adamsmith.cc</a></li>
<li>В продолжение прошлой темы про continuous deployment, <a href="http://www.startuplessonslearned.com/2010/01/case-study-continuous-deployment-makes.html">Lessons Learned: Case Study: Continuous deployment makes releases non-events</a></li>
<li>Очень интересный инструмент для &#8220;ускорения&#8221; сайта, <a href="http://highload.com.ua/index.php/2010/01/22/%D0%BA%D0%B5%D1%88%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86-%D1%83%D1%81%D0%BA%D0%BE%D1%80%D1%8F%D0%B5%D0%BC-%D1%81%D0%B0%D0%B9%D1%82-%D0%B2-100/">Кеширование страниц сайта при помощи Varnish + ESI</a></li>
<li>Для фрилансеров пригодится, <a href="http://twitter.com/bashmakov/status/7895972740">шаблон договора на оказание услуг по разработке ПО или веб-сайта</a>.</li>
<li>Пятничное видео, <a href="http://stkorn.livejournal.com/285391.html">Записки одного программиста &#8212; ВНЕДРЯЙ!</a></li>
</ul>
<br/><a href="http://www.developers.org.ua/archives/max/2010/01/22/weekly-linkdump-201/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/max/2010/01/22/weekly-linkdump-201/#comments">0 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/max/2010/01/22/weekly-linkdump-201/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/max/2010/01/22/weekly-linkdump-201/</feedburner:origLink></item>
		<item>
		<title>Немного о разрыве зависимостей и TDD</title>
		<link>http://feedproxy.google.com/~r/DevelopersOrgUa/~3/YmR7kRqN184/</link>
		<comments>http://www.developers.org.ua/archives/antonmartynenko/2010/01/18/tdd-dependency-breaking-technics/#comments</comments>
		<pubDate>Mon, 18 Jan 2010 09:55:38 +0000</pubDate>
		<dc:creator>Антон Мартыненко</dc:creator>
				<category><![CDATA[Разработка]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[NUnit]]></category>
		<category><![CDATA[Rhino Mocks]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[тестирование]]></category>

		<guid isPermaLink="false">http://www.developers.org.ua/index.php?p=5989</guid>
		<description><![CDATA[Я бы хотел показать некоторые методики разрыва зависимостей, которые я использовал в работе. Их автор – Michael Feathers. В книге Working Effectively with Legacy Code он описал больше методик, чем я здесь привожу. Я считаю, что описанные здесь методики наиболее востребованные и эффективные. Все методики я привожу на языке C#.]]></description>
			<content:encoded><![CDATA[<p>TDD (Test-Driven Development) – это техника программирования, при которой разработка ведется через тестирование. Тесты пишутся до кода, либо до внесения изменений в существующий код. Эта техника предполагает написания множества юнит-тестов, которые тестируют код. Как правило, тесты выполняются во время интеграционного тестирования, что позволяет обнаружить ошибки. </p>
<p>По мере роста размера проекта тесты принимают все более важное значение, т.к. в большом проекте возникает проблемы с изменением кода. В большом проекте очень сложно менять код, не внося при этом ошибок. Чем он больше – тем сложнее понять, на что повлияет изменение, и тем выше шанс что-то сломать. При росте размера проекта важность тестов растет экспоненциально. Юнит-тесты – отличный помощник в такой ситуации.</p>
<p>Michael Feathers в его книге Working Effectively with Legacy Code вводит понятие «Унаследованный код» (Legacy code). Унаследованный код – это код без тестов, изменение которого может быть сложным из-за отсутствия автоматических регрессионных тестов. Объективно, это существенная часть кода в тех компаниях, где мы работаем (см. <a href="http://www.developers.org.ua/archives/max/2009/12/04/qa/">опрос</a> – более 70% имеет ограниченное покрытие тестами, либо не пишут тесты совсем). Не секрет, что многие проекты в начале представляют собой простые и понятные системы, над которыми работают 1-2 программиста. В таких проектах написание тестов часто считается тратой времени. Но по мере роста проекта и возрастания сложности все более ощущается отсутствие автоматического регрессионного тестирования. Дизайн все более усложняется, и становится все труднее поддерживать и развивать проект. Так появляется унаследованный код…</p>
<p>Причины, по которым люди не пишут тесты достаточно разные. Вот немногие из них: отсутствие времени, лень, сложность написания тестов, непрофессионализм и т.д. Я бы хотел заострить внимание на сложности написания тестов, и показать пару техник, которые могут помочь. Основная причина сложности написания тестов – проблемы в архитектуре и проектировании классов. Очень часто классы имеют слишком много зависимостей, и из-за этого класс или метод невозможно изолировать для тестирования. Простой пример – форма, которая обращается к базе данных за какой-либо информацией. Обсуждение архитектуры и дизайна уходят за рамки этой статьи, но я бы хотел сказать, что такие изменения не делаются быстро, а уговорить заказчика на рефакторинг очень сложно – ведь заказчику сложно понять, почему он будет оплачивать месяцы работы, и после это не получит никакого нового функционала. Программист остается один на один с унаследованным кодом, и ему надо как-то разрывать зависимости и писать тесты.</p>
<p>Я бы хотел показать некоторые методики разрыва зависимостей, которые я использовал в работе. </p>
<p>Их автор – Michael Feathers. В книге Working Effectively with Legacy Code он описал больше методик, чем я здесь привожу. Я считаю, что описанные здесь методики наиболее востребованные и эффективные:</p>
<ul>
<li>Parameterize constructor</li>
<li>Parameterize method</li>
<li>Introduce static setter</li>
<li>Extract and override call</li>
<li>Extract and override factory method</li>
</ul>
<p>Все методики я привожу на языке C#, так как я на нем пишу. Надеюсь, он будет всем понятен =)</p>
<h3>1. Parameterize constructor</h3>
<p>Эта методика предназначена для выноса зависимости при помощи конструктора. Основная ее идея – создание нового конструктора, который принимает в качестве параметра интерфейс класса, от которого зависит «унаследованный код».</p>
<p>В унаследованном коде есть метод, который необходимо протестировать, но в этом методе содержится обращение к веб-сервису, который реализован классом WebServiceFacade в виде паттерна синглтон:</p>
<pre><code>namespace ParameterizeConstructor.LegacyCode
{
    public class ClassWithDependency
    {
        public ClassWithDependency()
        {
            //some initialization
        }

        public bool DoSomething()
        {
            //...
            int caseCount = WebServiceFacade.Instance.GetCaseCount();
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }
    }
}

using System.Diagnostics;

namespace ParameterizeConstructor.LegacyCode
{
    public class WebServiceFacade
    {
        private static WebServiceFacade instance;

        public static WebServiceFacade Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new WebServiceFacade();
                }
                return instance;
            }
        }

        public int GetCaseCount()
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web serviсe. This is not acceptable for unit test.&quot;);
            return 42;
        }

        //...
    }
}</code></pre>
<p>Нам необходимо внести изменения в код этого метода и мы должны сначала написать тест. Но мы не можем написать юнит-тест, потому что метод будет обращаться к веб-сервису во время запуска теста. Это неприемлемо. Для разрыва зависимости нам необходимо извлечь интерфейс (Extract Interface) в классе <code>WebServiceFacade</code>:</p>
<pre><code>namespace ParameterizeConstructor.BrokenDependency
{
    public interface IWebServiceFacade
    {
        int GetCaseCount();
    }
}

using System.Diagnostics;

namespace ParameterizeConstructor.BrokenDependency
{
    public class WebServiceFacade : IWebServiceFacade
    {
        private static IWebServiceFacade instance;

        public static IWebServiceFacade Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new WebServiceFacade();
                }
                return instance;
            }
        }

        public int GetCaseCount()
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web serviсe. This is not acceptable for unit test.&quot;);
            return 42;
        }
    }
}</code></pre>
<p>Теперь мы добавляем новый конструктор, не забыв оставить старый:</p>
<pre><code>namespace ParameterizeConstructor.BrokenDependency
{
    public class ClassWithDependency
    {
        /// &lt;summary&gt;
        /// We preserved original constructor
        /// &lt;/summary&gt;
        public ClassWithDependency()
            : this(WebServiceFacade.Instance)
        {
        }

        /// &lt;summary&gt;
        /// This constructor has been created for testing purposes. You can inject your dependency using this constructor
        /// &lt;/summary&gt;
        public ClassWithDependency(IWebServiceFacade webService)
        {
            this.webService = webService;
            //some initialization has gone here
        }

        private IWebServiceFacade webService;

        public bool DoSomething()
        {
            //...
            int caseCount = webService.GetCaseCount();
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }
    }
}</code></pre>
<p>В старом конструкторе мы вызываем новый конструктор с параметром <code>WebServiceFacade.Instance</code> это сделано для того, чтобы гарантировать сохранение интерфейса класса для всех, кто это класс будет использовать.</p>
<p>Теперь мы можем написать тест, используя мок:</p>
<pre><code>#if TEST
using NUnit.Framework;
using Rhino.Mocks;

namespace ParameterizeConstructor.BrokenDependency
{
    [TestFixture]
    public class TestClassWithDependency
    {
        [Test]
        public void DoSomething()
        {
            var webService = MockRepository.GenerateMock&lt;IWebServiceFacade&gt;();

            webService.Expect(x =&gt; x.GetCaseCount()).Return(20);

            var classWithDependency = new ClassWithDependency(webService);
            bool result = classWithDependency.DoSomething();
            Assert.IsTrue(result);

            //...

            webService.VerifyAllExpectations();
        }
    }
}
#endif</code></pre>
<h3>2. Parameterize method</h3>
<p>Эта методика предназначена для выноса зависимости при помощи изменения сигнатуры метода. В унаследованном коде есть метод, который необходимо протестировать, но в этом методе содержится обращение к веб-сервису, который реализован классом <code>WebServiceFacade</code> в виде паттерна синглтон:</p>
<pre><code>using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ParameterizeMethod.LegacyCode
{
    public class ClassWithDependency
    {
        public bool DoSomething()
        {
            //...
            int caseCount = WebServiceFacade.Instance.GetCaseCount();
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }
    }
}

using System.Diagnostics;

namespace ParameterizeMethod.LegacyCode
{
    public class WebServiceFacade
    {
        private static WebServiceFacade instance;

        public static WebServiceFacade Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new WebServiceFacade();
                }
                return instance;
            }
        }

        public int GetCaseCount()
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web serviсe. This is not acceptable for unit test.&quot;);
            return 42;
        }
    }
}</code></pre>
<p>Для разрыва зависимости нам необходимо извлечь интерфейс (Extract Interface) в классе <code>WebServiceFacade</code>:</p>
<pre><code>namespace ParameterizeConstructor.BrokenDependency
{
    public interface IWebServiceFacade
    {
        int GetCaseCount();
    }
}

using System.Diagnostics;

namespace ParameterizeConstructor.BrokenDependency
{
    public class WebServiceFacade : IWebServiceFacade
    {
        private static IWebServiceFacade instance;

        public static IWebServiceFacade Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new WebServiceFacade();
                }
                return instance;
            }
        }

        public int GetCaseCount()
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web serviсe. This is not acceptable for unit test.&quot;);
            return 42;
        }
    }
}</code></pre>
<p>Теперь мы добавляем новую сигнатуру метода, в старом методе делаем вызов нового с параметром <code>WebServiceFacade.Instance</code> это сделано для того, чтобы гарантировать сохранение интерфейса класса для всех, кто это класс будет использовать.</p>
<pre><code>namespace ParameterizeMethod.BrokenDependency
{
    public class ClassWithDependency
    {
        /// &lt;summary&gt;
        /// We preserved original signature
        /// &lt;/summary&gt;
        public bool DoSomething()
        {
            return DoSomething(WebServiceFacade.Instance);
        }

        /// &lt;summary&gt;
        /// This method has been created for testing purposes
        /// &lt;/summary&gt;
        public bool DoSomething(IWebServiceFacade webService)
        {
            //...
            int caseCount = webService.GetCaseCount();
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }
    }
}</code></pre>
<p>Теперь мы можем написать тест:</p>
<pre><code>#if TEST
using NUnit.Framework;
using Rhino.Mocks;

namespace ParameterizeMethod.BrokenDependency
{
    [TestFixture]
    public class TestClassWithDependency
    {
        [Test]
        public void DoSomething()
        {
            var webService = MockRepository.GenerateMock&lt;IWebServiceFacade&gt;();

            webService.Expect(x =&gt; x.GetCaseCount()).Return(20);

            var classWithDependency = new ClassWithDependency();
            bool result = classWithDependency.DoSomething(webService);
            Assert.IsTrue(result);

            //...

            webService.VerifyAllExpectations();
        }
    }
}
#endif</code></pre>
<h3>3. Introduce static setter</h3>
<p>Эта методика позволяет внедрять мок-классы в синглтон и другие статические сущности. В унаследованном коде есть метод, который необходимо протестировать, но в этом методе содержится обращение к веб-сервису, который реализован классом <code>WebServiceFacade</code> в виде паттерна синглтон:</p>
<pre><code>namespace IntroduceStaticSetter.LegacyCode
{
    public class ClassWithDependency
    {
        public bool DoSomething()
        {
            //...
            int caseCount = WebServiceFacade.Instance.GetCaseCount();
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }
    }
}

using System.Diagnostics;

namespace IntroduceStaticSetter.LegacyCode
{
    public class WebServiceFacade
    {
        private static WebServiceFacade instance;

        public static WebServiceFacade Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new WebServiceFacade();
                }
                return instance;
            }
        }

        public int GetCaseCount()
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web service. This is not acceptable for unit test.&quot;);
            return 42;
        }
    }
}</code></pre>
<p>Для разрыва зависимости нам необходимо извлечь интерфейс (Extract Interface) в классе <code>WebServiceFacade</code> а также создать статический метод – setter:</p>
<pre><code>namespace IntroduceStaticSetter.BrokenDependency
{
    public interface IWebServiceFacade
    {
        int GetCaseCount();
    }
}

using System.Diagnostics;

namespace IntroduceStaticSetter.BrokenDependency
{
    public class WebServiceFacade : IWebServiceFacade
    {
        private static IWebServiceFacade instance;

        public static IWebServiceFacade Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new WebServiceFacade();
                }
                return instance;
            }
        }

        /// &lt;summary&gt;
        /// This method has been created for testing purposes
        /// &lt;/summary&gt;
        public static void SetInstance(IWebServiceFacade webService)
        {
            instance = webService;
        }

        public int GetCaseCount()
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web service. This is not acceptable for unit test.&quot;);
            return 42;
        }
    }
}</code></pre>
<p>Класс с зависимостью остается без изменений, но теперь можно смело писать юнит-тест:</p>
<pre><code>#if TEST
using NUnit.Framework;
using Rhino.Mocks;

namespace IntroduceStaticSetter.BrokenDependency
{
    [TestFixture]
    public class TestClassWithDependency
    {
        [Test]
        public void DoSomething()
        {
            var webService = MockRepository.GenerateMock&lt;IWebServiceFacade&gt;();

            webService.Expect(x =&gt; x.GetCaseCount()).Return(20);

            WebServiceFacade.SetInstance(webService);

            var classWithDependency = new ClassWithDependency();
            bool result = classWithDependency.DoSomething();
            Assert.IsTrue(result);

            webService.VerifyAllExpectations();
        }
    }
}
#endif</code></pre>
<h3>4. Extract and override call</h3>
<p>Эта методика позволяет избавиться от зависимостей, связанных с вызовом статических методов, либо вызовов какого-либо API. Предположим у нас есть следующий код:</p>
<pre><code>namespace ExtractAndOverrideCall.LegacyCode
{
    public class ClassWithDependency
    {
        public bool DoSomething()
        {
            string customerName = string.Empty;
            //...
            //here we somehow retrieve and assign result to customerName
            customerName = &quot;Anton Martynenko&quot;;
            //...

            int caseCount = CaseCountCalculator.CalculateCaseCount(customerName);
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }
    }
}

using System.Diagnostics;

namespace ExtractAndOverrideCall.LegacyCode
{
    public class CaseCountCalculator
    {
        public static int CalculateCaseCount(string customerName)
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web service. This is not acceptable for unit test.&quot;);
            return 42;
        }
    }
}</code></pre>
<p>Для разрыва зависимости мы добавим публичный виртуальный метод в класс с зависимостью:</p>
<pre><code>namespace ExtractAndOverrideCall.BrokenDependency
{
    public class ClassWithDependency
    {
        public bool DoSomething()
        {
            string customerName = string.Empty;
            //...
            //here we somehow retrieve and assign result to customerName
            customerName = &quot;Anton Martynenko&quot;;
            //...

            int caseCount = CalculateCaseCount(customerName);
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }

        public virtual int CalculateCaseCount(string customerName)
        {
            return CaseCountCalculator.CalculateCaseCount(customerName);
        }
    }
}</code></pre>
<p>Теперь мы можем написать тест, используя мок класса с зависимостью и подменяя во времени выполнения результаты вызова метода <code>public virtual int CalculateCaseCount(string customerName)</code>:</p>
<pre><code>#if TEST
using NUnit.Framework;
using Rhino.Mocks;

namespace ExtractAndOverrideCall.BrokenDependency
{
    [TestFixture]
    public class TestClassWithDependency
    {
        [Test]
        public void DoSomething()
        {
            var classWithDependency = MockRepository.GenerateMock&lt;ClassWithDependency&gt;();
            classWithDependency.Expect(x =&gt; x.CalculateCaseCount(Arg&lt;string&gt;.Is.Equal(&quot;Anton Martynenko&quot;)))
                .Return(31);

            bool result = classWithDependency.DoSomething();
            Assert.IsTrue(result);

            classWithDependency.VerifyAllExpectations();
        }
    }
}
#endif</code></pre>
<h3>5. Extract and override factory method</h3>
<p>Эта методика позволяет разорвать зависимости, связанные с создание экземпляров классов, основанных на промежуточных результатах выполнения метода. Посмотрим пример:</p>
<pre><code>namespace ExtractAndOverrideFactoryMethod.LegacyCode
{
    public class ClassWithDependency
    {
        public bool DoSomething()
        {
            string customerName = string.Empty;
            //...
            //here we somehow retrieve and assign result to customerName
            customerName = &quot;Anton Martynenko&quot;;
            //...
            var caseCountCalculator = new CaseCountCalculator(customerName);

            int caseCount = caseCountCalculator.CalculateCaseCount();
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }
    }
}

using System.Diagnostics;

namespace ExtractAndOverrideFactoryMethod.LegacyCode
{
    public class CaseCountCalculator
    {
        public CaseCountCalculator(string customerName)
        {
            //customerName is used for initialization
        }

        public int CalculateCaseCount()
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web service. This is not acceptable for unit test.&quot;);
            return 42;
        }
    }
}</code></pre>
<p>Экземпляр класса <code>CaseCountCalculator</code> создается на основе <code>customerName</code>, которое вычисляется в процессе выполнения метода. В этом случае мы извлечем интерфейс в классе <code>CaseCountCalculator</code> и используем паттерн «фабричный метод»:</p>
<pre><code>namespace ExtractAndOverrideFactoryMethod.BrokenDependency
{
    public interface ICaseCountCalculator
    {
        int CalculateCaseCount();
    }
}

using System.Diagnostics;

namespace ExtractAndOverrideFactoryMethod.BrokenDependency
{
    public class CaseCountCalculator : ICaseCountCalculator
    {
        public CaseCountCalculator(string customerName)
        {
            //customerName is used for initialization
        }

        public int CalculateCaseCount()
        {
            //make call to real web service
            Debug.Fail(&quot;This code makes call to real web serviсe. This is not acceptable for unit test.&quot;);
            return 42;
        }
    }
}

namespace ExtractAndOverrideFactoryMethod.BrokenDependency
{
    public class ClassWithDependency
    {
        public bool DoSomething()
        {
            string customerName = string.Empty;
            //...
            //here we somehow retrieve and assign result to customerName
            customerName = &quot;Anton Martynenko&quot;;
            //...
            var caseCountCalculator = CreateCaseCountCalculator(customerName);

            int caseCount = caseCountCalculator.CalculateCaseCount();
            if (caseCount &gt; 0)
            {
                //...
                return true;
            }
            //...
            return false;
        }

        public virtual ICaseCountCalculator CreateCaseCountCalculator(string customerName)
        {
            return new CaseCountCalculator(customerName);
        }
    }
}</code></pre>
<p>Теперь мы можем написать тест, используя мок класса с зависимостью и подменяя во времени выполнения результаты вызова метода <code>public virtual ICaseCountCalculator CreateCaseCountCalculator(string customerName)</code>:</p>
<pre><code>#if TEST
using NUnit.Framework;
using Rhino.Mocks;

namespace ExtractAndOverrideFactoryMethod.BrokenDependency
{
    [TestFixture]
    public class TestClassWithDependency
    {
        [Test]
        public void DoSomething()
        {
            var caseCountCalculator = MockRepository.GenerateMock&lt;ICaseCountCalculator&gt;();
            caseCountCalculator.Expect(x =&gt; x.CalculateCaseCount())
                .Return(31);

            var classWithDependency = MockRepository.GenerateMock&lt;ClassWithDependency&gt;();
            classWithDependency.Expect(x =&gt; x.CreateCaseCountCalculator(Arg&lt;string&gt;.Is.Equal(&quot;Anton Martynenko&quot;)))
                .Return(caseCountCalculator);

            bool result = classWithDependency.DoSomething();
            Assert.IsTrue(result);

            caseCountCalculator.VerifyAllExpectations();
            classWithDependency.VerifyAllExpectations();
        }
    }
}
#endif</code></pre>
<p>Конечно, стоит отметить, что в реальной жизни все намного сложнее, чем в примерах. Но комбинируя эти методики с остальными приемами Inversion of Control можно добиться значительного увеличения покрытия тестами и улучшения дизайна классов. Всем, кто заинтересован увеличением покрытия тестами унаследованного кода я рекомендую прочитать книгу Working Effectively with Legacy Code. Она содержит множество полезных советов для работы с тем, с чем множество из нас сталкивается каждый день =)</p>
<p>В примерах использовались:</p>
<ul>
<li>.NET 3.5</li>
<li>Rhino Mocks 3.5</li>
<li>NUnit 2.5.2.9222</li>
</ul>
<p><a href="http://www.developers.org.ua/wordpress/wp-content/uploads/2010/01/DependencyBreakingTechnics.zip">Исходники тут</a>.</p>
<br/><a href="http://www.developers.org.ua/archives/antonmartynenko/2010/01/18/tdd-dependency-breaking-technics/#ratings">Оценить статью на сайте</a> | <a href="http://www.developers.org.ua/archives/antonmartynenko/2010/01/18/tdd-dependency-breaking-technics/#comments">6 комментариев</a>]]></content:encoded>
			<wfw:commentRss>http://www.developers.org.ua/archives/antonmartynenko/2010/01/18/tdd-dependency-breaking-technics/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.developers.org.ua/archives/antonmartynenko/2010/01/18/tdd-dependency-breaking-technics/</feedburner:origLink></item>
	</channel>
</rss>
