<?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; Software design</title>
	<atom:link href="http://www.blinnov.com/category/%d0%a0%d0%b0%d0%b1%d0%be%d1%82%d0%b0/%d0%94%d0%b8%d0%b7%d0%b0%d0%b9%d0%bd-%d0%9f%d0%9e/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/2012/01/27/%d0%98%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%8f-%d1%8f%d0%b7%d1%8b%d0%ba%d0%be%d0%b2-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f/ru/</link>
		<comments>http://www.blinnov.com/2012/01/27/%d0%98%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%8f-%d1%8f%d0%b7%d1%8b%d0%ba%d0%be%d0%b2-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f/ru/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 00:24:33 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1517</guid>
		<description><![CDATA[Краткая, неполная и практически полностью неправильная. Здесь.
1972 &#8211; Dennis Ritchie invents a powerful gun that shoots both forward  and backward simultaneously.  Not satisfied with the number of deaths  and permanent maimings from that invention he invents C and Unix.
]]></description>
			<content:encoded><![CDATA[<p>Краткая, неполная и практически полностью неправильная. <a href="http://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html">Здесь</a>.</p>
<blockquote><p>1972 &#8211; Dennis Ritchie invents a powerful gun that shoots both forward  and backward simultaneously.  Not satisfied with the number of deaths  and permanent maimings from that invention he invents C and Unix.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2012/01/27/%d0%98%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%8f-%d1%8f%d0%b7%d1%8b%d0%ba%d0%be%d0%b2-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f/ru/feed/ru/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Сипласпласное</title>
		<link>http://www.blinnov.com/2011/07/25/%d0%a1%d0%b8%d0%bf%d0%bb%d0%b0%d1%81%d0%bf%d0%bb%d0%b0%d1%81%d0%bd%d0%be%d0%b5/ru/</link>
		<comments>http://www.blinnov.com/2011/07/25/%d0%a1%d0%b8%d0%bf%d0%bb%d0%b0%d1%81%d0%bf%d0%bb%d0%b0%d1%81%d0%bd%d0%be%d0%b5/ru/#comments</comments>
		<pubDate>Mon, 25 Jul 2011 06:40:02 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1421</guid>
		<description><![CDATA[Сегодня провели с коллегой полдня в пространных рассуждениях о многопоточности и с чем ее едят.
Езь код
std::map&#60;int, bool&#62; myMap;

// Map is filled in with some data here

void SetValue(int key, bool newValue)
{
myMap[key] = newValue;
}

Небольшие ограничения: мап заполняется значениями только один раз, при запуске программы, гарантированно однопоточно. После инициализации SetValue может вызываться из разных потоков для разных ключей [...]]]></description>
			<content:encoded><![CDATA[<p>Сегодня провели с коллегой полдня в пространных рассуждениях о многопоточности и с чем ее едят.</p>
<p>Езь код</p>
<pre class="brush:cpp">std::map&lt;int, bool&gt; myMap;

// Map is filled in with some data here

void SetValue(int key, bool newValue)
{
myMap[key] = newValue;
}
</pre>
<p style="padding-left: 30px;">Небольшие ограничения: мап заполняется значениями только один раз, при запуске программы, гарантированно однопоточно. После инициализации SetValue может вызываться из разных потоков для разных ключей (то есть гонок по одному ключу быть не может). Кроме того, вызов SetValue с ключом, которого в мапе нет, исключен (т.е. невозможен).</p>
<p>С моей точки зрения, с <em>данными допущениями</em> код SetValue можно считать потокобезопасным (присвоение bool считаем атомарной операцией, не углубляясь особенно в детали). Конечно, во всех этих допущениях просвечивает некоторое джидайство (к примеру, operator[] у мапа вообще-то для вставки используется), но если их принять, то никакого криминала в подобном грубом обращении с этим STL контейнером не будет.</p>
<p>Моя аргументация тут такова &#8211; SetValue() модифицирует только значения, не изменяя состояние контейнера, поэтому для обеспечения потокобезопасности кода в данном конкретном случае необходимо и достаточно обеспечить потокобезопасность оператора присвоения для типа значения. Контр-аргумент коллеги тоже имеет под собой все основания, ведь нигде прямо не написано, что присвоение элементу мапа нового значения &#8211; операция потокобезопасное. Я парировал тем, что в MSDN четко описаны случаи инвалидации итераторов, в число которых изменение уже хранимого значения без вставки или удаления нового ключа никаким боком не входит.</p>
<p>Впрочем, мы джедаи опытные и на личности не переходим. Но в итоге трехчасовой беседы с отсылкой к исходникам STL в коде SetValue появился таки появился лок с моим каментом &#8220;Меня заставили&#8221;.</p>
<p>Я не отрицаю, что в общем случае так делать не надо. Бо и правда, первый же залетевший дятел завтра заменит мап на какую другую неведому зверюшку и все развалится при первом же неосторожном чихе. Или какой юный падаван проигнорирует жЫрные ворнинги в каментах (а ворнинги там знатные &#8211; я, в отличие от, код без комментариев не пишу) выкорчует код и без изменений применит там, где <em>не надо</em>, в результате чего и огребет как тумаков от обладателей синего меча, так и поджопников &#8211; от владельцев красного, плюс еще щелбанов от юзверей на закуску.</p>
<p>Но в том-то и дело, что в данном конкретном случае речь шла не об абстрактном алгоритме в вакууме, а о весьма конкретном случае, когда мы уже под микроскопом рассматривали логи профайлера в надежде выжать из системы еще кусочек перформанса.</p>
<p>Вопрос  &#8211; я и правда провафлил какое-нибудь условие или мне стоило стоять на своем до конца?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2011/07/25/%d0%a1%d0%b8%d0%bf%d0%bb%d0%b0%d1%81%d0%bf%d0%bb%d0%b0%d1%81%d0%bd%d0%be%d0%b5/ru/feed/ru/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Шок и трепет</title>
		<link>http://www.blinnov.com/2011/06/29/%d0%a8%d0%be%d0%ba-%d0%b8-%d1%82%d1%80%d0%b5%d0%bf%d0%b5%d1%82/ru/</link>
		<comments>http://www.blinnov.com/2011/06/29/%d0%a8%d0%be%d0%ba-%d0%b8-%d1%82%d1%80%d0%b5%d0%bf%d0%b5%d1%82/ru/#comments</comments>
		<pubDate>Wed, 29 Jun 2011 02:12:16 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1406</guid>
		<description><![CDATA[Android,  оказывается, не поддерживает Ad-hoc wireless networks. Причем, вовсе не потому, что эту фичу решили не реализовывать &#8211; ее, напротив, выпилили в версии 2.2
Это, доложу вам, полный пиздец.  Кажется, удельная масса кретинов в гугле, как и в большинстве крупных компаний, перевалила критическую.
Ну и как дальше жыдь, я вас спрашиваю?
]]></description>
			<content:encoded><![CDATA[<p>Android,  оказывается, не поддерживает Ad-hoc wireless networks. Причем, вовсе не потому, что эту фичу решили не реализовывать &#8211; ее, напротив, выпилили в версии 2.2</p>
<p>Это, доложу вам, полный пиздец.  Кажется, удельная масса кретинов в гугле, как и в большинстве крупных компаний, перевалила критическую.</p>
<p>Ну и как дальше жыдь, я вас спрашиваю?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2011/06/29/%d0%a8%d0%be%d0%ba-%d0%b8-%d1%82%d1%80%d0%b5%d0%bf%d0%b5%d1%82/ru/feed/ru/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Теория и практика макаронолитейного дела</title>
		<link>http://www.blinnov.com/2011/03/22/%d0%a2%d0%b5%d0%be%d1%80%d0%b8%d1%8f-%d0%b8-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0-%d0%bc%d0%b0%d0%ba%d0%b0%d1%80%d0%be%d0%bd%d0%be%d0%bb%d0%b8%d1%82%d0%b5%d0%b9%d0%bd%d0%be%d0%b3%d0%be/ru/</link>
		<comments>http://www.blinnov.com/2011/03/22/%d0%a2%d0%b5%d0%be%d1%80%d0%b8%d1%8f-%d0%b8-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0-%d0%bc%d0%b0%d0%ba%d0%b0%d1%80%d0%be%d0%bd%d0%be%d0%bb%d0%b8%d1%82%d0%b5%d0%b9%d0%bd%d0%be%d0%b3%d0%be/ru/#comments</comments>
		<pubDate>Tue, 22 Mar 2011 01:06:09 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1370</guid>
		<description><![CDATA[Наверное, однажды я напишу книгу. Это будет руководство о том, как писать самый страшный, ужасный и неподдерживаемый код.
Вот искренне не понимаю, чем может думать человек, который в новоиспеченный класс вводит зависимость от другого очень толстого объекта при том, что новому классу требуется лишь знать значение одного поля этого объекта. При том, что это поле в [...]]]></description>
			<content:encoded><![CDATA[<p>Наверное, однажды я напишу книгу. Это будет руководство о том, как писать самый страшный, ужасный и неподдерживаемый код.</p>
<p>Вот искренне не понимаю, чем может думать человек, который в новоиспеченный класс вводит зависимость от другого очень толстого объекта при том, что новому классу требуется лишь знать значение одного поля этого объекта. При том, что это поле в рантайме измениться не может.</p>
<pre class="brush:cpp">class MyCoolClass
{
private:
BigFatObject* m_pOtherObject;
public:
MyCoolClass(BigFatObject* _pPtr):
m_pOtherObject(_pPtr)
{
}

void DoSmth()
{
std::string sName = m_pOtherObject-&gt;GetName();
// do smth
}

void DoMoreThings()
{
std::string sName = m_pOtherObject-&gt;GetName();
// do smth
}

// and other methods. All like this.

}</pre>
<p>Вот такого вот горбатого лепят сплошь и рядом. И даже искры сомнения о том, что тут что-то не так, не проскакивает. Зато другим людям, которым посчастливится изменять BigFatObject или которые захотят переиспользовать код класса в другом месте, придется метать гром и молнии.</p>
<p>Вот объясните мне, они действительно просто не понимают, что тут нужно было передать в конструктор строку, вместо того, чтобы пихать указатель, вводя совершенно ненужные зависимости, делая при этом юнит-тестирование пыткой и превращая будущий рефакторинг в ходьбу по минному полю, заодно добавляя вопрос в времени жизни объектов?  Или же это банальное вредительство?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2011/03/22/%d0%a2%d0%b5%d0%be%d1%80%d0%b8%d1%8f-%d0%b8-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0-%d0%bc%d0%b0%d0%ba%d0%b0%d1%80%d0%be%d0%bd%d0%be%d0%bb%d0%b8%d1%82%d0%b5%d0%b9%d0%bd%d0%be%d0%b3%d0%be/ru/feed/ru/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Would you mind getting real or why online С++ tests suck</title>
		<link>http://www.blinnov.com/2010/10/27/would-you-mind-getting-real-or-why-online-%d0%a1-tests-suck/en/</link>
		<comments>http://www.blinnov.com/2010/10/27/would-you-mind-getting-real-or-why-online-%d0%a1-tests-suck/en/#comments</comments>
		<pubDate>Wed, 27 Oct 2010 14:54:04 +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[interviews]]></category>
		<category><![CDATA[job]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1177</guid>
		<description><![CDATA[Dear Madam/Sir,
I appreciate you going into the trouble actually visiting this page.  This post represents this blog owner&#8217;s point of view on so-called &#8220;Online C++ tests&#8221; that are used by recruitment agents to select candidates and explains why its author does not take any of these tests anymore. The sole purpose of the post is [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: left; font-size: x-small;">Dear Madam/Sir,</p>
<p style="text-align: left; font-size: x-small;">I appreciate you going into the trouble actually visiting this page.  This post represents this blog owner&#8217;s point of view on so-called &#8220;Online C++ tests&#8221; that are used by recruitment agents to select candidates and explains why its author does not take any of these tests anymore. The sole purpose of the post is to be referred to when he is asked to sit one of these to save him the time explaining his position on this issue over and over again. By writing this post, the author did not intend to insult anyone nor pay revenge of any kind to anyone.</p>
<p>Almost every good software developer can find themselves discussing a new exciting career™ opportunity with the potential employer or their agent. Nine from ten, the candidate will be asked to sit a test. A very easy one, should not be too much trouble, person of such experience will not have any problems completing it in no time, they are told. And this is what is terribly wrong about it. You will have problems. No matter how good you are.</p>
<p>I agree that some initial screening may be required. For example, company needs a junior software developer and they need to be sure that candidates understand basic concepts of certain programming language. In this case test will help. It simply must be <em>well prepared, 100% accurate, 100% correct, 100% meaningful</em> and also short, if not too much trouble. The problem is that most of the tests out there don&#8217;t have any of this characteristics. The bigger problem is that they are usually put together by those who have never worked in the software development. And the killer problem is that these tests are filled with inconsistencies, discrepancies or simply full of errors (I wanted to use more colorful language here, but this post is going to be a part of my CV, so I better don&#8217;t).</p>
<p>About a year ago I was asked to sit an online C++ test.  I had no objections then. I also was interested in the position. The first question was quite obvious. The second had 4 answers and three of them were correct, but according to the question, only one of them was supposed to be correct. I lost all the interest momentarily. I wanted to stop it right then, but I decided to continue. I don&#8217;t regret. At least, now I have the proof how bad these tests are . That&#8217;s what question number 4 was:</p>
<p><span id="more-1177"></span></p>
<p style="text-align: left;"><img class="aligncenter size-full wp-image-1184" title="C++ test - question is incorrect" src="http://www.blinnov.com/wp-content/plugins/image-shadow/cache/1ed293764c9372f59bcec0e790535302.jpg" alt="" width="620" height="517" /></p>
<p style="text-align: left;">Anyone who knows C++ will see immediately that everything here is totally screwed. At first, Box::returnpointer() returns <em>reference</em>. But the question is &#8220;how to return the address&#8221;, which means <em>pointer</em>. I don&#8217;t know how this rubbish got into the test and I don&#8217;t really care, the fact is that the person who really knows C++ will never ever mistake reference for pointer and vice versa. The question makes no sense nor any of the answers is correct.</p>
<p style="text-align: left;">The next question brought me a joy of guessing what did they really had in mind. The question that came after that, was a masterpiece. Obviously, somebody simply copied and paste the code directly into HTML, so all template definitions simply disappeared.</p>
<p style="text-align: left;"><img class="aligncenter size-full wp-image-1186" title="C++ tests suck" src="http://www.blinnov.com/wp-content/plugins/image-shadow/cache/edf481649b87db4e8dd0a7f1c54a0e5c.jpg" alt="" width="620" height="451" /></p>
<p style="text-align: left;">It&#8217;s so screwed I don&#8217;t even want to explain anything. Of course, this is a technical error, but what I was supposed to do? Made a guess? Click randomly? Thank you very much, If I wanted to gamble, I&#8217;d go and play pokies.</p>
<p class="brush:cpp">In fact, I did a nice thing. I took those pictures, randomly clicked through the rest of questions (what was the point answering if the test was already compromised?), expectantly failing it. Then I went into the trouble of putting a big email together with those &#8220;screen shots&#8221; and detailed explanations what was wrong with the test. Surprisingly enough, I was invited to an interview, but at the end of the day it did not work out, but it is an entirely different story.</p>
<p style="text-align: left;">You may disagree with me &#8211; there are a lot of tests that are checked thoroughly. And you will be correct, well known Brainbench tests don&#8217;t usually have stuff-ups like above in them. But they are still stuffed, just in different way. They are still made by people who obviously don&#8217;t quite understand what software engineer job is about, and half of questions have no relations to how programming language is used in the real life. The second half of Brainbench questions are &#8220;find what&#8217;s wrong with this piece of shit code&#8221;. As a developer, I have to deal with not-so-great code on a regular basis, but what you&#8217;ll see in BB tests is beyond any reasonable limits. When commercial software is considered, such code just does not get checked in into the repository. The code review simply stops at the sight of it and the author gets a chance to get rid of it. To top it off, BB has a bad habit of giving code snippets in images. In which code is printed using proportional font. Like this:</p>
<p style="font-family: times;">int z= (*(pPtr))(i+m/k);</p>
<p style="text-align: left;">In programming, any single symbol matters. That&#8217;s why all programming IDEs use monospace fonts:</p>
<pre class="brush:cpp">int z= (*(pPtr))(i+m/k);</pre>
<p>The first snippet is much harder to read. Also, it is not the case of &#8220;it is just the test, it worth the effort, so stop bitching and read the bloody code&#8221;. It does not worth the effort. In the industry, only monospace fonts are used for the code. Every symbol matters, therefore all symbols must be of exactly the same width. To read the code the is printed in proportional font, you really have to look so hard it hurts.</p>
<p>I should also mention meaningless questions. Such as when you are asked something like &#8220;what is the standard name for basic_filebuf&lt;char&gt;&#8221;. No C++ guru will be able to answer this, except by accident. As it is not something you have to remember to be a C++ programmer. And chances are, you&#8217;ll never have deal with that basic_filebuf template.</p>
<p>There also is another type of questions that their authors tried used to evaluate something completely irrelevant. For example, some time ago I did that BB test and I was asked the question above. It was the only question (of 40) that had any C++ templates in them. At the end of the test I was told that I did not have enough competence in templates. How could they figure this out I don&#8217;t know? Trust me, I know C++ templates. My colleagues sometimes tell me I know them a little bit too well.</p>
<p>I could go for ages (I did not even mention virtual inheritance questions yet!), but I think I have already said enough. It&#8217;s time to summarize.</p>
<p>Imagine yourself in my shoes. You are not a graduate. You are a professional that uses this programming language since you can&#8217;t even remember when. You speak that language. You know its tricks. You know its best practices. And you are required to take a test, which:</p>
<ul>
<li>Created by people that are far less competent then you are</li>
<li>Created by people that, probably, never worked in software development</li>
<li>Has no relation to the real job you are doing <em>now</em></li>
<li>Is unrelated to what you will be doing on <em>that </em>job</li>
<li>Is inconclusive</li>
<li>Contains errors in either questions or answers. Or both</li>
<li>Has bugs in implementation</li>
</ul>
<p>All it means that you have pretty good chances of failing this test, no matter how brilliant you are. Simply because you click on the answer that you know is correct, but test thought it was incorrect.</p>
<p>Your time is wasted, and your application is marked &#8220;incompetent in C++&#8221;. And this mark is set by someone who doesn&#8217;t event know the difference between a reference and a pointer! And, in most cases, you have no chances to prove your innocence, because nobody listens to you.</p>
<p>I can&#8217;t speak up for everyone, but I don&#8217;t want to risk my reputation in that way. I don&#8217;t want to watch my experience and my knowledge being flushed down the toilet. This is why I don&#8217;t take any online tests.</p>
<p>If you are an agent who get here by the link in my resume, please note: if sitting such test is your requirement or your customer requires it, I will not be interested. I know my business. The software I developed works in a lot of places. It is unlikely that you will ever notice  it, but you have pretty good chances of being served by some of the systems I build. I won&#8217;t name them here (you have my resume, it is all there). I am not afraid of challenge. I love challenge. I desire challenges. That&#8217;s what I love most in my work. But the test that you are likely to offer is not a challenge. It&#8217;s a Russian roulette. And I won&#8217;t play it. Chances of losing playing it do not depend on how good I am, and I do not take such risks. I better lose this exciting opportunity this time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2010/10/27/would-you-mind-getting-real-or-why-online-%d0%a1-tests-suck/en/feed/en/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Рабоче-крестьянские зарисовки</title>
		<link>http://www.blinnov.com/2010/10/21/%d0%a0%d0%b0%d0%b1%d0%be%d1%87%d0%b5-%d0%ba%d1%80%d0%b5%d1%81%d1%82%d1%8c%d1%8f%d0%bd%d1%81%d0%ba%d0%b8%d0%b5-%d0%b7%d0%b0%d1%80%d0%b8%d1%81%d0%be%d0%b2%d0%ba%d0%b8/ru/</link>
		<comments>http://www.blinnov.com/2010/10/21/%d0%a0%d0%b0%d0%b1%d0%be%d1%87%d0%b5-%d0%ba%d1%80%d0%b5%d1%81%d1%82%d1%8c%d1%8f%d0%bd%d1%81%d0%ba%d0%b8%d0%b5-%d0%b7%d0%b0%d1%80%d0%b8%d1%81%d0%be%d0%b2%d0%ba%d0%b8/ru/#comments</comments>
		<pubDate>Thu, 21 Oct 2010 12:38:16 +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[software development]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1161</guid>
		<description><![CDATA[Совершенно случайно попала недавно в руки широко известная в узких кругах книга &#8220;Как передвинуть гору Фудзи&#8221;.  Совершенно случайно я ее прочитал и с сожалением отметил, что до меня эту самую книгу прочитало гораздо большее число человек, чем следовало бы. Причем если бы ее читали только те, кому следовало бы, я бы и слова не сказал, [...]]]></description>
			<content:encoded><![CDATA[<p>Совершенно случайно попала недавно в руки широко известная в узких кругах книга &#8220;Как передвинуть гору Фудзи&#8221;.  Совершенно случайно я ее прочитал и с сожалением отметил, что до меня эту самую книгу прочитало гораздо большее число человек, чем <em>следовало бы</em>. Причем если бы ее читали только те, кому <em>следовало бы</em>, я бы и слова не сказал, но беда состоит в том, что, судя по устоявшимся в индустрии трендам, книжка эта регулярно попадает в потные ручонки таких оригиналов, которым подобная литература противопоказана по причине клинического капеца головного мозга.</p>
<p><span id="more-1161"></span></p>
<p>Пару дней назад на <a href="http://www.rsdn.ru">кывте </a>случился очередной срач о собеседованиях и обязательно присущих им горах фудзи, гномах с людоедами и прочими мешками разнокалиберных шаров. Дескать, если не знаешь, как взвесить Боинг &#8211; то ты вообще не программист, а совсем даже лох педальный и все в таком духе.</p>
<p>Посмотрел я на этот срач свысока, вспомнил <span style="text-decoration: line-through;">острые </span>тупые ощущения от не очень давнего хождения по собеседованиям, оглянулся на свой опыт и с сожалением отметил, что индустрия разработки ПО переживает серьезную эпидемию, и добрая половина занятых в этой индустрии уже поражена фудзиямой головного мозга в терминальной стадии.</p>
<p>Вот совсем недавний эпизод на работе. Купили мы у одной компании библиотечку одну.  В сырцах. Компания солидная, в нашей области очень хорошо всем известная, да с репутацией годами наработанной. Радовались мы библиотечке как дети, ибо делала она все, что нам нужно было и даже больше, и работало все как из пушки. Знай себе, подтаскивай данные да откачивай результаты.</p>
<p>Заметили мы, правда, бажок за библиотекой. Не баг, а так, сущая ерунда. С кем не бывает. Ну подумаешь, память слегка попортит. То тут объектик расстреляет, то там в прямо в кучу кучу всякого вывалит. Дело житейское. Баг-то ерундовый, да случись нам выпустить продукт с этим багом внутрях, клиенты наши такого йумора бы не поняли, в связи с чем были бы нам и варфоломеевская ночь и утро стрелецкой казни в одном флаконе с кондиционером.</p>
<p>Написали мы аффтарам библиотечки и стали ждать ответа. Ждать ответа нам надоело довольно быстро и примерно через недельку мы решили, что неплохо было бы как-нибудь развлечь себя и всех вокруг. Поэтому мы стали пытать библиотечку люто. Пытали-пытали, да и выяснили, как именно так заинтересовавший нас подземный стук происходит и в какой бубен нужно стукнуть, чтобы его вызвать. Обрадовались мы, да и снова написали аффтарам. Глядите, говорим, баг у вас вот здесь, вот тут, а вон там вообще рыбу заворачивали.</p>
<p>На этот раз аффтары ответили очень быстро. Ух ты, был ответ, и правда бага. Аффтары передавали всяческих регардсов, обещали все починить вот прямо &#8220;завтра&#8221; и были таковы. Таковыми они оставались следующие три недели.</p>
<p>Через три недели мы получили новую, улучшенную версию библиотеки <span style="text-decoration: line-through;">с банановым вкусом</span>. Красота &#8211; память больше не портит. Правда, в улучшенной версии обнаружились парочка доселе невиданных теперь уже утечек памяти и race condition, но кого ж такая фигня в наше время волнует?</p>
<p>В IT индустрии в очередной раз случился перекос. Сейчас модно считать  гномов на собеседованиях, но почему-то библиотеки, купленные нами за сто  тыщ миллионов, продолжают портить память и тихо дедлочить сами себя.  Все кругом могут прикинуть количество заправочных станций в Соединенных  ША, но сроки проектов как проваливались, так и проваливаются. Требование уметь определить фальшивую монету за два взвешивания уже стали стандартом, а сплошь и рядом попадаются квадратичные, а то и экспоненциальные алгоритмы там, где сложность вообще может быть константной.</p>
<p>Посмотришь на то, как нынешние собеседования проводятся и сложится полное ощущение, что среднестатистический разработчик ПО &#8211; исключительно гений, способный навскидку прикинуть количество лиственных деревьев в лесу на юге Йоркшира с относительной ошибкой в пол-процента, а также обладающие сокровенным знанием неортодоксальных методов взвешивания Боингов. С другой стороны, среднестатистическая программа как была полным багов УГ лет десять назад, так им и остается. С той лишь разницей, что десять лет назад программам не удавалось засрать четыре гига оперативки по причине отсутствия наличия этих самых гигабайтов.</p>
<p>А мораль тут простая. Читать тоже нужно уметь. &#8220;Как передвинуть гору Фудзи&#8221; не дает советов о том, как следует нанимать сотрудников. Она лишь приводит примеры различных подходов к собеседованиям, принятых в разных компаниях. При этом там неоднократно упоминается, что умение человека щелкать головоломки говорит лишь о том, что он умееть щелкать головоломки. Больше оно не говорит ничего. Умение человека решать кроссворды вовсе не означает, что он будет блестяще проектировать модули системы. Тайное знание причин, по которым крышки к канализационным люкам делаются круглыми, не гарантирует того, что человек сумеет отличить ссылку от указателя. И так далее.</p>
<p>Знаете что? Если бы я хотел разгадывать кроссворды, я бы пошел работать охранником.  Но мне нравится моя профессия, и задачи мне приходится решать гораздо более обширные и серьезные, нежели любой из фудзиямовских ребусов. Которые, кстати, и сами по себе кривые, и ответы к ним тоже не выдерживают никакой критики.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2010/10/21/%d0%a0%d0%b0%d0%b1%d0%be%d1%87%d0%b5-%d0%ba%d1%80%d0%b5%d1%81%d1%82%d1%8c%d1%8f%d0%bd%d1%81%d0%ba%d0%b8%d0%b5-%d0%b7%d0%b0%d1%80%d0%b8%d1%81%d0%be%d0%b2%d0%ba%d0%b8/ru/feed/ru/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Историческое</title>
		<link>http://www.blinnov.com/2010/08/30/%d0%98%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%87%d0%b5%d1%81%d0%ba%d0%be%d0%b5/ru/</link>
		<comments>http://www.blinnov.com/2010/08/30/%d0%98%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%87%d0%b5%d1%81%d0%ba%d0%be%d0%b5/ru/#comments</comments>
		<pubDate>Mon, 30 Aug 2010 00:48:05 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1131</guid>
		<description><![CDATA[По старой памяти установил DevPartner на VS 2010.
Это даже не УГ, это намного хуже.
А когда-то вполне себе рулезная штуковина была.
]]></description>
			<content:encoded><![CDATA[<p>По старой памяти установил DevPartner на VS 2010.</p>
<p>Это даже не УГ, это намного хуже.</p>
<p>А когда-то вполне себе рулезная штуковина была.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2010/08/30/%d0%98%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%87%d0%b5%d1%81%d0%ba%d0%be%d0%b5/ru/feed/ru/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Оптимизированные грабли</title>
		<link>http://www.blinnov.com/2010/08/11/%d0%9e%d0%bf%d1%82%d0%b8%d0%bc%d0%b8%d0%b7%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%bd%d1%8b%d0%b5-%d0%b3%d1%80%d0%b0%d0%b1%d0%bb%d0%b8/ru/</link>
		<comments>http://www.blinnov.com/2010/08/11/%d0%9e%d0%bf%d1%82%d0%b8%d0%bc%d0%b8%d0%b7%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%bd%d1%8b%d0%b5-%d0%b3%d1%80%d0%b0%d0%b1%d0%bb%d0%b8/ru/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 00:00:28 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Life]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1094</guid>
		<description><![CDATA[Тут на днях коллеги подложили нам свинью.
#define true false    // happy debugging!
Не совсем такую, но несколько человеко-дней Щасливой отладки доставили. Дело в том, что хотя коллеги и подложили свинью, оптимизатор компилятора сделал все возможное, чтобы нам не было скучно ее искать.
Система наша не то чтобы старая. Политкорректно выражаясь, можно сказать, что она [...]]]></description>
			<content:encoded><![CDATA[<p>Тут на днях коллеги подложили нам свинью.</p>
<pre class="brush:cpp">#define true false    // happy debugging!</pre>
<p>Не совсем такую, но несколько человеко-дней Щасливой отладки доставили. Дело в том, что хотя коллеги и подложили свинью, оптимизатор компилятора сделал все возможное, чтобы нам не было скучно ее искать.</p>
<p>Система наша не то чтобы старая. Политкорректно выражаясь, можно сказать, что она имеет историю. И, как в приличных домах, состоит из ядра и множества внешних компонентов, поставляющих данные в систему. Компоненты эти общаются с ядром через свой собственный несложный API и могут быть написаны вообще кем угодно и на чем угодно. Что и случалось раньше и даже по сей день случается.</p>
<p><span id="more-1094"></span></p>
<p>Как это всегда случается с системами, имеющими историю, в один прекрасный момент стало ясно, что чего-то в имеющемся API не хватает. В нашем случае оказалось, что если всего лишь одна из функций научится принимать еще всего лишь один дополнительный параметр, то нам всем сразу наступит очень много нирваны и нам, может быть, от этого даже перепадет некоторое ненулевое количество ништяков.</p>
<p>В целях сохранения совместимости с историей системы (то есть, чтобы не переписывать и перетестировать все  тысячи внешних компонентов и не заставлять делать это сторонних вендоров, имевших несчастье компонент этот написать), было принято благоразумное решение оригинальную функцию не трогать, а рядом с ней объявить вторую такую же, с расширенным списком параметров. Соответственно, старые компоненты будут по-прежнему обращаться к старой функции, которая, в свою очередь, будет уже внутри ядра вызывать новую функцию со значением по умолчанию для нововведенного параметра.</p>
<p>Скоро код пишется, да не скоро митинг кончается. В общем, код отрефакторили, написали, начали тестировать, да и к нам прибежали. Дескать, не работает компонент наш. Ага, тот самый, который ни ухом ни рылом в новом API, поскольку написан был три года назад.</p>
<p>Делать нечего, натравили отладчик на систему. Натравили и втроем уставились в монитор, ибо вместо ожидаемого стека вызовов нашим глазам предстало ничего.</p>
<p>По идее, наш компонент, сидючи в своей dll, должен был вызывать функцию_ядра() с набором параметров. В новой системе эта функция ядра передавала вызов в функцию_ядра_второй_версии() вместе со своими параметрами,  в качестве значения нововведенного параметра подсунув некое ЗНАЧЕНИЕ_ПО_УМОЛЧАНИЮ.</p>
<p>По крайней мере, это следовало из кода программы. На деле же в дизассемблированном листинге релизной версии программы тело функции_ядра() состояло из одной-единственной инструкции ret. То есть функция_ядра() в новой версии системы не делала ровным счетом нихрена.  (Отладочной версии по определенным причинам под рукой не было, прим. автора)</p>
<p>Чезанаха искали долго. Сначала уволили отладчик студии. Потом приняли на работу обратно, так как windbg показал то же самое. Потом потрошили настройки проекта на предмет вдруг чего куда-нибудь не туда прилинковалось (при определенном радиусе кривизны рук и не такое может случиться).</p>
<p>Потом вся надежда иссякла. И в этот поворотный момент нам на помощь пришел я. Мне почему-то смутно казалось, что чудес все-таки не бывает и оптимизатор, наверное, имел какие-то определенные причины, побудившие его полностью похерить вызов функции_ядра_второй_версии(). Оказалось, не казалось. Помните, я упомянул, что старая функция просто вызывает новую со ЗНАЧЕНИЕМ_ПО_УМОЛЧАНИЮ для нового параметра? Так вот,  функция_ядра_второй_версии() начиналась ни с чего-нибудь, а с проверки этого параметра. Примерно вот так:</p>
<pre class="brush:cpp">void kernel_function_ver_2(int param, int newParam)
{
    if (newParam != ЗНАЧЕНИЕ_ПО_УМОЛЧАНИЮ)
    {
        //lots of useful stuff
    }
}</pre>
<p>Короче, в случае значения по умолчанию для нового параметра новая функция не делала ровным счетом нихрена. Умный компилятор, пытаясь проинлайнить вызов функции, это дело просекал и выкидывал собственно вызов чуть более, чем полностью.</p>
<p>В отладочной сборке мы, конечно, никакой такой чехарды с исчезающим кодом не увидели бы. Но тогда это был бы совершенно рядовой баг, о котором я бы и не подумал написать.</p>
<p>А мораль тут простая &#8211; надо, &lt;censored&gt; всегда писать &lt;censored&gt; автоматизированные тесты, &lt;very censored&gt;! Особенно, &lt;multiple censored&gt; если расширяете API, сохраняя обратную совместимость. Простейший юнит (5 минут на написание) или функциональный тест (25 минут на написание) для старой функции указал бы на косяк при первой же компиляции. Но теста не было и случилось то, что случилось &#8211; баг вылез в виде совершенно неожиданного спецэффекта в компоненте, который вообще к проблеме отношения не имел, а для его локализации в новом коде и собственно возвращения кода на доработку ненулевому количеству весьма занятых людей потребовалось на весьма ненулевое время напрячь серое вещество. Хотя подобных блох компьютер прекрасно мог бы ловить сам, если бы кому-то не было лениво писать автоматические тесты.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2010/08/11/%d0%9e%d0%bf%d1%82%d0%b8%d0%bc%d0%b8%d0%b7%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%bd%d1%8b%d0%b5-%d0%b3%d1%80%d0%b0%d0%b1%d0%bb%d0%b8/ru/feed/ru/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Паттерн &#8220;observer&#8221; на tr1::function или почти настоящие делегаты</title>
		<link>http://www.blinnov.com/2010/06/25/%d0%9f%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-observer-%d0%bd%d0%b0-tr1function-%d0%b8%d0%bb%d0%b8-%d0%bf%d0%be%d1%87%d1%82%d0%b8-%d0%bd%d0%b0%d1%81%d1%82%d0%be%d1%8f%d1%89%d0%b8%d0%b5-%d0%b4%d0%b5/ru/</link>
		<comments>http://www.blinnov.com/2010/06/25/%d0%9f%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-observer-%d0%bd%d0%b0-tr1function-%d0%b8%d0%bb%d0%b8-%d0%bf%d0%be%d1%87%d1%82%d0%b8-%d0%bd%d0%b0%d1%81%d1%82%d0%be%d1%8f%d1%89%d0%b8%d0%b5-%d0%b4%d0%b5/ru/#comments</comments>
		<pubDate>Thu, 24 Jun 2010 23:34:50 +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[design patterns]]></category>
		<category><![CDATA[software development]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1021</guid>
		<description><![CDATA[Про C++ делегаты на основе boost::function (tr1::function) я уже писал. В отличие от стандартного варианта обсервера для C++, который подразумевает фиксированный контракт (интерфейс) для подписчиков, вариант с функциональными объектами обладает определенными весомыми преимуществами (все они перечислены в посте по ссылке).
Но за удобство приходится платить. В данном случае расплачиваться приходится невозможностью реализовать отписку. И причина тому [...]]]></description>
			<content:encoded><![CDATA[<p>Про C++ делегаты на основе boost::function (tr1::function) <a href="http://www.blinnov.com/2010/04/23/use-boost-to-implement-inter-class-callbacks-or-delegates/en/">я уже писал</a>. В отличие от стандартного варианта обсервера для C++, который подразумевает фиксированный контракт (интерфейс) для подписчиков, вариант с функциональными объектами обладает определенными весомыми преимуществами (все они перечислены в посте по ссылке).</p>
<p>Но за удобство приходится платить. В данном случае расплачиваться приходится невозможностью реализовать отписку. И причина тому банально проста. Вот простейший пример</p>
<pre class="brush:cpp">class Subject
{
   public:
       typedef std::tr1::function&lt;void (const MyData&amp;)&gt; typeDelegate;

       void Subscribe(typeDelegate);
       void Unsubscribe(typeDelegate);
}</pre>
<p>Реализация метода Subscribe() вопросов не вызывает. А вот с отпиской возникает проблема. В случае с классическим обсервером в оба метода передается голый указатель на интерфейс подписчика. А указатели можно сравнивать без хитростей, поэтому отписка превращается в банальное удаление элемента из контейнера.</p>
<p>Function сравнивать нельзя. В tr1 этот класс не определяет операторы сравнения, да и сама идея сравнивать функции в общем виде выглядит несколько нелепо. Идея подобного функционального объекта состоит в том, чтобы единожды его создав, скрыть его внутренности от всех остальных, при этом предоставив возможность создавать копии и выполнять как функцию с предопределенной сигнатурой. Эта идея не подразумевает возможности сравнивать, так как непонятно, что тут вообще можно сравнить. В бусте вроде пытались сделать оператор равенства для функций, но ничего хорошего из этого не вышло.</p>
<p>Отсутствие возможности сравнивать ставит жиирный такой знак вопроса на самой возможности отписки. Конечно, можно усложнить интерфейс субъектов и обязать подписчиков передавать какой-нибудь уникальный идентификатор при подписке и отписке. Таким идентификатором, например, может быть и указатель на подписчика, совсем как в классическом обсервере.</p>
<p>Делать так можно. Только это кривовато сразу по нескольким статьям. Поэтому нам нужно пойти другим путем.</p>
<p>Вышеозначенный делегат можно создавать динамически и заворачивать в умный указатель. А умные указатели уже можно сравнивать! Значит, получим</p>
<pre class="brush:cpp">class Subject
{
   public:
       typedef std::tr1::function&lt;void (const MyData&amp;)&gt; typeDelegate;
       typedef std::tr1::shared_ptr&lt;typeDelegate&gt; typeDelegatePtr;

       void Subscribe(typeDelegatePtr);
       void Unsubscribe(typeDelegatePtr);
}</pre>
<p>Теперь, чтобы подписаться на события субъекта, подписчик должен сначала динамически создать объект типа typeDelegate, завернуть его в shared_ptr, а затем уже этот умный указатель использовать для подписки и отписки:</p>
<pre class="brush:cpp">// Somewhere in subscriber's constructor, for example
Subject::typeDelegatePtr m_Delegate(
    new Subject::typeDelegate(bind(&amp;Subscriber::Process, this, _1))
    );
//...
//   Subscribe for events on _pSubject
_pSubject-&gt;Subscribe(m_Delegate);
//
//
//   Unsubscribe from _pSubject
_pSubject-&gt;Unsubscribe(m_Delegate);</pre>
<p>При этом реализация методов подписки и отписки субъекта становится очевидной, поэтому о них больше ни слова.</p>
<p>Как видно, если у объекта есть необходимость отписки, он должен сохранять оригинал делегата для этих целей. Если отписка не требуется (а такое бывает часто), локальная копия m_Delegate не нужна &#8211; временный экземпляр его можно будет создать при вызове Subscribe().</p>
<p>Можно еще сделать следующий финт ушами &#8211; слегка изменить интерфейсы и в субъект передавать не shared_ptr, а weak_ptr, образованный от оригинального умного указателя на делегат, который является членом класса-подписчика. При этом бесплатно решается проблема курицы и яйца: иногда требуется обеспечить, чтобы объект-подписчик автоматически отписывался при удалении, но никакой гарантии, что субъект еще жив, нет и быть не может. Достаточно лишь обеспечить, чтобы субъект проверял, не протухли ли &#8220;слабые&#8221; указатели (или делал им lock()) перед вызовом делегата, а подписчик владел оригинальным shared_ptr&lt;typeDelegate&gt;. При этом удаление подписчика будет вызывать инвалидацию всех инстанций weak_ptr, образованных от этого указателя, тем самым делая невозможным вызов убитого объекта через делегат, что и даст нам такую вожделенную возможность подписчика замести все свои следы даже без информации о том, на события каких объектов он подписан и живы ли они еще.</p>
<p>Я подозреваю, что этот трюк будет работать только для однопоточного приложения. В ближайшее время я собираюсь детально разобраться с возможными проблемами многопоточности при использовании данного подхода.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2010/06/25/%d0%9f%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-observer-%d0%bd%d0%b0-tr1function-%d0%b8%d0%bb%d0%b8-%d0%bf%d0%be%d1%87%d1%82%d0%b8-%d0%bd%d0%b0%d1%81%d1%82%d0%be%d1%8f%d1%89%d0%b8%d0%b5-%d0%b4%d0%b5/ru/feed/ru/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fuck the standards!</title>
		<link>http://www.blinnov.com/2010/06/23/fuck-the-standards/ru/</link>
		<comments>http://www.blinnov.com/2010/06/23/fuck-the-standards/ru/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 14:41:11 +0000</pubDate>
		<dc:creator>vital</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Software design]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[software development]]></category>

		<guid isPermaLink="false">http://www.blinnov.com/?p=1014</guid>
		<description><![CDATA[TR1 уже давно вышел. Это хорошо. Студия 2008 и 2010 уже включают его по умолчанию. Это просто отлично.
Стандарт (а TR1 &#8211; это де-факто уже стандарт) &#8211; это всегда хорошо. Больше нельзя называться C++ программистом и закатывать истерики при виде безобидного bind. Теперь нужно либо напрячь мозги и таки освоить основы функциональщины, либо идти заниматься гуевой [...]]]></description>
			<content:encoded><![CDATA[<p>TR1 уже давно вышел. Это хорошо. Студия 2008 и 2010 уже включают его по умолчанию. Это просто отлично.</p>
<p>Стандарт (а TR1 &#8211; это де-факто уже стандарт) &#8211; это всегда хорошо. Больше нельзя называться C++ программистом и закатывать истерики при виде безобидного bind. Теперь нужно либо напрячь мозги и таки освоить основы функциональщины, либо идти заниматься гуевой мышевозней.</p>
<p>А еще стандарты &#8211; это плохо. Потому что любое, даже самое разумное и оправданное изменение стандарта превращается в процесс перемещения и горы и Магомета к единому стандартизированному месту встречи. И стандартно занимает до чертиков времени, да и других восполнимых и не очень ресурсов тоже дофига требует.</p>
<p>Вот включили они bind в стандарт. И чо (что, шо, So what, нужное подчеркнуть)? А перегруженные операторы не включили! Бо не было их еще в бусте на момент подачи черновиков в стандарт. В итоге в TR1 вот так вот не сделать:</p>
<pre class="brush:cpp">vector&lt;Person&gt; myVector;
//
// Some stuff here
//
vector&lt;Person&gt;::iterator iter = find_if(
myVector.begin(),
myVector.end(),
bind(&amp;Person::GetLastName, _1) == "Pupkin");</pre>
<p>А все из-за того, что тот bind, что в TR1, не перегружает оператор &#8220;==&#8221;, сцуко такой! В итоге, чтобы сделать то же самое, что на куске кода вверху, нужно городить двухуровневый bind с equal_to посередине, от вида которого даже у привычных к boost пассажиров может случится истерика:</p>
<pre class="brush:cpp">vector&lt;Person&gt;::iterator iter = find_if(
myVector.begin(),
myVector.end(),
bind(equal_to&lt;string&gt;, "Pupkin", bind(&amp;Person::GetLastName, _1)));</pre>
<p>Еще можно по-старинке взять и нарисовать функтор. На каждый подобный чих. В итоге от обилия их изжога начнется уже у меня.</p>
<p>Нинавижу.</p>
<p>А следующего стандарта еще 10 лет ждать.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.blinnov.com/2010/06/23/fuck-the-standards/ru/feed/ru/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>

