<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
	<channel>
		<title>Блог Александра Купреева</title>
		<link>http://kupreev.com/</link>
		<description></description>
		<pubDate>Thu, 07 Jan 2016 18:12:15 +0500</pubDate>
		<language>en-ru</language>
		<generator>MaxSite CMS (http://max-3000.com/)</generator>
		<copyright>Copyright 2023, http://kupreev.com/</copyright>
				<item>
			<title><![CDATA[С праздником Рождества Христова!]]></title>
			<link>http://kupreev.com/page/christmas-2016</link>
			<guid>http://kupreev.com/page/christmas-2016</guid>
			<pubDate>Thu, 07 Jan 2016 18:12:15 +0500</pubDate>
			<category><![CDATA[просто Дневник, Христианство]]></category>
			<description><![CDATA[
<p>Не успеваешь оглянуться - снова зима и радостный не смотря на всю мою угрюмость праздник Рождества. Желаю здоровья, любви и энергичности, проактивности в делах! На таком морозе, да в праздник никак нельзя тянуться унылой селедкой.</p>
<p>Подумал, над какими сторонними проектами мне бы хотелось поработать, если б оказалось свободное время. Из самого свежего, только неоформленные идеи: </p>

<li> рабочая среда для программирования, в которой задействуется не только голова и пальцы, а все тело. Чтобы не сидеть скрючившись в три погибели с неприятными последствиями, а иметь (опциональную) возможность энергично подвигаться. Например, дополненная реальность, где можно руками (и ногами?) активировать макросы, доставать определения методов и т.д., и плюс отладка, конечно (характерный взмах руки - запустили тесты, указал на ошибку - перешли к проблемному коду и т.д.). Да еще голосовое управление. Для командной работы сложно. А дома размяться самое то было бы: "Сейчас я станцую класс для ведения логов".</li>
<li> сервис для общения людей пожилого возраста. Что-то типа гибрида видеочата и социальной сети с учетом ограниченных возможностей и плохого знакомства с компьютерными интерфейсами. Большой шрифт, голосовое взаимодействие с программой, облегченный поиск желающих пообщаться. </li>
<p>Думаю, кто-нибудь подобное уже делает.</p>
<p>А над чем было бы интересно вам поработать?</p>
<a href="http://kupreev.com/page/christmas-2016#comments"> Discuss</a>]]></description>
		</item>
				<item>
			<title><![CDATA[How Linux Works: What Every Superuser Should Know]]></title>
			<link>http://kupreev.com/page/review-how-linux-works-what-every-superuser-should-know</link>
			<guid>http://kupreev.com/page/review-how-linux-works-what-every-superuser-should-know</guid>
			<pubDate>Sat, 02 May 2015 00:48:30 +0500</pubDate>
			<category><![CDATA[Обзоры]]></category>
			<description><![CDATA[
<p>Прочел книгу "How Linux Works: What Every Superuser Should Know" by Brian Ward.</p>
<p><strong>О чем книга?</strong></p>
<p>Книга стремится дать общее представление об устройстве Linux-подобных ОС. Начинает с основ и постепенно раскрывает общую картину: командная строка, основные команды, устройства, диски, файловая система, загрузка ядра, user space, конфигурация, логирование, крон, процессы, сеть, десктоп, инструменты разработчика и т.д. В книге чуть более 300 страниц, изложить все одинаково подробно нереально. Поэтому автор более подробно раскрывает базовые вещи (принципы устройства, команды и их вывод и т.д.) и очень кратко касается специальных тем: десктопа, разработки, приложений и сервисов. Каких-то секретов и тонкостей устройства, настройки и т.п. в книге не нашел. </p>
<p><strong>Что понравилось?</strong></p>
<p>Практическая ориентированность. Акцент делается на решаемых задачах, более того, автор предлагает все примеры прорабатывать в командной строке - к сожалению, у меня времени на это не было. Теоретические сведения тоже есть, но по минимуму, иногда хочется побольше. </p>
<p>Радует понятное изложение. К примеру, рассказ о базовом конфигурировании фаервола не вызвал вопросов, в отличие от прочитанных ранее how-to.</p>
<p><strong>Что не понравилось?</strong></p>
<p>Отсутствие некоторых интересных тем, например, IPv6. А некоторые темы показались лишними <img src="http://kupreev.com/uploads/smiles/smile.gif" width="19" height="19" alt="smile" style="border:0;" class="smiley"></p>
<p><strong>Для чего может быть полезна?</strong> </p>
<p>При моем уровне работы с Linux (десктоп + изредка местами сервер) книга полезна как общее введение в тему, которое нелишне прочитать для ознакомления. Думаю, ее уровень отвечает знаниям идеального "администратора начального уровня".</p>
<p><strong>Оценка</strong></p>
<p>4/5 (нужная книга)</p>
<a href="http://kupreev.com/page/review-how-linux-works-what-every-superuser-should-know#comments"> Discuss</a>]]></description>
		</item>
				<item>
			<title><![CDATA[Христос воскрес!]]></title>
			<link>http://kupreev.com/page/christ-is-risen-2015</link>
			<guid>http://kupreev.com/page/christ-is-risen-2015</guid>
			<pubDate>Sun, 12 Apr 2015 15:55:26 +0500</pubDate>
			<category><![CDATA[Христианство]]></category>
			<description><![CDATA[
<p><span style="color:red">Христос воскрес!</span> Это лучший повод для радости несмотря ни на что.</p>
<a href="http://kupreev.com/page/christ-is-risen-2015#comments"> Discuss</a>]]></description>
		</item>
				<item>
			<title><![CDATA[Делаю ToDoLog &#45; часть 3. Response]]></title>
			<link>http://kupreev.com/page/working-on-todolog-part3-response</link>
			<guid>http://kupreev.com/page/working-on-todolog-part3-response</guid>
			<pubDate>Tue, 10 Jun 2014 18:06:23 +0500</pubDate>
			<category><![CDATA[Технологии]]></category>
			<description><![CDATA[
<p>С концепцией запроса в целом разобрался, что делать с результатами работы Интерактора? В каком формате возвращать результат, как учесть ошибки и валидацию данных? Думаю, что Интерактор должен возвращать объект Ответа. Мотивация аналогична объекту Запроса: четкая структура ответа и типизация, более абстрактный Интерактор не должен заботиться о конкретном формате возвращаемых данных, требуемом клиентской стороной. С другой стороны, клиент будет знать структуру возвращаемых данных и сможет с ними работать.</p>
<p>Следующий вопрос: как возвращать объект Ответа? Вижу два основных варианта. В первом объект создается внутри интерактора и после заполнения данными отправляется наружу. Во втором в интерактор передается пустой (установленный по умолчанию) объект ответа, который внутри заполняется данными. Какой вариант предпочтительнее? Это зависит от того, что нужно делать в контроллере с этим объектом. Если понадобится расширять и дополнять его, то предпочтителен второй вариант. Такая возможность полезна, ведь одни и те же данные часто нужно возвращать на клиент в разном виде. Поэтому для контроллеров может понадобиться дополнительная функциональность, облагораживающая данные для показа в конкретном шаблоне.</p>
<p>Сначала я написал реализацию с созданием объекта ответа внутри интерактора (<a href="https://github.com/AlexKupreev/todolog/commit/0d29b024aa6ef33679334c87bcf20b2dfebfa128" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">коммит</a>). Базовый класс <code>Response</code>
 содержит поля для статуса ответа и ошибок, если таковые возникнут. Плюс геттеры и сеттеры для статуса. Это общая функциональность, которая нужна всем классам-наследникам. В последних задаются конкретные поля для возвращаемых данных. </p>
<p>По некотором размышлении подумалось, что правильнее использовать второй вариант - создание чистого объекта ответа на клиенте (в контроллере) и передача его для заполнения в интерактор. Основную роль в этом убеждении сыграли вышеприведенные соображения плюс соображения о предпочтении интерфейсов реализациям. Так и <a href="https://github.com/AlexKupreev/todolog/commit/03068ecc828ae0763cbd44bdd065841982667769" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">переделал</a>.</p>
<p>И еще. В интеракторе создания задачи разделил само по себе создание объекта-задачи и добавление его в репозиторий (<a href="https://github.com/AlexKupreev/todolog/commit/5ea7e0744bcfb5915d3f7031a6b768cc64b8e3ce" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">коммит</a>). По-хорошему, создание объекта и сохранение его не связаны между собой по смыслу. Не всегда созданный объект нужно сохранять, можно, например, вернуть его клиенту в ответ на запрос. Поэтому добавление созданного объекта будет производиться при помощи метода <code>Repo\TaskInterface::add(Entity\Task $task)</code>
. За создание объекта отвечает метод <code>Repo\TaskInterface::create(...)</code>
 (<a href="https://github.com/AlexKupreev/todolog/commit/5ea7e0744bcfb5915d3f7031a6b768cc64b8e3ce" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">коммит</a>). Он позволяет избежать явного создания Сущности там, где она нужна. </p>
<p>Итак, использование отдельного объекта Ответа унифицирует формат возвращаемых в контроллер данных и отвязывает эти данные от типа ответа клиенту.</p>
<a href="http://kupreev.com/page/working-on-todolog-part3-response#comments"> Discuss</a>]]></description>
		</item>
				<item>
			<title><![CDATA[Делаю ToDoLog &#45; часть 2. Request]]></title>
			<link>http://kupreev.com/page/working-on-todolog-part2-request</link>
			<guid>http://kupreev.com/page/working-on-todolog-part2-request</guid>
			<pubDate>Thu, 05 Jun 2014 14:00:08 +0500</pubDate>
			<category><![CDATA[Технологии]]></category>
			<description><![CDATA[
<p>Один из недостатков кода - механизм обработки данных внешних запросов. Сейчас данные новой задачи передаются в Интерактор обычным массивом, внутри дополняются, модифицируются, потом из них строится Сущность. Проверяется наличие нужных полей, заполняются значения по-умолчанию, и вот они уже образовали новый объект-задачу. Главной проблемой такого подхода является априорное знание Сущности и Интерактора о поступивших данных - что это массив, какие поля он содержит. По сути, в этом нет ничего плохого, должен же Интерактор знать, что ему нужно для работы? Проблема в том, что нужно знать о формате входных данных. Представьте, что они приходят не из массива <code>$_POST</code>
, а от запроса через API, или из командной строки. А если поле из <code>$_POST</code>
 - массив, а шлюз к API возвращает объект? Нужно либо предусмотреть в Интеракторе или Сущности обработку по-разному организованных входных данных, либо заранее привести входные данные к известному формату. Первое нарушает правило <em>Clean Architecture</em> - более абстрактные слои не должны зависеть от менее абстрактных. Второе приемлемо: можно привести "сырой" запрос к стандартному виду, откуда бы он не поступил, а уже "причесанный" отправить для обработки в Интерактор. В качестве такого "причесанного" можно задействовать массив с известными полями, но более адекватным, на мой взгляд, будет использование объекта с уникальными свойствами для каждого типа запроса (<a href="https://github.com/AlexKupreev/todolog/commit/779eb8ad08e727092a7e652b0ddae2cadbd257ea" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">коммит</a>). Для объектов в PHP легче задавать структуру, можно требовать передачи в функцию параметра определенного класса, что автоматически определяет его сигнатуру. Возможность добавлять и переопределять методы-обработчики тоже не будет лишней. </p>
<p>При таком подходе передача в конструктор сущности Task массива параметров становится бессмысленной. Нужно передавать отдельные поля. Вопрос только в том, все ли поля передавать сразу в конструктор. Нормально ли, если объект появится без поля userId, например? И когда считать объект корректным и валидировать его корректность? Пока буду передавать в конструктор все, что нужно, и формировать корректный объект (<a href="https://github.com/AlexKupreev/todolog/commit/b073ac7b0e377a8cbe95978c5fe5305725349eab" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">коммит</a>). </p>
<p>И, конечно, нужно аналогично переделать создание сущности User. Интеракторов для нее пока нет, так что в сценарии передаем параметры вручную (<a href="https://github.com/AlexKupreev/todolog/commit/5ca7cecb1062dda0a406cd86677b791610a3a8aa" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">коммит</a>).</p>
<p><strong>Резюме:</strong> теперь интерактор не знает о том, откуда получен запрос и какая его внутренняя структура. Получает нужные данные в стандартном виде.</p>
<a href="http://kupreev.com/page/working-on-todolog-part2-request#comments"> Discuss</a>]]></description>
		</item>
				<item>
			<title><![CDATA[Делаю ToDoLog &#45; часть 1]]></title>
			<link>http://kupreev.com/page/working-on-todolog-part1</link>
			<guid>http://kupreev.com/page/working-on-todolog-part1</guid>
			<pubDate>Sat, 31 May 2014 15:10:54 +0500</pubDate>
			<category><![CDATA[Технологии]]></category>
			<description><![CDATA[
<p>В прошлый раз я <a href="http://kupreev.com/page/starting-todolog" >озадачился двумя вопросами о Clean Architecture</a>: как работать со структурами данных типа дерева и какими все же должны быть Сущности. Подумав и почитав ветки, пришел к следующему.</p>
<p>Структура данных Сущности должна отображаться либо в ней самой, либо в специально созданной другой сущности. Но при этом служебным данным в них не место. Например, если нужно иметь дерево задач, я могу эмулировать его свойством <em>children</em>, куда помещать задачи-непосредственные потомки. Или же создать отдельную сущность <em>TaskTree</em>, которая будет содержать иерархию <em>Task</em>. Думаю, на теперешнем этапе более приемлем первый вариант. </p>

<pre lang=php>public $children = &#91;&#93;;</pre>
<p>Разумеется, должны добавиться методы, обрабатывающие эту иерархию, в нашем случае <code>addChild()</code>
, <code>removeChild()</code>
  и другие. Чтобы не грузить каждый раз всю иерархию, можно добавить поле <code>$hasChildren</code>
, которое будет показывать, есть ли у задачи потомки. </p>
<p>Далее. Как я понял из комментариев, Сущность в первую очередь должна определять бизнес-правила обработки себя. Заполнение, выборка, валидация — все, что работает на высшем, самом абстрактном уровне иерархии приложения. При этом непосредственного доступа к данным она может и не иметь. То есть, Сущность может и должна быть абстрактным классом, от которой наследуются конкретные реализации с ORM, например. Такое усложнение и вызвано, по-видимому, наличием слоя ORM, который сам работает с БД, но при этом должен реализовать требуемые бизнес-методы сущности. Это говорит о том, что у меня все неправильно. Впрочем, ломать сейчас не буду. Есть частные мнения, что сущности все же могут быть конкретными классами с нормальными полями данных, формироваться из данных БД они могут в Репозиториях. Кроме того, хочу, чтобы изменения в коде были естественными, а пока не вижу необходимости менять реализацию класса.</p>
<p>На сегодняшний день реализован <a href="https://github.com/AlexKupreev/todolog/commit/0f80973be9579424ebb76157d681b39ae988293d" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">сценарий создания задачи</a>. </p>

<pre lang=php>$taskCreator = new Interactor\Task\Creation($this-&gt;taskRepo, $this-&gt;userRepo, $this-&gt;sessionService);
$this-&gt;boolResult = $taskCreator-&gt;execute($data);</pre>
<p>При создании в него инжектируются репозитории задачи и пользователя, а также сервис для работы с сессией. Для выполнения он получает на вход данные новой задачи, которые дополняет ID создателя и вызывает метод создания задачи в репозитории.</p>

<pre lang=php>$data&#91;'userId'&#93; = $this-&gt;session-&gt;getLoggedInUserId();
$this-&gt;taskRepo-&gt;create($data);</pre>
<p>В чем достоинство такого кода? Создание задачи отделено от обслуживающего вызов кода (в данном случае, теста). Бизнес-логика реализуется внутри Интерактора, только он знает, какие поля выбрать, куда записать и как сохранить. Но при этом абстрагируется от конкретного способа сохранения — сейчас за это отвечает mock-репозиторий , работающий с оперативной памятью.</p>
<p>Недостатков у кода много, о них пока не буду. Интересно посмотреть, как такой код может взаимодействовать с запросами извне.</p>
<a href="http://kupreev.com/page/working-on-todolog-part1#comments"> Discuss</a>]]></description>
		</item>
				<item>
			<title><![CDATA[Начал работу над пробным проектом Clean Architecture]]></title>
			<link>http://kupreev.com/page/starting-todolog</link>
			<guid>http://kupreev.com/page/starting-todolog</guid>
			<pubDate>Sun, 18 May 2014 17:32:31 +0500</pubDate>
			<category><![CDATA[Технологии]]></category>
			<description><![CDATA[
<p>Начал писать <a href="https://github.com/AlexKupreev/todolog" onclick="javascript:pageTracker._trackPageview('/outbound/github.com');">код приложения</a> (простой ToDo-менеджер-журнал). Пока что все просто, не знаю, стоит ли что-то пояснять. Описал первые сценарии, вырисовалась структура для Сущностей/Интеракторов/Границ. Предполагается, что на первых порах сценарии будут работать с фиктивными (mock) источниками данных и сервисами. Работу с сессией реализовал в виде сервиса, а не репозитория, поскольку хранение данных текущего пользователя возможно не только в сессии, но и, например, с использованием токенов. Идея сервиса для обработки таких вещей кажется более уместной. </p>
<p><img src="http://kupreev.com/uploads/todolog-struct.png" title="" alt=""></p>
<p>Столкнулся и с первой архитектурной проблемой. Набор задач логично организовать в виде дерева, с иерархией подзадач. Но как отобразить ее в нашей Сущности задачи? С одной стороны, чего проще — ввести дополнительные поля для работы с Nested Sets или Adjacency List. Но эти поля будут отображением реляционной таблицы в нашу Сущность. А Сущность не должна знать о внутреннем устройстве системы хранения данных! Стал копать <a href="https://groups.google.com/d/msg/clean-code-discussion/_5R8JZ4vWSs/lzEH6Q8G21MJ" onclick="javascript:pageTracker._trackPageview('/outbound/groups.google.com');">гуглогруппу о Clean Architecture</a>  - и запутался еще больше. Оказывается, Сущность не должна быть отображением нашего объекта данных.</p>

<blockquote><strong>Misconception #1: Entities are data.</strong>  <br>
Entities are not data.  Entities are objects, and objects have functions that implement business rules.  Entities may _use_ data; but the _are not_ data.  Entities are behavior.</blockquote>

<p>Еще один удар в рушащуюся картину мира нанес следующий пункт</p>

<blockquote><strong>Misconception #2: Entities, Database, and Web use the same data</strong><br>
They most definitely do _not_.  Databases store data in strange and arcane formats (like tables) that is inconvenient for most business rule calculations.  For that reason we often use ORMs to map the tables into more convenient data structures.  Entities use the data from those data structures; but the mapping is not one-to-one.  Very often a given entity will use more than one of those data structures.  ...  The mapping is complex.  Moreover, most entities only want certain data elements, and not the entire data structure.  So, to keep the entities from knowing too much, it is wise to map the generic data structures that come from the database into entity-specific data structures that keep the entities decoupled from data they don't need.<br>
...<br>
Be very careful.  The temptation to use the same data structures (even the same objects) throughout the entire system is strong at first, and can lead you into a coupling nightmare.  Keep these tiers separate.   Allow the structure of the data in each tier to conform to the needs of _that_ tier.</blockquote>

<p>На этом я пока остановился. Нужно собраться с мыслями и понять, как же должны работать Сущности здорового программиста.</p>
<a href="http://kupreev.com/page/starting-todolog#comments"> Discuss</a>]]></description>
		</item>
			</channel>
</rss>
