<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Программирование on Алексей Пахунов</title>
    <link>https://blog.not-a-kernel-guy.com/tags/%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%D0%B5/</link>
    <description>Recent content in Программирование on Алексей Пахунов</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>ru-ru</language>
    <lastBuildDate>Sun, 18 Jul 2021 19:56:02 -0700</lastBuildDate>
    <atom:link href="https://blog.not-a-kernel-guy.com/tags/%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%D0%B5/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Загрузка кода в чужой процесс на Linux</title>
      <link>https://blog.not-a-kernel-guy.com/2021/07/18/lx_preload/</link>
      <pubDate>Sun, 18 Jul 2021 19:56:02 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2021/07/18/lx_preload/</guid>
      <description>&lt;p&gt;Оказывается грузить свой код в чужой процесс на Linux ничуть не менее&#xA;увлекательно, чем на Windows. Я раньше не наведывался в этой темный угол, а вот&#xA;на днях заглянул. Содержимое угла привычно обнадежило: залатанный древний&#xA;загрузчик, дохлые мухи, пара растяжек, и грабли кругом. Все как мы любим. Задача&#xA;была такая. Есть несколько загружаемых с помощью &lt;a href=&#34;https://stackoverflow.com/questions/426230/what-is-the-ld-preload-trick&#34;&gt;&lt;code&gt;LD_PRELOAD&lt;/code&gt;&lt;/a&gt; модулей.&#xA;Модули переопределяют поведение небольшого числа POSIX функций. Требовалось&#xA;перенести сборку модулей на более свежую версию GCC. Казалось что может быть&#xA;проще?.. Да, давно уже не ощущал себя насколько наивным, аж ностальгия&#xA;пробивает. Ниже следует список обнаруженных граблей.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Грустное про обратную совместимость</title>
      <link>https://blog.not-a-kernel-guy.com/2021/01/31/py3/</link>
      <pubDate>Sun, 31 Jan 2021 16:14:44 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2021/01/31/py3/</guid>
      <description>&lt;p&gt;На Hacker News давече &lt;a href=&#34;https://news.ycombinator.com/item?id=25888249&#34;&gt;разгорелась очередная дискуссия про трудности перехода со второго&#xA;Питона на третий&lt;/a&gt;. Этот случай, без сомнения, должен войти в учебники как пример&#xA;того, как делать ни в коем случае не надо. Очень показательно, что &lt;a href=&#34;https://docs.python.org/3/howto/pyporting.html&#34;&gt;официальное&#xA;руководство по переходу&lt;/a&gt; ссылается на две статьи: &lt;a href=&#34;https://ncoghlan-devs-python-notes.readthedocs.io/en/latest/python3/questions_and_answers.html&#34;&gt;Питон 3: вопросы и ответы&lt;/a&gt; и&#xA;&lt;a href=&#34;https://snarky.ca/why-python-3-exists/&#34;&gt;Почему Питон 3 существует&lt;/a&gt;. Обе статьи признают, что переход создал множество&#xA;проблем, но при этом многословно объясняют почему третий Питон был необходим. Обе статьи&#xA;были бы гораздо честнее, если бы авторы просто сказали &amp;ldquo;Простите. Мы ошиблись&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;Мое мнение по этому поводу можно свести к двум тезисам:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Питон 3 не предложил &lt;em&gt;ничего&lt;/em&gt;, что оправдало бы обратную несовместимость со вторым&#xA;Питоном.&lt;/li&gt;&#xA;&lt;li&gt;100% покрытие кода тестами - необходимое условие для того, чтобы безболезненно&#xA;переписывать код на Питоне.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Чтобы проиллюстрировать это мнение, я собрал немного статистики по миграции небольшого&#xA;проекта на 38 тысяч строк. Проект состоит из коллекции тестов, проверяющих поведение&#xA;операционной системы на целевой платформе, и обвязки, которая позволяет эти тесты&#xA;запускать на железе. Код проекта покрыт юнит тестами плохо. Юнит тесты занимают всего&#xA;около двух с половиной тысяч строк. Это имеет рациональное объяснение - покрывать код&#xA;тестов тестами вроде как особого смысла нет. Но на легкость переписывания кода это, само&#xA;собой, влияет.&lt;/p&gt;&#xA;&lt;p&gt;Основной перевод кода с py2 на py2+py3 начался в июле прошлого года и занял ровно две&#xA;недели, 14 пул-реквестов и примерно чуть более 5% измененного кода. Если включить&#xA;автоматическое переформатирование кода, то дельта увеличивается до 30% кода. Для&#xA;сравнения, в два раза более крупное, похожее по характеру изменение в проекте на С++&#xA;(150 тысяч строк кода) заняло 4 дня от начала до конца.&lt;/p&gt;&#xA;&lt;p&gt;Здесь кстати есть еще один характерный момент. Переход на третий Питон - это почти&#xA;всегда переход на код, совместимый с обоими версиями сразу. Просто потому, что&#xA;невозможно перевести сколь-нибудь крупный проект за раз. Но, как мы помним, эти версии&#xA;умышленно несовместимы друг с другом. Так что костыли вроде &lt;a href=&#34;https://pypi.org/project/six/&#34;&gt;six&lt;/a&gt; просто необходимы.&lt;/p&gt;&#xA;&lt;p&gt;Какие же изменения были сделаны за эти две недели? Да все же тот стандартный список:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Байты и строки.&lt;/li&gt;&#xA;&lt;li&gt;Целочисленное деление.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;int&lt;/code&gt; vs &lt;code&gt;long&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;print&lt;/code&gt; стал функцией.&lt;/li&gt;&#xA;&lt;li&gt;Некорректные управляющие последовательности в строках.&lt;/li&gt;&#xA;&lt;li&gt;Отсутствующий &lt;code&gt;sys.maxint&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;Отсутствующий &lt;code&gt;xrange&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;В случае типизированного языка, все эти несовместимости ловятся на этапе компиляции. В&#xA;конце концов, компилятор компилирует 100% кода программы (слава богу &lt;a href=&#34;https://en.cppreference.com/w/cpp/language/sfinae&#34;&gt;SFINAE&lt;/a&gt; в&#xA;нормальных программах используется более-менее локально). Единственный способ надежно&#xA;отловить все ошибки компиляции в Питоне можно только выполнив &lt;em&gt;каждую&lt;/em&gt; строку кода в&#xA;программе. Я еще ни разу в жизни не видел ни одного реального программного проекта со&#xA;100% покрытием тестами.&lt;/p&gt;&#xA;&lt;p&gt;Обидно, что даже самое полезное новшество - раздельные строки и байты не требует ломать&#xA;обратную совместимость. Ну совсем. Что нужно было сделать? - дать возможность явно&#xA;указать, ожидает ли код байты или строки в новом коде, а старый код обложить&#xA;диагностикой, которая ловит ошибки. Добавить специальный режим проверок во время&#xA;исполнения, если требуется. Что сделали разработчики Питона? Переименовали &lt;code&gt;str&lt;/code&gt; в&#xA;&lt;code&gt;bytes&lt;/code&gt;, а &lt;code&gt;unicode&lt;/code&gt; в &lt;code&gt;str&lt;/code&gt;. Чем сломали ожидания огромного массива существующего кода.&lt;/p&gt;&#xA;&lt;p&gt;Однако авторам этого показалось мало и они добавили еще кучу тривиальных, и совсем&#xA;ненужных несовместимостей. К примеру убрали &lt;code&gt;iteritems()&lt;/code&gt; или убрали оператор &lt;code&gt;print&lt;/code&gt;.&#xA;Что мешало оставить первый и позволить второму быть и оператором и функцией - это выше&#xA;моего понимания.&lt;/p&gt;&#xA;&lt;p&gt;Но если вы думаете, что за две недели эпопея закончилась, вы сильно ошибаетесь. Это был&#xA;только первый тикет в баг-трекере. Спустя полгода их заведено уже 15. Заслано 33&#xA;пул-реквеста. Крайний и видимо не последний баг, вызванный переходом, был найден неделю&#xA;назад. Как минимум три тикета еще предстоит исправить. Вот такие дела.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Фонтанный код</title>
      <link>https://blog.not-a-kernel-guy.com/2020/09/06/fountain-codes/</link>
      <pubDate>Sun, 06 Sep 2020 15:23:17 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2020/09/06/fountain-codes/</guid>
      <description>&lt;p&gt;Недавно совершенно случайно узнал про &lt;a href=&#34;https://en.wikipedia.org/wiki/Fountain_code&#34;&gt;фонтанный код&lt;/a&gt; и поразился насколько&#xA;элегантно работает этот алгоритм. Этот код позволяет надежно передавать данные&#xA;по каналу с потерями без обратной связи и с минимальными накладными расходами.&#xA;Более того передатчик и приемник не обязаны синхронизировать начало и конец&#xA;передачи данных. Фонтанный код позволяет передатчику генерировать бесконечный&#xA;поток пакетов, кодирующих исходное сообщение, а приемник может начать слушать в&#xA;любой момент. Все что требуется - это принять минимально необходимое для&#xA;декодирования количество пакетов. &lt;a href=&#34;https://en.wikipedia.org/wiki/Raptor_code&#34;&gt;Raptor code&lt;/a&gt;, - одна из наиболее&#xA;практичных реализаций, требует всего лишь передать всего 0.2% дополнительных&#xA;пакетов для успешного декодирования с вероятностью 0.999999. При этом&#xA;вероятность успешного декодирования стремительно приближается к единице с каждым&#xA;дополнительным пакетом.&lt;/p&gt;&#xA;&lt;p&gt;Зачем это нужно когда уже есть протоколы надежной передачи по двухстороннему&#xA;каналу, скажем тот же TCP/IP? Оказывается существует ситуации, когда организация&#xA;обратного канала связи требует изобретения машины времени. Когда нам нужно&#xA;восстановить данные со сбойного сектора на жестком диске, мы не можем послать&#xA;“запрос на повторную передачу” в прошлое - в то время, когда сектор нормально&#xA;читался. Все что мы можем сделать - это записать избыточные данные в другой&#xA;сектор или на другой диск заранее.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Контрольная сумма UDP</title>
      <link>https://blog.not-a-kernel-guy.com/2020/04/11/udp-checksum/</link>
      <pubDate>Sat, 11 Apr 2020 21:16:34 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2020/04/11/udp-checksum/</guid>
      <description>&lt;p&gt;Большинство проектов, над которыми я когда-либо работал, так или иначе&#xA;не работают без передачи данных по сети. Последним проектом не&#xA;выходящим за рамки одного компьютера была поддержка &lt;a href=&#34;https://blog.not-a-kernel-guy.com/tags/wow64/&#34;&gt;Wow64&lt;/a&gt; в ядре&#xA;Windows. Тем не менее возится с кодом, непосредственно обрабатывающим IP&#xA;пакеты мне довелось всего пару раз. Оба раза я столкнулся с одной и той&#xA;же ошибкой вычисления контрольных сумм в IP стеке. В одном случае,&#xA;сетевая карта ошибочно помечала хорошие пакеты как испорченные. В другом -&#xA;две библиотеки, написанные разными людьми, неверно вычисляли контрольную&#xA;сумму некоторых пакетов. Одна из библиотек широко использовалась в&#xA;&amp;ldquo;боевых&amp;rdquo; условиях. Немного удивительно, что ошибка оставалась незамеченной&#xA;так долго.&lt;/p&gt;&#xA;&lt;p&gt;Корнями этот баг уходит в 1980-й год, когда был опубликована &lt;a href=&#34;https://tools.ietf.org/html/rfc768&#34;&gt;спецификация&#xA;протокола UDP&lt;/a&gt;. Чтобы разобраться в чем заключается ошибка, нужно&#xA;сначала разобраться как работают контрольные суммы в IP стеке. В IPv4 пакете&#xA;есть две контрольные суммы: контрольная сумма IPv4 заголовка и контрольная&#xA;сумма протокола следующего уровня (UDP, TCP, ICMP, и т.п.). Контрольная&#xA;сумма IPv4 заголовка защищает только IPv4 заголовок. Контрольная сумма&#xA;протокола следующего уровня защищает тело пакета и некоторые поля из&#xA;заголовка.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Когда 1.0 = 0.0</title>
      <link>https://blog.not-a-kernel-guy.com/2019/12/16/gcc/</link>
      <pubDate>Mon, 16 Dec 2019 22:49:36 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2019/12/16/gcc/</guid>
      <description>&lt;p&gt;Столкнулся недавно с новой для себя областью - ловлей багов в компиляторе.&#xA;Ловить &lt;a href=&#34;https://blog.not-a-kernel-guy.com/2010/07/11/854/&#34;&gt;баг в процессоре&lt;/a&gt; мне уже доводилось, а вот с компиляторами до&#xA;недавнего времени как-то везло.&lt;/p&gt;&#xA;&lt;p&gt;Началось все очень прозаично. В нашем репозитории есть своя реализация умного&#xA;указателя. Ну, вы знаете, как это бывает. Обычная история на самом деле&amp;hellip;&#xA;Этот класс был написан в древние времена, тогда и &lt;a href=&#34;https://en.wikipedia.org/wiki/C%2B%2B03&#34;&gt;С++03&lt;/a&gt; еще на свете не&#xA;было. С тех пор уже и &lt;a href=&#34;https://en.wikipedia.org/wiki/C%2B%2B17&#34;&gt;С++17&lt;/a&gt; появился и &lt;a href=&#34;https://en.wikipedia.org/wiki/C%2B%2B20&#34;&gt;С++20&lt;/a&gt; не за горами, но класс&#xA;по-прежнему активно используется. Мы его давно хотели заменить на что-нибудь&#xA;более стандартное и современное, но все руки не доходили. “Работает - не трожь”.&lt;/p&gt;&#xA;&lt;p&gt;В один прекрасный день в этом классе нашлось &lt;a href=&#34;https://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D1%91%D0%BD%D0%BD%D0%BE%D0%B5_%D0%BF%D0%BE%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5&#34;&gt;неопределенное поведение&lt;/a&gt;, что&#xA;стало последней каплей, &lt;del&gt;переломившей верблюду соломинку&lt;/del&gt;. Указатель был&#xA;переписан на корню и стал тонкой оберткой вокруг &lt;code&gt;std::shared_ptr&amp;lt;&amp;gt;&lt;/code&gt;.&#xA;На следующий же день сломался один неприметный юнит тест на одной из платформ.&#xA;Причем на первый взгляд никакого отношения к переписанному указателю этот тест&#xA;не имел. Но от фактов было трудно отвертеться. С новым указателем тест падал, а&#xA;со старым - нет.&lt;/p&gt;</description>
    </item>
    <item>
      <title>В одном бите от ядерной катастрофы</title>
      <link>https://blog.not-a-kernel-guy.com/2019/03/21/bit-flip-nuclear-disaster/</link>
      <pubDate>Thu, 21 Mar 2019 22:05:47 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2019/03/21/bit-flip-nuclear-disaster/</guid>
      <description>&lt;p&gt;А хотите я вам страшилку на ночь расскажу? На данный момент большинство всех&#xA;важных решений принимают и &lt;em&gt;выполняют&lt;/em&gt; компьютеры. Совершенно автоматически.&#xA;Не верите? Смотрите, подъезжаете вы к перекрестку на котором в этот момент&#xA;не кстати загорается красный свет. Вы плавно нажимаете на тормоз и привычно&#xA;останавливаете машину. Знакомая картина? На самом деле все происходит совсем не&#xA;так.&lt;/p&gt;&#xA;&lt;p&gt;Для начала светофором уже давно управляет автоматическая системы управления,&#xA;задача которой - равномерно рассредоточить нагрузку на дорожную сеть. И хотя&#xA;разгоняясь от предыдущего светофора вы, откровенно говоря, немного газанули&#xA;(чтобы успеть до следующего красного), систему не дураки проектировали. Время&#xA;переключения адаптируется в зависимости от времени суток и показаний датчиков,&#xA;встроенный в полотно дороги. Шансов проскочить у вас не много.&lt;/p&gt;&#xA;&lt;p&gt;Когда вы нажимаете на акселератор, перемещение педали никак не влияет на&#xA;состав горючей смеси в двигателе. Вместо этого компьютер отслеживает положение&#xA;педали и просит другой компьютер приготовить горючую смесь определенного&#xA;состава, который зависит не только от положения педали, но и от кучи других&#xA;параметров, включая приложенное усилие, дорожные условия, настройки машины,&#xA;качество топлива и т.д. Как вы думаете, что произойдет, если &lt;a href=&#34;https://en.wikipedia.org/wiki/2009%E2%80%9311_Toyota_vehicle_recalls&#34;&gt;программисты не&#xA;оттестировали как следует этот алгоритм&lt;/a&gt;?&lt;/p&gt;&#xA;&lt;p&gt;Нажатие на тормоз все еще передается на колеса почти напрямую, но и этот бастион&#xA;скоро падет.&lt;/p&gt;&#xA;&lt;p&gt;Чем сложнее система, тем больше вероятность того, что человек не приминает&#xA;никаких решений напрямую. В самолетах концепция &lt;a href=&#34;https://en.wikipedia.org/wiki/Fly-by-wire&#34;&gt;fly-by-wire&lt;/a&gt; давно победила&#xA;ручное управление. Ракеты изначально &lt;a href=&#34;https://www.youtube.com/watch?v=PK_yguLapgA&#34;&gt;летают в полностью автоматическом&#xA;режиме&lt;/a&gt;. Финансовые системы практически полностью существуют в виртуальном&#xA;мире. Решения о покупке и продаже &lt;a href=&#34;https://en.wikipedia.org/wiki/2010_Flash_Crash&#34;&gt;принимаются автоматически&lt;/a&gt;. Медицинская&#xA;техника? Это только кажется, что человек нажимает кнопку и что-то при этом&#xA;решает. На самом дале нажатие кнопки всего лишь запускает глючный код, который&#xA;определяет &lt;a href=&#34;https://en.wikipedia.org/wiki/Therac-25&#34;&gt;дозу рентгена, которую получит пациент&lt;/a&gt;. Атомные станции? Ядерный&#xA;арсенал? Управляется опытными операторами? Не смешите мои тапочки. Опытные&#xA;операторы только кнопки нажимают. Компьютеры принимают все решения.&lt;/p&gt;&#xA;&lt;p&gt;Как компьютер принимает решение? А вот так:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (speed &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt; desired_speed)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    accelerate();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Для процессора, который выполняет этот код, принятие решение выглядит как&#xA;одна-единственная инструкция условного перехода. Если условие истинно, то&#xA;перейти по этому адресу, я если нет - то по другому. Один бит.&lt;/p&gt;&#xA;&lt;p&gt;Достаточно ошибится в одном бите, чтобы выполнить действие, прямо&#xA;противоположное действие задуманному. Разница между &amp;ldquo;отдать штурвал от себя&amp;rdquo; и&#xA;&amp;ldquo;потянуть штурвал на себя&amp;rdquo; - один бит.&lt;/p&gt;&#xA;&lt;p&gt;Страшно?&lt;/p&gt;</description>
    </item>
    <item>
      <title>Волшебство Питона</title>
      <link>https://blog.not-a-kernel-guy.com/2018/11/20/python-magic/</link>
      <pubDate>Tue, 20 Nov 2018 22:36:35 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/11/20/python-magic/</guid>
      <description>&lt;p&gt;Мне все-таки не понятно как живут большие проекты, написанные на Питоне. Он же&#xA;как песок. Пока проект небольшой - все классно. Быстро накидали горку мокрого&#xA;песка, лопаткой обхлопали для придания формы и все дела. Знай только что брызгай&#xA;водой своевременно. Когда проект разрастается, то красивый и уютный песчанный&#xA;замок превращается в минное поле. Отрефакторил подвал - крыша отвалилась.&#xA;Поправил крышу - окна слиплись в один комок.&lt;/p&gt;&#xA;&lt;p&gt;Непонятно как все это счастье держать в одной куче. Неужели все живут за счет&#xA;100% покрытия тестами? Не верю. Или все на PyCharm сидят?&lt;/p&gt;&#xA;&lt;p&gt;Расскажу про очередной прикол Питона. Итак есть простой код:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;init&lt;/span&gt;(factories):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Convert a list of factorie into a list of objects.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; [factory() &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; factory &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; factories]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cleanup&lt;/span&gt;(objects):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Clean up objects in the reversed order of their creation.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; obj &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; reversed(objects):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        obj&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;cleanup()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;init()&lt;/code&gt; берет список фабрик и отдает список объектов, созданных фабриками.&#xA;&lt;code&gt;cleanup()&lt;/code&gt; чистит созданные объекты в порядке, противоположном порядку&#xA;создания. Нам требуется написать тест, который проверяет, что методы &lt;code&gt;cleanup()&lt;/code&gt;&#xA;вызываются в правильном порядке:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; itertools &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; permutations&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; mock&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;test_cleanup&lt;/span&gt;():&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Verify cleanup() order.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# Try all permitations of initialization order. &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; init_order &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; permutations(range(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cleanup_order &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;factory&lt;/span&gt;(index):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cleanup&lt;/span&gt;():&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Record the clean up order.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                cleanup_order&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;append(index)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;create&lt;/span&gt;():&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&amp;#34;Return a mock implementing cleanup().&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                obj &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mock&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Mock&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                obj&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;cleanup &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; mock&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Mock(side_effect&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;cleanup)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; obj&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; create&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Create objects in the desired order.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        objects &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; init([factory(index) &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; index &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; init_order])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cleanup(objects)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# Verify that the object were cleaned up in the reveresed&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;# order of their creation.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;assert&lt;/span&gt; cleanup_order &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; list(reversed(init_order))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Разберу логику по кускам. Тест перебирает все возможные кобинации порядка&#xA;создания объектов:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; init_order &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; permutations(range(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Декоратор &lt;code&gt;factory()&lt;/code&gt; возвращает фабрику &lt;code&gt;create()&lt;/code&gt;, которая в свою учередь&#xA;создает объект с методом &lt;code&gt;cleanup()&lt;/code&gt;. Для создания объекта на коленке&#xA;используется &lt;a href=&#34;https://docs.python.org/3/library/unittest.mock.html&#34;&gt;&lt;code&gt;Mock&lt;/code&gt;&lt;/a&gt;. Релизация &lt;code&gt;cleanup()&lt;/code&gt; запоминает порядок вызова в&#xA;&lt;code&gt;cleanup_order&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;init()&lt;/code&gt; создает объекты в заданном порядке, &lt;code&gt;cleanup()&lt;/code&gt; - чистит:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;objects &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; init([factory(index) &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; index &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; init_order])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cleanup(objects)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Наконец, в самом конце мы проверяем, что порядок очистки противоположен порядку&#xA;создания:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;assert&lt;/span&gt; cleanup_order &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; list(reversed(init_order))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Все просто, не так ли? Запускаем тест и получаем облом:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;gt;               assert cleanup_order == list(reversed(init_order))&#xA;E     assert [2, 2, 2] == [2, 1, 0]&#xA;E       At index 1 diff: 2 != 1&#xA;E       Use -v to get the full diff&#xA;&#xA;&#xA;rabbit_test.py:41: AssertionError &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Заядлые питонщики давно раскусили, в чем проблема. А вы сможете найти ошибку не&#xA;заглядывая в ответ?&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ну-ка, еще разок</title>
      <link>https://blog.not-a-kernel-guy.com/2018/11/08/retrying/</link>
      <pubDate>Thu, 08 Nov 2018 21:57:46 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/11/08/retrying/</guid>
      <description>&lt;p&gt;Питоний пакет &lt;a href=&#34;https://pypi.org/project/retrying/&#34;&gt;retrying&lt;/a&gt; - универсальная заплатка для кода, который может&#xA;поломаться из-за внешних причин. Например, &lt;a href=&#34;https://docs.python.org/3.7/library/socket.html#socket.socket.connect&#34;&gt;&lt;code&gt;socket.connect()&lt;/code&gt;&lt;/a&gt; может&#xA;закончится ошибкой из-за непредвиденной ситуации в сети. Заворачиваем вызов в&#xA;&lt;code&gt;@retry&lt;/code&gt; и бац! Все работает.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-py&#34; data-lang=&#34;py&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;@retry&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;create_connection&lt;/span&gt;(address):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    s &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; socket&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;socket(socket&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;AF_INET, socket&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;SOCK_STREAM)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; socket&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;connect(address)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Однако бездумное применение &lt;code&gt;@retry&lt;/code&gt;, как нетрудно догадаться, приводит&#xA;проблемам. Самый известный пример - вложенные &lt;code&gt;@retry&lt;/code&gt;.&#xA;&lt;code&gt;@retry(stop_max_attempt_number=3)&lt;/code&gt; вложенный в другой&#xA;&lt;code&gt;@retry(stop_max_attempt_number=3)&lt;/code&gt; дает 9 повторов. Три уровня вложенности -&#xA;27 повторов.&lt;/p&gt;&#xA;&lt;p&gt;Один раз использование &lt;code&gt;@retry&lt;/code&gt; привело к тому, что IT заблокировало мою учетную&#xA;запись. Банальная история - был некий скрипт, который при запуске спрашивал&#xA;логин и пароль для авторизации. В один прекрасный день некто (не будем&#xA;показывать пальцем, хотя это был Слонёнок) усовершенствовал скрип, завернув&#xA;сетевой вызов в &lt;code&gt;@retry&lt;/code&gt;. Отличная идея, за исключением того, что ошибка&#xA;авторизации приводила к повторному запросу с тем же неправильным именем и&#xA;паролем. После определенного числа попыток контроллер домена решил, что кто-то&#xA;пытается подобрать пароль к учетной записи и заблокировал её.&lt;/p&gt;&#xA;&lt;p&gt;Мораль истории - знайте свои ошибки в лицо и используйте параметр&#xA;&lt;code&gt;retry_on_exception&lt;/code&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Текстовые данные в юнит тестах</title>
      <link>https://blog.not-a-kernel-guy.com/2018/08/05/text-data/</link>
      <pubDate>Sun, 05 Aug 2018 18:44:25 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/08/05/text-data/</guid>
      <description>&lt;p&gt;В предыдущем посте про &lt;a href=&#34;https://blog.not-a-kernel-guy.com/2018/08/01/table-driven-unit-tests/&#34;&gt;табличные юнит тесты&lt;/a&gt; я рассказал про способ&#xA;улучшения читаемости однообразных юнит тестов. Там же мне в комментариях&#xA;аналогичных примеров из существующих фреймворков накидали. Теперь давайте&#xA;посмотрим как этот способ сделать еще лучше.&lt;/p&gt;&#xA;&lt;p&gt;Основная идея была очень проста. Есть повторяющийся, очень монотонный код&#xA;тестов. Чтобы сделать его читаемым, пишется универсальное тело теста, а все&#xA;необходимые вариации описываются параметрами. Параметры упаковываются в таблицу,&#xA;что очень важно для улучшения читаемости. Когда все параметры собраны в одном&#xA;месте (в пределах одного экрана), анализировать поведение тестируемого кода&#xA;легче, чем когда параметры разбросаны по файлу длиной в сотни строк.&lt;/p&gt;&#xA;&lt;p&gt;Как сделать код еще более понятным? К примеру, возьмем таблицу из предыдущего&#xA;поста. Что с ней не так?&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; x;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; y;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;string that_thing;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;string this_key;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; result;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; cases[] &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thing1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;, false},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thing1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;, false},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thing1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key2&amp;#34;&lt;/span&gt;, false},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thing1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;, true },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thing2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;key1&amp;#34;&lt;/span&gt;, false},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thing2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,     false},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;thing2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,     true },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,     false},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,     true },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,       &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,     false},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;В этой таблице слишком много знаков препинания: скобки, запятые, кавычки.&#xA;К параметрам в этой таблице неудобно писать комментарии и еще сложнее подружить&#xA;удобно выровненные колонки с &lt;a href=&#34;https://clang.llvm.org/docs/ClangFormat.html&#34;&gt;&lt;code&gt;clang-format&lt;/code&gt;&lt;/a&gt; (&lt;code&gt;clang-format off&lt;/code&gt; - это&#xA;единственный выход). Более того, столкнувшись с реальностью, подобная таблица&#xA;станет еще менее читаемой - колонки вылезут за правый край экрана, выравнивание&#xA;будет принесено в жертву более компактной записи и т.д.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Табличные юнит тесты</title>
      <link>https://blog.not-a-kernel-guy.com/2018/08/01/table-driven-unit-tests/</link>
      <pubDate>Wed, 01 Aug 2018 19:52:48 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/08/01/table-driven-unit-tests/</guid>
      <description>&lt;p&gt;Расскажу об одной технике, которая, как мне кажется, позволяет писать более&#xA;понятные и читаемые юнит тесты. Начну немного издалека. Допустим мы хотим&#xA;убедится, что определенный кусок кода работает правильно. Если бы мы имели дело&#xA;с игрушечным примером, то это наш тест мог бы Примерно вот так:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;foobar&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; x, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; y)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; (x &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; y) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ((x &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; y) &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_FALSE(foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_FALSE(foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_FALSE(foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_TRUE (foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_FALSE(foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_FALSE(foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_TRUE (foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_FALSE(foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_TRUE (foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_FALSE(foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Такой тест достаточно легко читать. Достаточно понять конструкцию&#xA;&lt;code&gt;ASSERT_XXX(foobar(...))&lt;/code&gt; после чего глаза сами фокусируются на входных&#xA;значениях, автоматически отсеивая ненужный синтаксический мусор.&lt;/p&gt;&#xA;&lt;p&gt;Однако, если взять реальный код, то подобный пример превратиться в гораздо менее&#xA;удобочитаемого монстра:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cpp&#34; data-lang=&#34;cpp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;unique_ptr&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;Foobar&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; rabbit &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    create_foobar_with_abc(parent,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        some_context,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        more_stuff &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; that &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; is_required &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; to_create_foobar,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        a,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        b,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        mock_c(),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        logger);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_TRUE(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rabbit&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;connect(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        this_thing,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        that_key,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        did_you_think_we_are_done_here &lt;span style=&#34;color:#f92672&#34;&gt;?&lt;/span&gt; no : hell_no));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_TRUE(rabbit&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;wait_for_accept(timeout));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ASSERT_FALSE(rabbit&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;foobar(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;));&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; и так далее для каждого тест кейса. Подобный код легко превращается в&#xA;длинную простыню однообразного текста с незаметными, но важными вариациями во&#xA;входных данных или параметрах инициализации.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Как я провел прошлую пятницу</title>
      <link>https://blog.not-a-kernel-guy.com/2018/07/07/sneaky-comma/</link>
      <pubDate>Sat, 07 Jul 2018 17:09:38 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/07/07/sneaky-comma/</guid>
      <description>&lt;p&gt;Расскажу как я провел прошлую пятницу. Провел я её пытаясь понять, почему&#xA;простой как доска тест-кейс не работает.&lt;/p&gt;&#xA;&lt;p&gt;Тест-кейс запускает код в среде, которая симулирует полетное окружение: среду&#xA;выполнения, показания датчиков и т.д. Далее выполняется простой сценарий -&#xA;тест-кейс получает телеметрию и выполняет действия/проверки по наступлению&#xA;определенных событий. Например, тест-кейс может запустить ракету, выключить&#xA;четвертый двигатель, когда высота превысит сотню метров, а затем проверить, что&#xA;код корректно обработал нештатную ситуацию.&lt;/p&gt;&#xA;&lt;p&gt;Такие тест-кейсы, естественно, не пишутся с нуля. Кейс набирается из уже&#xA;готовых, давно написанных блоков. Что может быть очень простым делом (если есть&#xA;готовый шаблон), или не очень простым (когда такой шаблон нужно создать самому).&#xA;В этот раз случился как раз второй вариант. Когда все компоненты теста правильно&#xA;соединены остается только написать код, который ждет наступления интересных&#xA;событий и реагирует на них нужным образом.&lt;/p&gt;&#xA;&lt;p&gt;К пятнице я добрался до момента, когда сценарий тест-кейса уже написан, но еще&#xA;не работает. Сценарий вылетал по таймауту ожидая наступления одного из событий.&#xA;При этом телеметрия четко показывала, что событие наступило и у теста был вагон&#xA;времени, чтобы это заметить. Интересно, что точно такой же код, отслеживающий&#xA;другую телеметрию работал как часы. Хм.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Skyrora</title>
      <link>https://blog.not-a-kernel-guy.com/2018/05/22/skyrora/</link>
      <pubDate>Tue, 22 May 2018 22:36:33 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/05/22/skyrora/</guid>
      <description>&lt;p&gt;Ха. Прислал письмо рекрутер из британско-украинского ракетного стартапа&#xA;&lt;a href=&#34;https://www.skyrora.com/&#34;&gt;Skyrora&lt;/a&gt;. Насколько я понимаю - деньги британские, а спецы южмашевские. Судя&#xA;по сайту - вполне себе приличный ракетный стартап. Первая суборбитальная версия&#xA;ракеты в разработке; вторая, орбитальная, в планах. Больше про компанию ничего&#xA;не знаю, но все равно приятно, что в Украине есть такие стартапы. Было бы&#xA;здорово, если бы у них получилось завоевать свое место под солнцем.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.not-a-kernel-guy.com/2018/05/skyrora-1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Рекрутер попросил пропиарить позицию &lt;a href=&#34;https://www.signalhire.com/jobs/skyrora/software-architect-c-developer/djo5MTk4O2M6MjI3NDA1O3I6MzQ2O3JmOjE=&#34;&gt;Software Architect/C++ Developer&lt;/a&gt;,&#xA;который будет заниматься системой управления ракеты-носителя. Позиция открыта в&#xA;Днепре. Есть желающие дерзнуть? :-)&lt;/p&gt;</description>
    </item>
    <item>
      <title>SubGit</title>
      <link>https://blog.not-a-kernel-guy.com/2018/05/15/subgit/</link>
      <pubDate>Tue, 15 May 2018 22:46:12 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/05/15/subgit/</guid>
      <description>&lt;p&gt;Получил непрошенное подтверждение &lt;a href=&#34;https://blog.not-a-kernel-guy.com/2018/04/22/svn-git/&#34;&gt;тезиса про вред реализации веток через&#xA;операцию копирования в Subversion&lt;/a&gt;. Вторую неделю бодаюсь с импортом SVN в&#xA;Git с помощью &lt;a href=&#34;https://subgit.com/&#34;&gt;SubGit&lt;/a&gt;. SubGit довольно неплохо с этим справляется. Особенно&#xA;хорошо то, что он может постоянно синхронизировать SVN и Git, делая переход с&#xA;одного на другой плавным и безболезненным. Он даже со всякими&#xA;противоестественными манипуляциями со структурой веток в SVN репозитории&#xA;справляется.&lt;/p&gt;&#xA;&lt;p&gt;Но и на старуху найдется свой Раскольников. При создании одного из зеркал был&#xA;указан не корневой адрес SVN, а https://foobar/svn/xyz. Зеркало прекрасно&#xA;жило своей зеркальной жизню, пока не было обнаружено, что часть истории&#xA;отсутствует. Для её восстановления родился план - заново импортировать все из&#xA;корня (https://foobar/svn), а затем, уже на стороне Git, - сшить старую и новую&#xA;историю вместе.&lt;/p&gt;&#xA;&lt;p&gt;Отличный был план. И, что самое главное, и SubGit и Git все эти фокусы позволяют&#xA;и поддерживают. За одним маленьким исключением&amp;hellip; Как выяснилось, менять адрес&#xA;с https://foobar/svn/xyz на https://foobar/svn категорически не получается.&#xA;Вернее получается, но результат выходит как-то не очень. SubGit пытается&#xA;импортировать историю (и находит все правильные коммиты, что характерно), но&#xA;затем пытается заново засунуть их обратно в SVN. SVN кричит &amp;ldquo;что вы в меня это&#xA;пихаете?&amp;rdquo; SubGit ужасно смущается, бормочет многоэтажные стек-трейсы в лог и&#xA;заодно сносит &lt;code&gt;master&lt;/code&gt; к праотцам.&lt;/p&gt;&#xA;&lt;p&gt;Эх&amp;hellip; Буду теперь с &lt;code&gt;git replace&lt;/code&gt; возится&amp;hellip;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ошибки дизайна</title>
      <link>https://blog.not-a-kernel-guy.com/2018/04/22/svn-git/</link>
      <pubDate>Sun, 22 Apr 2018 18:47:23 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/04/22/svn-git/</guid>
      <description>&lt;p&gt;А давайте про ошибки в дизайне поговорим. Тем более, что задним умом мы тут&#xA;самые умные&amp;hellip; Я в последнее время много играюсь с миграцией &lt;a href=&#34;https://subversion.apache.org/&#34;&gt;Subversion&lt;/a&gt; на&#xA;&lt;a href=&#34;https://git-scm.com/&#34;&gt;Git&lt;/a&gt; и многие их косяки так в глаза и лезут.&lt;/p&gt;&#xA;&lt;p&gt;Начнем с Subversion. Во времена массового перехода с &lt;a href=&#34;https://en.wikipedia.org/wiki/Concurrent_Versions_System&#34;&gt;CVS&lt;/a&gt; на Subversion,&#xA;одним из главных аргументов &amp;ldquo;за&amp;rdquo; была поддержка директорий и операций&#xA;копирования/перемещения в Subversion. Было видно, что разработчикам поддержка&#xA;копирования очень пришлась по душе. Насколько пришлась, что и ветки в Subversion&#xA;создаются через копирование, а структура репозитория по-умолчанию - это&#xA;знаменитые три директории &lt;code&gt;trunk&lt;/code&gt;, &lt;code&gt;branches&lt;/code&gt; и &lt;code&gt;tags&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Я догадываюсь как принималось это решение. Что-нибудь в духе &amp;ldquo;прикиньте,&#xA;одна операция поддерживает и копирование, и ветки, и метки. Не нужно писать&#xA;новый код для отдельного пространства имен веток. У нас уже есть этот код&amp;rdquo;. Но&#xA;если пересчитать набитые шишки, то становится понятно, что решение было так&#xA;себе&amp;hellip; не очень&amp;hellip; совсем хреновое решение это было, как оказалось.&lt;/p&gt;&#xA;&lt;p&gt;Почему? А вот почему. Корректная работа с путями файлов, не смотря на кажущуюся&#xA;простоту, - это постоянный источник багов. Казалось бы, что тут может быть&#xA;сложного, но в результате получается как с указателями - нет, нет, а обязательно&#xA;один потеряется. А Subversion заставляет с путями работать.&lt;/p&gt;&#xA;&lt;p&gt;Скажем количество шагов в пути для &lt;code&gt;trunk&lt;/code&gt; и &lt;code&gt;branches/foobar&lt;/code&gt; разная. Это&#xA;значит, что любой скрипт должен это корректно обработать. Не существует способа&#xA;найти все ветки в произвольном репозитории. Операция копирования не обязательно&#xA;означает создание ветки - а значит без какого-нибудь соглашения не обойтись.&#xA;Ну а мы знаем насколько хорошо &lt;a href=&#34;https://xkcd.com/927/&#34;&gt;люди выдумывают совместимые стандарты&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Использование копирования для создания веток автоматически означает, что&#xA;Subversion создать рабочую копию из людой директории в репозитории. Отличная&#xA;оптимизация, когда нужно выкачать один файл, но, опять же, это означает, что&#xA;скрипты не могут делать массы полезных предположений о структуре репозитория.&#xA;Практически сразу же вся эта гибкость запрещается и создается wiki страничка&#xA;&amp;ldquo;чекаут делается так, а ветки называются только так, а всех кто делает не так -&#xA;прибью нафиг&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;Теперь давайте про Git. Линус выбрал другую крайность. Вместо того, чтобы&#xA;оставить поддержку копирования для файлов, но сделать нормальные ветки, он&#xA;сделал нормальные ветки, но выкорчевал поддержку операций копирования. За одно&#xA;под раздачу попали пустые директории.&lt;/p&gt;&#xA;&lt;p&gt;Объяснение, как я его понимаю, тут такое - ни копирование, ни пустые директории&#xA;с точки зрения самой системы контроля версий не несут полезной информации. Они&#xA;совершенно не нужны чтобы корректно отслеживать версии исходного кода. Более&#xA;того, эффективное использование Git подразумевает, что никто не анализирует&#xA;историю изменений коммит за коммитом. Вместо этого история - это просто такая&#xA;база данных, хранящая связи между изменениями в коде, и работать с ней нужно как&#xA;с базой данных - с помощью языка запросов, оперируя большими наборами коммитов&#xA;(т.е. ветками). Полноценная поддержка операции копирования означает, слияние&#xA;веток требует анализа каждого коммита между этими ветками (медленно). Git же&#xA;обходится только анализом начального и конечного состояния дерева файлов,&#xA;пропуская промежуточные состояния.&lt;/p&gt;&#xA;&lt;p&gt;Что же тут плохого, спросите вы? В данном случае проблема упирается в психологию&#xA;людей. Да, соглашается подавляющее большинство разработчиков, - поддержка&#xA;копирования и пустые директории в принципе не нужны. Но! Мы к ним так привыкли.&#xA;Мы хотим линейную историю, явную поддержку копирования и пустые директории.&#xA;Нам без них не уютно.&lt;/p&gt;&#xA;&lt;p&gt;Вы будете смеяться, но это реальная проблема. Особенно, когда мигрируешь с&#xA;Subversion на Git.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Но ведь оно раньше работало. Я мог сделать так и так.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Полностью согласен, но, на кой, простите, вам это нужно делать именно таким&#xA;способом?&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Но ведь это единственный правильный способ. Мы так всегда делали&amp;hellip;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;У нас на работе есть коробка с плюшевыми медведями - специально для таких&#xA;случаев. Когда ситуация заходит в тупик и разумные аргументы уже не помогают в&#xA;дело вступают плюшевые медведи. Коллеге, чью любимую &lt;a href=&#34;https://xkcd.com/1172/&#34;&gt;фичу пришлось отдать в&#xA;жертву прогрессу&lt;/a&gt;, на руки выдается плюшевый медведь - дабы облегчить тяжесть&#xA;утраты.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Уроки разработки полетного софта</title>
      <link>https://blog.not-a-kernel-guy.com/2018/02/17/fsw-lessons/</link>
      <pubDate>Sat, 17 Feb 2018 21:00:54 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/02/17/fsw-lessons/</guid>
      <description>&lt;p&gt;Часто, когда речь заходит про космический софт, можно слышать &amp;ldquo;ну уж там-то код&#xA;компилируется со всеми предупреждениями&amp;rdquo;, или &amp;ldquo;ну уж там-то наверняка запускается&#xA;статический анализатор кода и все ошибки исправляются&amp;rdquo;, или &amp;ldquo;ну уж там то тесты&#xA;покрывают код на 100%&amp;rdquo;. Как вы скорее всего уже догадались рая нет. Вернее, рай&#xA;в планах был, но из-за превышения сметы успели достроить только ад. К счастью,&#xA;костры успели развести только под половиной котлов, поскольку часть дров&#xA;заменили бетонными шпалами, а расположение котлов забыли задокументировать.&lt;/p&gt;&#xA;&lt;p&gt;Сайт &lt;a href=&#34;https://llis.nasa.gov&#34;&gt;NASA Lessons Learned&lt;/a&gt; полон таких историй. Сегодня мы пройдемся по&#xA;результатам исследования &lt;a href=&#34;http://aisel.aisnet.org/cgi/viewcontent.cgi?article=1671&amp;amp;context=amcis2009&#34;&gt;Flight Software Engineering Lessons&lt;/a&gt; за авторством&#xA;Ronald Kirk Kandt опубликованное на конференции AMCIS 2009 (Americas Conference&#xA;on Information Systems). Автор исследования просуммировал результаты других&#xA;работ, посвященных трудностям процесса разработки программного обеспечения, а&#xA;также результаты расследования аварий реальных космических аппаратов.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Потеря связи с зондом Deep Impact в 2013 году</title>
      <link>https://blog.not-a-kernel-guy.com/2018/02/14/epoxi/</link>
      <pubDate>Wed, 14 Feb 2018 20:15:47 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2018/02/14/epoxi/</guid>
      <description>&lt;p&gt;12 января 2005 года с мыса Канаверал стартовал зонд Deep Impact, созданный для&#xA;изучение внутреннего состава кометы 9P/Темпеля. Зонд достиг кометы в июле 2005&#xA;года, после чего разделился на импактор и пролетную часть. 4 июля 2005 года&#xA;370 килограммовый импактор успешно столкнулся с ядром кометы на скорости около&#xA;10.3 км/с, выбросив в космос здоровенное облако пыли:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://upload.wikimedia.org/wikipedia/commons/3/3e/Deep_Impact_HRI.jpeg&#34;&gt;&lt;img src=&#34;https://blog.not-a-kernel-guy.com/2018/02/Deep_Impact_HRI.jpeg&#34; alt=&#34;&#34; title=&#34;Столкновение импактора с ядром кометы 9P/Темпеля&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;Согласно измерениям, проведенным космическим аппаратом &lt;a href=&#34;https://en.wikipedia.org/wiki/Stardust_(spacecraft)&#34;&gt;Stardust&lt;/a&gt; в 2011&#xA;году, диаметр кратера, образовавшегося в результате столкновения, составил около&#xA;150 метров.&lt;/p&gt;&#xA;&lt;p&gt;По завершению основной миссии, NASA направило зонд Deep Impact к комете&#xA;103P/Хартли в рамках расширенной миссии &amp;ldquo;EPOXI&amp;rdquo;. Пролет этой кометы&#xA;состоялся 4 ноября 2010 года:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://blog.not-a-kernel-guy.com/2018/02/NASAHartley2Comet.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;В конце 2011 года, аппарат был отправлен на перехват астероида&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/(163249)_2002_GT&#34;&gt;(163249) 2002 GT&lt;/a&gt; пролет которого должен был состоятся в 2020 году. Однако&#xA;в августе 2013 года контакт с аппаратом был потерян:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;a href=&#34;http://epoxi.astro.umd.edu/1mission/status.shtml&#34;&gt;3 сентября 2013&lt;/a&gt;:&lt;br&gt;&#xA;&amp;hellip; Связь с аппаратом утеряна между 11 и 14 августа (связь с аппаратом&#xA;поддерживается раз в неделю). Последний сеанс связи был проведен 8 августа.&#xA;Проведенное расследование позволило установить причину неполадки. Дальнейшие&#xA;усилия направлены на определение лучшего способа восстановить связь с&#xA;аппаратом.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;a href=&#34;http://epoxi.astro.umd.edu/1mission/status.shtml&#34;&gt;23 сентября 2013&lt;/a&gt;:&lt;br&gt;&#xA;&amp;hellip; все попытки передачи низкоуровневых аппаратных команд не увенчались&#xA;успехом. На этом все возможные сценарии восстановления связи с аппаратом были&#xA;исчерпаны. Мы рекомендовали NASA объявить аппарат утерянным. NASA официально&#xA;заявило об утере аппарата в четверг 19 сентября.&lt;/p&gt;&#xA;&lt;/blockquote&gt;</description>
    </item>
    <item>
      <title>Свежая презентация про полетный софт в SpaceX</title>
      <link>https://blog.not-a-kernel-guy.com/2017/12/11/bazel-spacex/</link>
      <pubDate>Mon, 11 Dec 2017 19:22:00 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2017/12/11/bazel-spacex/</guid>
      <description>&lt;p&gt;Свежая презентация про полетный софт в SpaceX в целом, и про миграцию с make на&#xA;&lt;a href=&#34;https://bazel.build/&#34;&gt;Bazel&lt;/a&gt; в частности:&lt;/p&gt;&#xA;&#xA;&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;&#xA;  &lt;iframe src=&#34;https://www.youtube.com/embed/t_3bckhV_YI&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;Основные моменты:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Два основных репозитория: один содержит полетный код, второй - код симуляции.&#xA;Более миллиона строк C++ в каждом. Немного Python.&lt;/li&gt;&#xA;&lt;li&gt;Используется своя версия Linux, поддержкой которой занимается отдельная&#xA;команда.&lt;/li&gt;&#xA;&lt;li&gt;C++ код собирается под несколько разных процессорных архитектур.&lt;/li&gt;&#xA;&lt;li&gt;Полетный код для Falcon и Dragon собирается из одного репозитория.&lt;/li&gt;&#xA;&lt;li&gt;&amp;ldquo;Test like you fly&amp;rdquo; - код тестируется в тех же самых условиях, что наблюдаются&#xA;в полете. Софт и железо тестируются как единая интегрированная система.&lt;/li&gt;&#xA;&lt;li&gt;Система непрерывной интеграции выполняет более 8 тысяч заданий в день.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Вторая половина презентации посвящена миграции с древней системы сборки на&#xA;основе make на более современный Bazel. Эта часть будет интересна в основном&#xA;тем, кто интересуется системами сборки кода.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Не число</title>
      <link>https://blog.not-a-kernel-guy.com/2017/10/08/nan/</link>
      <pubDate>Sun, 08 Oct 2017 19:23:03 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2017/10/08/nan/</guid>
      <description>&lt;p&gt;Числа с плавающей запятой обманчиво привычны и из-за этого гораздо более коварны,&#xA;чем кажется. Общеизвестно, что результат вычислений с плавающей запятой нельзя&#xA;сравнивать на точное равенство - из-за погрешности вычислений совпадение двух&#xA;величин с точностью до бита маловероятен. Но это только самая вершина айсберга.&#xA;На точность влияет порядок вычислений, используемая платформа, математическая&#xA;библиотека, процессор и т.д.&lt;/p&gt;&#xA;&lt;p&gt;Сегодня я хотел бы поговорить о такой особенности чисел с плавающей запятой, как&#xA;&amp;ldquo;не число&amp;rdquo;. Он же &lt;code&gt;NaN&lt;/code&gt; (not a number). &lt;code&gt;NaN&lt;/code&gt; - это специальное значение, которое&#xA;возвращается как результат некоторых операций - например результат деления ноля&#xA;на ноль.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Непредсказуемость динамической памяти</title>
      <link>https://blog.not-a-kernel-guy.com/2017/07/30/malloc/</link>
      <pubDate>Sun, 30 Jul 2017 13:03:30 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2017/07/30/malloc/</guid>
      <description>&lt;p&gt;Написал небольшую программу, демонстрирующую непредсказуемую стоимость выделения&#xA;динамической памяти. Программа выделяет и освобождает N блоков одного размена и&#xA;измеряет среднее время, затраченное на один вызов malloc() и один вызов free():&lt;/p&gt;</description>
    </item>
    <item>
      <title>rr</title>
      <link>https://blog.not-a-kernel-guy.com/2017/05/07/rr/</link>
      <pubDate>Sun, 07 May 2017 18:56:38 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2017/05/07/rr/</guid>
      <description>&lt;p&gt;Недавно наткнулся на &lt;a href=&#34;http://rr-project.org/&#34;&gt;rr (Record and Replay Framework)&lt;/a&gt;&#xA;от Mozilla и я вам скажу, что это просто незаменимый инструмент для ловли&#xA;неуловимых багов в отладчике. Это не первый и не единственный инструмент&#xA;подобного плана. &lt;a href=&#34;https://github.com/mozilla/rr/wiki/Related-work&#34;&gt;Соответствующая страница проекта&lt;/a&gt;&#xA;описывает десятка три альтернатив. Из этого списка мне раньше доводилось&#xA;работать только с iDNA, который впоследствии стал &lt;a href=&#34;http://www.thewindowsclub.com/microsoft-time-travel-tracing-diagnostic&#34;&gt;Time Travel Tracing&#xA;&lt;/a&gt; (TTT).&#xA;TTT мог записать процесс выполнения программы с точностью до инструкции и&#xA;воспроизвести его в точности в прямом и обратном направлении. TTT был просто&#xA;незаменим для ловли сложных багов и его главным недостатком было то, что TTT был&#xA;внутренним инструментом, который Microsoft так и не выпустила как отдельный&#xA;продукт.&lt;/p&gt;&#xA;&lt;p&gt;rr тоже может записать выполнение процесса с точностью до инструкции и проиграть&#xA;его назад и вперед. rr требует современного процессора, причем обязательно&#xA;Intel, так как использует performance counters которые не реализованы в других&#xA;процессорах. ARM и другие архитектуры тоже не поддерживаются. В обмен на это,&#xA;rr практически не замедляет записываемый процесс. Скорость выполнения падает в&#xA;1.2 раза - сущие пустяки. Размер генерируемой записи тоже крайне скромен - в&#xA;районе гигабайта за 10-15 минут выполнения “вычислительного” кода. Практически&#xA;бесплатно. В пересчете на количество выполненных инструкций получается что-то&#xA;вроде 0.1 бита на выполненную инструкцию.&lt;/p&gt;&#xA;&lt;p&gt;Что интересно, rr базируется на очень простой идее: большая часть кода&#xA;выполняется всегда одинаково. Если записать все случайные события (ввод/вывод,&#xA;RDTSC, системный вызовы) и начальные условия (содержимое памяти), то процесс&#xA;выполнения становится полностью детерминированным. Более детально можно почитать&#xA;здесь: &lt;a href=&#34;http://rr-project.org/rr.html&#34;&gt;http://rr-project.org/rr.html&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Процесс отладки с помощью rr выглядит так:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Записываем процесс: &lt;code&gt;rr record &amp;lt;program&amp;gt;&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Запускаем запись в отладчике: &lt;code&gt;rr replay&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Проматываем до конца и смотрим чем вызван segfault.&lt;/li&gt;&#xA;&lt;li&gt;Ставим watchpoint на память из которой читается плохой указатель.&lt;/li&gt;&#xA;&lt;li&gt;Выполняем программу назад пока не сработает watchpoint.&lt;/li&gt;&#xA;&lt;li&gt;Смотрим почему в память пишется плохой указатель и повторяем шаги 4-6 до&#xA;победного конца.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Дополнительный бонус заключается в том, что все адреса при повторном&#xA;воспроизведении сохраняются. Если нужная переменная находится по адресу&#xA;&lt;code&gt;0x123fooba&lt;/code&gt;, то она там будет всегда. Отпадает необходимость выяснять где в&#xA;памяти находится интересный кусок каждый раз при запуске отладчика. rr также&#xA;может помечать вывод в stdout метками для быстрой перемотки в нужное место.&#xA;Это помогает сопоставить код с интересными местами в лог файлах.&lt;/p&gt;&#xA;&lt;p&gt;Само собой, у rr есть куча других ограничений. К примеру, он не работает под&#xA;Windows, не поддерживаются все системные вызовы, не поддерживается циклическая&#xA;запись (последние несколько минут выполнения процесса), поддерживается только&#xA;одно процессорное ядро, и т.д. Тем не менее, если вы столкнулись с “невозможным”&#xA;багом в Linux, rr - один из наиболее вероятных способов докопаться до источника&#xA;проблемы.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Идеальный инструмент для просмотра кода</title>
      <link>https://blog.not-a-kernel-guy.com/2016/11/27/an-ideal-code-review-tool/</link>
      <pubDate>Sun, 27 Nov 2016 17:54:01 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2016/11/27/an-ideal-code-review-tool/</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;!-- raw HTML omitted --&gt;Здравствуйте. Меня зовут Алексей и я каждое утро просматриваю&#xA;чужой код&amp;hellip;&lt;!-- raw HTML omitted --&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;За последнее время пришел к выводу, что ни один из известных мне инструментов&#xA;для просмотра кода (в смысле &amp;ldquo;code review&amp;rdquo;) решительно не годится для выполнения&#xA;своей главной функции.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Налоговая декларация</title>
      <link>https://blog.not-a-kernel-guy.com/2016/03/19/1806/</link>
      <pubDate>Sat, 19 Mar 2016 22:41:18 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2016/03/19/1806/</guid>
      <description>&lt;p&gt;В Штатах, и особенно в южной Калифорнии, о наступлении весны напоминает процесс заполнения налоговой декларации. Сначала, еще в январе, начинают приходить имейлы: “Ваша форма W-2/1098/1099-B/DIV/MISC будет готова к концу января. Потерпите”. Ближе к февралю начитают приходить обещанные налоговые формы. Потом активизируется TurboTax: “Спешите отправить Tax Return сейчас, пока мы еще добрые и даем скидку”. К апрелю активность TurboTax достигает максимума: “Скидку вы, конечно, профукали, но можно подать на продление и отложить час расплаты на полгода.”&lt;/p&gt;</description>
    </item>
    <item>
      <title>Писать на фортране можно на любом языке</title>
      <link>https://blog.not-a-kernel-guy.com/2014/01/29/1562/</link>
      <pubDate>Wed, 29 Jan 2014 22:37:41 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2014/01/29/1562/</guid>
      <description>&lt;p&gt;Господа, какой-же все-таки махровый &lt;em&gt;&amp;amp;^%&lt;/em&gt;! Вот посмотрите &lt;a href=&#34;https://github.com/JuliaLang/openlibm/blob/master/src/k_rem_pio2.c#L294&#34;&gt;сюда&lt;/a&gt;. Это код библиотеки OpenLIBM, которая, цитирую:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;OpenLIBM is an effort to have a &lt;strong&gt;high quality&lt;/strong&gt; standalone LIBM library.&lt;/p&gt;&#xA;&lt;/blockquote&gt;</description>
    </item>
    <item>
      <title>Будни Chromium разработчика</title>
      <link>https://blog.not-a-kernel-guy.com/2013/02/05/1467/</link>
      <pubDate>Tue, 05 Feb 2013 01:12:53 -0700</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2013/02/05/1467/</guid>
      <description>&lt;p&gt;Хотите знать как выглядит процесс коммита в &lt;a href=&#34;http://www.chromium.org/Home&#34;&gt;Chromium&lt;/a&gt;? Есть у меня такие истории. Для затравки уточню терминологию. Chromium - это, фактически, open source версия &lt;a href=&#34;https://www.google.com/intl/en/chrome/browser/&#34;&gt;Chrome&lt;/a&gt;. Если взять Chromium и добавить немного закрытого кода и логотип Google, то получится Chrome. А вот если добавить немного закрытого кода и логотип Яндекс, то получится &lt;a href=&#34;http://browser.yandex.ru/&#34;&gt;Яндекс.Браузер&lt;/a&gt;. Исходники &lt;a href=&#34;https://chrome.google.com/webstore/detail/chrome-remote-desktop/gbchcmhmhahfdphkhkmpfmihenigjmpp?hl=en&#34;&gt;Chrome Remote Desktop&lt;/a&gt;, над которым работаю я с коллегами, тоже собираются из репозитория Chromium.&lt;/p&gt;&#xA;&lt;p&gt;Так вот, про процесс коммита.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Трассировка описателей (AKA handle tracing)</title>
      <link>https://blog.not-a-kernel-guy.com/2012/12/04/1437/</link>
      <pubDate>Tue, 04 Dec 2012 23:23:13 -0800</pubDate>
      <guid>https://blog.not-a-kernel-guy.com/2012/12/04/1437/</guid>
      <description>&lt;p&gt;Начиная с Windows XP в ядро встроена поддержка трассировки описателей ядра (AKA handle tracing). Включение трассировки имеет двойной эффект. Во-первых, все операции с ядерными описателями сохраняются в циклический буфер (откуда их можно потом прочитать). Во-вторых, при любой попытке использовать несуществующий описатель генерируется исключение STATUS_INVALID_HANDLE. Фактически, проверка корректности операций с описателями в &lt;a href=&#34;http://msdn.microsoft.com/en-us/library/windows/desktop/dd371695(v=vs.85).aspx&#34;&gt;Application Verifier&lt;/a&gt; - это тонкая обертка вокруг функций трассировки, предоставляемых ядром. Расширение отладчика !htrace - аналогично.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
