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

<channel>
	<title>blinnov's blog &#187; applied coffee making</title>
	<atom:link href="http://www.blinnov.com/category/%d0%bf%d1%80%d0%b8%d0%ba%d0%bb%d0%b0%d0%b4%d0%bd%d0%be%d0%b5-%d0%ba%d0%be%d1%84%d0%b5%d0%b2%d0%b0%d1%80%d0%b5%d0%bd%d0%b8%d0%b5/en+ru/feed/en+ru/" rel="self" type="application/rss+xml" />
	<link>http://www.blinnov.com</link>
	<description>another brilliant mind poisoned by c++</description>
	<lastBuildDate>Fri, 10 Feb 2012 11:08:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Юнит-тестирование. Всем чтить!</title>
		<link>http://www.blinnov.com/2009/06/25/%d0%ae%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%92%d1%81%d0%b5%d0%bc-%d1%87%d1%82%d0%b8%d1%82%d1%8c/ru/</link>
		<comments>http://www.blinnov.com/2009/06/25/%d0%ae%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%92%d1%81%d0%b5%d0%bc-%d1%87%d1%82%d0%b8%d1%82%d1%8c/ru/#comments</comments>
		<pubDate>Thu, 25 Jun 2009 00:41:13 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[applied coffee making]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[Unit tests]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/2009/06/25/%d0%ae%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%92%d1%81%d0%b5%d0%bc-%d1%87%d1%82%d0%b8%d1%82%d1%8c/ru/</guid>
		<description><![CDATA[Вчера совершал уже обыденный прочес интернетов на предмет очередного факапа в MSTest. К слову, я всерьез считаю, что его нельзя использовать на критичных проектах &#8211; подставит в самый ответственный момент.
Но дело не в этом. Искал иформацию о куске говна, а нашел бриллиант. Отличная, замечательная презентация о юнит-тестах.  Здесь.
ППКС.
]]></description>
			<content:encoded><![CDATA[<p>Вчера совершал уже обыденный прочес интернетов на предмет очередного факапа в MSTest. К слову, я всерьез считаю, что его нельзя использовать на критичных проектах &#8211; подставит в самый ответственный момент.</p>
<p>Но дело не в этом. Искал иформацию о куске говна, а нашел бриллиант. Отличная, замечательная презентация о юнит-тестах.  <a href="http://www.masukomi.org/talks/unit_testing_talk_2/index.xul?data=slide_data.txt">Здесь</a>.</p>
<p>ППКС.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2009/06/25/%d0%ae%d0%bd%d0%b8%d1%82-%d1%82%d0%b5%d1%81%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%92%d1%81%d0%b5%d0%bc-%d1%87%d1%82%d0%b8%d1%82%d1%8c/ru/feed/ru/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Код: до и после н.э. Зачем на самом деле нужны юнит-тесты.</title>
		<link>http://www.blinnov.com/2009/05/11/%d0%9a%d0%be%d0%b4-%d0%b4%d0%be-%d0%b8-%d0%bf%d0%be%d1%81%d0%bb%d0%b5-%d0%bd%d1%8d-%d0%97%d0%b0%d1%87%d0%b5%d0%bc-%d0%bd%d0%b0-%d1%81%d0%b0%d0%bc%d0%be%d0%bc-%d0%b4%d0%b5%d0%bb%d0%b5-%d0%bd%d1%83/ru/</link>
		<comments>http://www.blinnov.com/2009/05/11/%d0%9a%d0%be%d0%b4-%d0%b4%d0%be-%d0%b8-%d0%bf%d0%be%d1%81%d0%bb%d0%b5-%d0%bd%d1%8d-%d0%97%d0%b0%d1%87%d0%b5%d0%bc-%d0%bd%d0%b0-%d1%81%d0%b0%d0%bc%d0%be%d0%bc-%d0%b4%d0%b5%d0%bb%d0%b5-%d0%bd%d1%83/ru/#comments</comments>
		<pubDate>Mon, 11 May 2009 04:47:25 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[applied coffee making]]></category>
		<category><![CDATA[разработка]]></category>
		<category><![CDATA[юнит-тесты]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/2009/05/11/%d0%9a%d0%be%d0%b4-%d0%b4%d0%be-%d0%b8-%d0%bf%d0%be%d1%81%d0%bb%d0%b5-%d0%bd%d1%8d-%d0%97%d0%b0%d1%87%d0%b5%d0%bc-%d0%bd%d0%b0-%d1%81%d0%b0%d0%bc%d0%be%d0%bc-%d0%b4%d0%b5%d0%bb%d0%b5-%d0%bd%d1%83/ru/</guid>
		<description><![CDATA[В истории кода текущего проекта обнаружился переломный момент, когда с ним случилось нечто страшное интересное. Это сподвигло меня написать эту, и, наверное, несколько последующих статей, посвященных юнит-тестированию.
БОльшая половина кода нашего проекта на первый взгляд выглядит очень хардкорно. Если опустить пару моментов, где я вдоволь оттянулся с белой и черной шаблонной магией, то бросится в глаза, [...]]]></description>
			<content:encoded><![CDATA[<p>В истории кода текущего проекта обнаружился переломный момент, когда с ним случилось нечто <strike>страшное</strike> интересное. Это сподвигло меня написать эту, и, наверное, несколько последующих статей, посвященных юнит-тестированию.</p>
<p>Б<strong>О</strong>льшая половина кода нашего проекта на первый взгляд выглядит очень хардкорно. Если опустить пару моментов, где я вдоволь оттянулся с белой и черной шаблонной магией, то бросится в глаза, что остальная часть этой половины идет вразрез с заветами секты &#8220;ООП&#8221;  и ее течения &#8220;многоэтажные иерархии классов&#8221; (да, я редко сажаю леса вроде приведенного на картинке ниже). В глаза бросится, да не долетит, а упадет и стечет (может быть даже прямо в ботинки).</p>
<p><a href="http://www.blinnov.com/wp-content/uploads/2009/05/class-hierarchy.png" title="Многоэтажная иерархия"><img src="http://www.blinnov.com/wp-content/uploads/2009/05/class-hierarchy.png" alt="Многоэтажная иерархия" width="540" /></a><br />
<span id="more-349"></span></p>
<p>При ближайшем рассмотрении код оказывается простым как пробка, понятным как дважды два и гибким, как резинка от трусов. Что-то нужно изменить? Нет проблем. Изволите перламутровые пуговицы вместо молнии? Пожалуйста. Что? Хотите декоративные пуговицы, а ширинку все же на молнии? Проще простого. И так далее. Причем для проведения хирургической операции по пересадки молнии не приходится укорачивать рукава и заодно перестраивать ещё и платяной шкаф, как это часто случается в индустрии программного обеспечения. Кстати, перекраска последнего по желанию заказчика (любой каприз за Ваши деньги!) тоже вовсе не изменяет цвет костюмов, в нем висящих. Код-как детали из детского конструктора, строй из них все, что хочешь.</p>
<p>Другая, хоть и меньшая, но не менее важная половина кода &#8211; полная противоположность всему вышесказанному. Вроде изящная структура интерфейсов и классов отлично видна даже в перевернутый бинокль (смотри картинку выше), но стоит посмотреть невооруженным глазом, как уши сами, опасаясь неминуемых последствий, начинают инстинктивно сворачиваться в трубочку.  Местами этот спагетти-код настолько суров, что если потянуть за макаронину в своей тарелке, мясные тефтельки в тарелке у клиента воооон за тем столиком придут в движение и начнут водить хороводы. Если сравнить с более материальным миром, то попытка что-нибудь исправить в таком коде напоминает процесс штопания дырки в носке, который по непонятной причине неизменно заканчивается пришитым к ширинке рукавом майки (откуда у майки взялся рукав, лучше даже и не спрашивать, я давно забросил все попытки выяснить это). Причем после отпарывания рукава от ширинки обнаруживается, что до сих пор бывшими модельными ботинки каким-то образом превратились в ласты 47 размера, а стильные солнечные очки &#8211; в маску сварщика.</p>
<p>В общем, несмотря на кажущуюся структурированность,  код отдельных компонентов имеет очень жуткую и совершенно неявную связность и практически не поддается модификации без применения тяжелой артиллерии класса &#8220;.. до основанья, а затем&#8230;&#8221;.</p>
<p>Самое замечательное во всей этой истории то, что разница между кодом, который лучше не трогать и кодом, с которым очень легко делать все, что угодно, очень уж очевидна. Порой кажется, что кто-то где-то провел границу в коде и сказал &#8220;с этого момента прекращаем гнать лажу по-старому и начинаем по-новому&#8221;.</p>
<p>Это мой первый проект  за последние несколько лет, где практика юнит-тестирования и частично TTD были внедрены ровно на полпути. В моей практике это первый случай, где преимущества правильного использования юнит-тестирования не просто говорят сами за себя, а буквально кричат изо всех окон Студии, попутно постукивая шарахающихся зевак деревянной киянкой по голове.</p>
<p>Итак, б<strong>о</strong>льшая половина кода в проекте была написана после внедрения технологии юнит-тестирования. Поначалу произведя эффект разорвавшейся клизмы, что всегда бывает в компаниях, где думают, что юнит-тесты &#8211; это <em>исключительно </em>средство <em>тестирования </em>кода (что есть неправда &#8211; это в первую очередь <em>технология</em> разработки), результат внедрения техники превзошел экономический эффект от использования технологии &#8220;сборка трезвым&#8221; на предприятии по производству яиц Фаберже с часовым механизмом. Не буду говорить о том, что подавляющее большинство найденных багов относится как раз к старой половине, при написании которой, похоже, руководствовались принципом &#8220;некогда фигней разной и тестами в частности заниматься, копать надо&#8221;, это мелочи. Тесты совсем не панацея от багов, хотя и помогают асимптотически устремить их число к нулю.</p>
<p>На самом деле, основной эффект от использования тестов проявился сейчас, спустя почти полгода после окончания разработки. Проект уже вышел и находится в стадии исправления и добавления фич. Ну, вы понимаете, ст<strong>о</strong>ит заказчику получить то, что он, собственно и заказывал, так начинается &#8220;а почему это работает так, а не эдак? Да, мы думали, что оно будет работать именно так, почему вы нам не сказали, ой, разве сказали, а когда, ой, в спеке написано, так мы ж его не читали, а почему вы нам не сказали, что его нужно читать, но все равно, сделайте нам ништяк, да так, чтобы нам ничего за это не было&#8221;. Так вот, если исправление или новая фича затрагивает новый код, то никаких проблем &#8211; из самого кода очевидно, что, где и как нужно изменить, а полтысячи разных тестов добавляют уверенности в том, что система не пойдет на йух после добавления новой фичи в ядро.</p>
<p>Совершенно другая история с кодом старым. К счастью, он достаточно прозрачен, и <em>обычно </em>не нужно производить археологических раскопок для поиска того места, которое нужно изменить. К несчастью, этот мир подчиняется <a href="http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%BA%D0%BE%D0%BD_%D0%9C%D1%91%D1%80%D1%84%D0%B8">закону Мерфи</a>, поэтому нужно посмотреть внимательно на предыдущее предложение, уделив особое внимание словам &#8220;обычно не нужно&#8221;, понять, что к нашему случаю &#8220;обычно&#8221; и &#8220;не&#8221; не относятся  и приготовиться к длительному туплению в монитор и потеряным человеко-годам в отладчике. В полном соответствии с этим законом, любые багфиксы или фичи приходятся на код, который непрозрачен настолько, что любые изменения в нем очень, наверное, похожи на разминирование минного поля вслепую. В целях обеспечения безопасности на производстве приходится одевать каску, залезать в окоп и оттуда уже запускать систему после любого изменения. Побочные эффекты постоянно вылезают феерверком там, где их ждали меньше всего. Кстати, как ни странно, тот факт, что половина кода все же покрыта тестами, позволяет отловить часть таких скрытых приколов.</p>
<p>Впрочем, это довольно типичная ситуация. Разработчики потратили время, кофе и пончики, разрабатывая и согласовывая интерфейсы и то, что называется &#8220;Top level architecture&#8221;, и придумали действительно очень красивую архитектуру. Но как только принялись собственно за кодирование, напрочь забыли о том, что собственно дизайн модулей, интерфейсы реализующих, тоже хорошо бы придумать и потом поддерживать. Дальнейшая разработка напоминает скорее постройку забора бойцами Советской Армии. Бери больше, кидай дальше, пока летит &#8211; отдыхай.</p>
<p>Когда разработка ведется с использованием юнит-тестирования, разработчик стремится написать тест для любой маленькой фигни. Это накладывает серьезнейший отпечаток на дизайн модуля, так как код в должен быть тестируемый в первую очередь. Значит, прежде чем бросаться грудью на амбразуры, програмиист должен подумать, а как, собственно, он собирается проверить, что этот кусок кода работает именно так, как задумано. А так как программист это существо, мозговой деятельности обученное,  тут и начинаются интересные вещи. Первыми исчезают монстроидальные классы вида &#8220;универсальный всемогутор&#8221; с названием &#8220;менеджер чего-то там&#8221; и иже с ними, вместо этого появляется десяток-другой классов поменьше или вообще функций, каждая из которых решает какую-то отдельную небольшую задачу, не заморачиваясь о существовании других классов, функций и типов данных, ей неинтересных. Соответственно, твердое &#8220;нет&#8221; говорится процессам, где состояние объекта меняется неявно и незаметно. Функции, в которые раньше передавались огромные структуры для работы лишь с одним из их полей, начинают принимать только то самое поле. Внутренние и неявные связи исчезют на глазах. В следующий момент обнаруживается, что многие из мелких функций и классов теперь можно и нужно использовать в других местах проекта. Потом, при написании теста для отдельного класса обнаруживается, что для его удобного использования нужно применить <a href="http://en.wikipedia.org/wiki/Inversion_of_control">Inversion of control</a>, что и будет вскоре сделано, заодно решив еще целую кучу намечающихся проблем.</p>
<p><strong>Короче говоря, цель юнит-тестирования &#8211; помочь программисту начать выступать не только и не столько в роли творца шедевра, но первым и самым главным пользователем и критиком своего же кода.</strong>  &#8220;Плохой&#8221; код, то есть код, который трудно стыковать с другими модулями, очень сложно, а то и вообще невозможно тестировать, в то время как код, для которого написан и выполняется тест, гарантирует как минимум, что он стыкуется с другим относительно простым кодом &#8211; кодом теста &#8211; и его уже точно один раз (а может и больше) использовали и проверили в деле. Это помогает программисту увидеть слабости кода и изолировать потенциальные проблемы интеграции задолго до того, как потенциальные проблемы превратятся в проблемы реальные.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2009/05/11/%d0%9a%d0%be%d0%b4-%d0%b4%d0%be-%d0%b8-%d0%bf%d0%be%d1%81%d0%bb%d0%b5-%d0%bd%d1%8d-%d0%97%d0%b0%d1%87%d0%b5%d0%bc-%d0%bd%d0%b0-%d1%81%d0%b0%d0%bc%d0%be%d0%bc-%d0%b4%d0%b5%d0%bb%d0%b5-%d0%bd%d1%83/ru/feed/ru/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Useful C++ template magic. Hiding nasty global static&#8217;s</title>
		<link>http://www.blinnov.com/2009/01/06/useful-template-magic-hiding-nasty-global-statics/en/</link>
		<comments>http://www.blinnov.com/2009/01/06/useful-template-magic-hiding-nasty-global-statics/en/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 11:16:40 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[applied coffee making]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/2009/01/06/useful-template-magic-hiding-nasty-global-statics/en/</guid>
		<description><![CDATA[This article explains a very easy technique to get around "nasty global variable" problem using templates.]]></description>
			<content:encoded><![CDATA[<p>In C++, often there is a need to provide and support single instance of certain class, accessible on demand from anywhere in the program. That is encyclopedic example given in many books promoting <strong>singleton </strong>pattern. For instance, if your program has a log file, it is strongly recommended that you make a class that encapsulates all logging and make it singleton. This approach, without any doubts, is much much better than making global static instance of the logger and then referring to it from whatever you need as it reduces number of cross-dependencies, an issue that stays among the most bad techniques making code less maintainable.</p>
<p>This is easy to understand &#8211; while there is nothing wrong in static variable, even in global static variable, we must ensure that it is initialized before it is used first, which is especially important if the object has to be created dynamically. And this is the problem Singleton pattern solves.</p>
<p>Take the example</p>
<pre name="code" class="c++">
// SomeSourceFile.h
#include "CoffeePlantation.h"
static CoffeePlantation g_Plantation;

// SomeSourceFile.cpp
#include "SomeSourceFile.h"
// Initialize the instance
g_Plantation = CoffeePlantation();</pre>
<p><span id="more-276"></span><br />
Note &#8211; coffee plantation object is created on a stack. Plantation&#8217;s constructor will be called before main() and, presumably, any other code that uses g_Plantation. But in order to use this single plantation, you&#8217;ll must include this &#8220;SomeSourceFile.h&#8221; into every file when it is or may be referred from. Moreover, once you added more global statics, you may get lost is you sources as you&#8217;ll need to keep in mind which header declares what variable. Having single common header file may help a little, though, but not always.</p>
<p>From the other hand, there are still heaps of cases when you&#8217;d rather use global static variable for certain need. For instance, pattern &#8220;State&#8221; (see &#8220;Design patterns&#8221; by GoF) assumes that all object represent states have to implement singleton pattern. But at the closer look you may realize that it makes code unnecessary complex and bulky &#8211; state machine of that kind assumes that all transitions and states are already known, they don&#8217;t change in runtime and can be created once-and-for-all, in other words, they must be static.</p>
<p>Right, how we handle this situation then?</p>
<p>Well, it&#8217;s about the time when &#8220;template&#8221; word, so many developers are still afraid of, should be addressed. C++ template is a great way to ask compiler to generate as many synthetic data types as we want exactly when we need them. For instance, vector&lt;char&gt; and vector&lt;unsigned char&gt; are two different data types. Which meaning does it have for our task?</p>
<p>Check this out:</p>
<pre name="code" class="c++">
// file name: StaticInstance.htemplate &lt;class T&gt;
class  tStaticInstance
{
public:
        static T* GetInstance();
private:
        static T m_Instance;
}

template &lt;class T&gt;
T tStaticInstance&lt;T&gt;::m_Instance = T();</pre>
<p>That&#8217;s it. That&#8217;s really all we need to hide ugly global static behind nice looking fence. Now, instead of declaring static variable in designated header and then pushing it *.h around the project, just do this:</p>
<pre name="code" class="c++">
#include "StaticInstance.h"/// somewhere somewhentStaticInstance&lt;MyConcreteType&gt;::GetInstance()-&gt;SomeMethod();

tStaticInstance&lt;OtherType&gt;::GetInstance()-&gt;SomeMethod();</pre>
<p>This code may look a bit scary, but it solves the whole bunch of problems:</p>
<ul>
<li>There is no need to modify either of MyConcreteType or OtherType to implement singleton functionality they may not need generally.</li>
<li>Global static variable can be &#8220;created&#8221; from any place in your program without the need of declaring it anywhere else</li>
<li>Does not have singleton&#8217;s weaknesses</li>
<li>This expression clearly explains that in this particular place we wanted to deal with single global instance of the class. There are quite a few cases when it may be useful</li>
<li>Code is very simple</li>
<li>Static objects are created automatically and only if they are used. Unlike the case with implicit static declaration, it is now impossible to declare an object that is never used.</li>
</ul>
<p>Of course, there is a price to pay:</p>
<ul>
<li>The uniqueness of the instance is only guaranteed within single binary and we fully rely on modern compiler and linker</li>
<li>Object gets created once a construction with tStaticInstance<t>::GetInstance() appears in the code, even if that code is never going to be used (which is quite bad by itself) or gets called once in a blue moon.</t></li>
</ul>
<p>It is also not idiot-proof:</p>
<pre name="code" class="c++">
MyType pInstance* = tStaticInstance&lt;MyConcreteType&gt;::GetInstance();

delete pInstance;     // Something bad happens here</pre>
<p>That delete will lead to crash, but it will be trivial to track down and fix. You write unit test for you code, aren&#8217;t you?</p>
<p>I have been using this pattern in several projects and it works just fine, assuming that it is intended for occasions where your code is allowed to know that is deals with static instance of the class.</p>
<p>Having said that, this is how I would deal with my coffee plantation:</p>
<pre name="code" class="c++">
// CoffeeHarvester.h
#include "CoffeePlantation.h"
#include "StaticInstance.h"
// ...
tStaticInstance&lt;CoffeePlantation&gt;::GetInstance()-&gt;CheckIfCoffeeRipeEnough();</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2009/01/06/useful-template-magic-hiding-nasty-global-statics/en/feed/en/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

