Блог Александра Купреева

С праздником Рождества Христова!

Просмотров: 769Комментарии: 0
Христианствопросто Дневник

Не успеваешь оглянуться - снова зима и радостный не смотря на всю мою угрюмость праздник Рождества. Желаю здоровья, любви и энергичности, проактивности в делах! На таком морозе, да в праздник никак нельзя тянуться унылой селедкой.

Подумал, над какими сторонними проектами мне бы хотелось поработать, если б оказалось свободное время. Из самого свежего, только неоформленные идеи:

  • рабочая среда для программирования, в которой задействуется не только голова и пальцы, а все тело. Чтобы не сидеть скрючившись в три погибели с неприятными последствиями, а иметь (опциональную) возможность энергично подвигаться. Например, дополненная реальность, где можно руками (и ногами?) активировать макросы, доставать определения методов и т.д., и плюс отладка, конечно (характерный взмах руки - запустили тесты, указал на ошибку - перешли к проблемному коду и т.д.). Да еще голосовое управление. Для командной работы сложно. А дома размяться самое то было бы: "Сейчас я станцую класс для ведения логов".
  • сервис для общения людей пожилого возраста. Что-то типа гибрида видеочата и социальной сети с учетом ограниченных возможностей и плохого знакомства с компьютерными интерфейсами. Большой шрифт, голосовое взаимодействие с программой, облегченный поиск желающих пообщаться.
  • Думаю, кто-нибудь подобное уже делает.

    А над чем было бы интересно вам поработать?

    How Linux Works: What Every Superuser Should Know

    Просмотров: 1397Комментарии: 0
    Обзоры

    Прочел книгу "How Linux Works: What Every Superuser Should Know" by Brian Ward.

    О чем книга?

    Книга стремится дать общее представление об устройстве Linux-подобных ОС. Начинает с основ и постепенно раскрывает общую картину: командная строка, основные команды, устройства, диски, файловая система, загрузка ядра, user space, конфигурация, логирование, крон, процессы, сеть, десктоп, инструменты разработчика и т.д. В книге чуть более 300 страниц, изложить все одинаково подробно нереально. Поэтому автор более подробно раскрывает базовые вещи (принципы устройства, команды и их вывод и т.д.) и очень кратко касается специальных тем: десктопа, разработки, приложений и сервисов. Каких-то секретов и тонкостей устройства, настройки и т.п. в книге не нашел.

    Что понравилось?

    Практическая ориентированность. Акцент делается на решаемых задачах, более того, автор предлагает все примеры прорабатывать в командной строке - к сожалению, у меня времени на это не было. Теоретические сведения тоже есть, но по минимуму, иногда хочется побольше.

    Радует понятное изложение. К примеру, рассказ о базовом конфигурировании фаервола не вызвал вопросов, в отличие от прочитанных ранее how-to.

    Что не понравилось?

    Отсутствие некоторых интересных тем, например, IPv6. А некоторые темы показались лишними smile

    Для чего может быть полезна?

    При моем уровне работы с Linux (десктоп + изредка местами сервер) книга полезна как общее введение в тему, которое нелишне прочитать для ознакомления. Думаю, ее уровень отвечает знаниям идеального "администратора начального уровня".

    Оценка

    4/5 (нужная книга)

    Делаю ToDoLog - часть 3. Response

    Просмотров: 5124Комментарии: 8
    Технологии

    С концепцией запроса в целом разобрался, что делать с результатами работы Интерактора? В каком формате возвращать результат, как учесть ошибки и валидацию данных? Думаю, что Интерактор должен возвращать объект Ответа. Мотивация аналогична объекту Запроса: четкая структура ответа и типизация, более абстрактный Интерактор не должен заботиться о конкретном формате возвращаемых данных, требуемом клиентской стороной. С другой стороны, клиент будет знать структуру возвращаемых данных и сможет с ними работать.

    Следующий вопрос: как возвращать объект Ответа? Вижу два основных варианта. В первом объект создается внутри интерактора и после заполнения данными отправляется наружу. Во втором в интерактор передается пустой (установленный по умолчанию) объект ответа, который внутри заполняется данными. Какой вариант предпочтительнее? Это зависит от того, что нужно делать в контроллере с этим объектом. Если понадобится расширять и дополнять его, то предпочтителен второй вариант. Такая возможность полезна, ведь одни и те же данные часто нужно возвращать на клиент в разном виде. Поэтому для контроллеров может понадобиться дополнительная функциональность, облагораживающая данные для показа в конкретном шаблоне.

    Сначала я написал реализацию с созданием объекта ответа внутри интерактора (коммит). Базовый класс Response содержит поля для статуса ответа и ошибок, если таковые возникнут. Плюс геттеры и сеттеры для статуса. Это общая функциональность, которая нужна всем классам-наследникам. В последних задаются конкретные поля для возвращаемых данных.

    По некотором размышлении подумалось, что правильнее использовать второй вариант - создание чистого объекта ответа на клиенте (в контроллере) и передача его для заполнения в интерактор. Основную роль в этом убеждении сыграли вышеприведенные соображения плюс соображения о предпочтении интерфейсов реализациям. Так и переделал.

    И еще. В интеракторе создания задачи разделил само по себе создание объекта-задачи и добавление его в репозиторий (коммит). По-хорошему, создание объекта и сохранение его не связаны между собой по смыслу. Не всегда созданный объект нужно сохранять, можно, например, вернуть его клиенту в ответ на запрос. Поэтому добавление созданного объекта будет производиться при помощи метода Repo\TaskInterface::add(Entity\Task $task) . За создание объекта отвечает метод Repo\TaskInterface::create(...) (коммит). Он позволяет избежать явного создания Сущности там, где она нужна.

    Итак, использование отдельного объекта Ответа унифицирует формат возвращаемых в контроллер данных и отвязывает эти данные от типа ответа клиенту.

    Делаю ToDoLog - часть 2. Request

    Просмотров: 1894Комментарии: 0
    Технологии

    Один из недостатков кода - механизм обработки данных внешних запросов. Сейчас данные новой задачи передаются в Интерактор обычным массивом, внутри дополняются, модифицируются, потом из них строится Сущность. Проверяется наличие нужных полей, заполняются значения по-умолчанию, и вот они уже образовали новый объект-задачу. Главной проблемой такого подхода является априорное знание Сущности и Интерактора о поступивших данных - что это массив, какие поля он содержит. По сути, в этом нет ничего плохого, должен же Интерактор знать, что ему нужно для работы? Проблема в том, что нужно знать о формате входных данных. Представьте, что они приходят не из массива $_POST , а от запроса через API, или из командной строки. А если поле из $_POST - массив, а шлюз к API возвращает объект? Нужно либо предусмотреть в Интеракторе или Сущности обработку по-разному организованных входных данных, либо заранее привести входные данные к известному формату. Первое нарушает правило Clean Architecture - более абстрактные слои не должны зависеть от менее абстрактных. Второе приемлемо: можно привести "сырой" запрос к стандартному виду, откуда бы он не поступил, а уже "причесанный" отправить для обработки в Интерактор. В качестве такого "причесанного" можно задействовать массив с известными полями, но более адекватным, на мой взгляд, будет использование объекта с уникальными свойствами для каждого типа запроса (коммит). Для объектов в PHP легче задавать структуру, можно требовать передачи в функцию параметра определенного класса, что автоматически определяет его сигнатуру. Возможность добавлять и переопределять методы-обработчики тоже не будет лишней.

    При таком подходе передача в конструктор сущности Task массива параметров становится бессмысленной. Нужно передавать отдельные поля. Вопрос только в том, все ли поля передавать сразу в конструктор. Нормально ли, если объект появится без поля userId, например? И когда считать объект корректным и валидировать его корректность? Пока буду передавать в конструктор все, что нужно, и формировать корректный объект (коммит).

    И, конечно, нужно аналогично переделать создание сущности User. Интеракторов для нее пока нет, так что в сценарии передаем параметры вручную (коммит).

    Резюме: теперь интерактор не знает о том, откуда получен запрос и какая его внутренняя структура. Получает нужные данные в стандартном виде.

    Делаю ToDoLog - часть 1

    Просмотров: 1870Комментарии: 4
    Технологии

    В прошлый раз я озадачился двумя вопросами о Clean Architecture: как работать со структурами данных типа дерева и какими все же должны быть Сущности. Подумав и почитав ветки, пришел к следующему.

    Структура данных Сущности должна отображаться либо в ней самой, либо в специально созданной другой сущности. Но при этом служебным данным в них не место. Например, если нужно иметь дерево задач, я могу эмулировать его свойством children, куда помещать задачи-непосредственные потомки. Или же создать отдельную сущность TaskTree, которая будет содержать иерархию Task. Думаю, на теперешнем этапе более приемлем первый вариант.

    public $children = [];

    Разумеется, должны добавиться методы, обрабатывающие эту иерархию, в нашем случае addChild() , removeChild() и другие. Чтобы не грузить каждый раз всю иерархию, можно добавить поле $hasChildren , которое будет показывать, есть ли у задачи потомки.

    Далее. Как я понял из комментариев, Сущность в первую очередь должна определять бизнес-правила обработки себя. Заполнение, выборка, валидация — все, что работает на высшем, самом абстрактном уровне иерархии приложения. При этом непосредственного доступа к данным она может и не иметь. То есть, Сущность может и должна быть абстрактным классом, от которой наследуются конкретные реализации с ORM, например. Такое усложнение и вызвано, по-видимому, наличием слоя ORM, который сам работает с БД, но при этом должен реализовать требуемые бизнес-методы сущности. Это говорит о том, что у меня все неправильно. Впрочем, ломать сейчас не буду. Есть частные мнения, что сущности все же могут быть конкретными классами с нормальными полями данных, формироваться из данных БД они могут в Репозиториях. Кроме того, хочу, чтобы изменения в коде были естественными, а пока не вижу необходимости менять реализацию класса.

    На сегодняшний день реализован сценарий создания задачи.

    $taskCreator = new Interactor\Task\Creation($this->taskRepo, $this->userRepo, $this->sessionService);
    $this->boolResult = $taskCreator->execute($data);

    При создании в него инжектируются репозитории задачи и пользователя, а также сервис для работы с сессией. Для выполнения он получает на вход данные новой задачи, которые дополняет ID создателя и вызывает метод создания задачи в репозитории.

    $data['userId'] = $this->session->getLoggedInUserId();
    $this->taskRepo->create($data);

    В чем достоинство такого кода? Создание задачи отделено от обслуживающего вызов кода (в данном случае, теста). Бизнес-логика реализуется внутри Интерактора, только он знает, какие поля выбрать, куда записать и как сохранить. Но при этом абстрагируется от конкретного способа сохранения — сейчас за это отвечает mock-репозиторий , работающий с оперативной памятью.

    Недостатков у кода много, о них пока не буду. Интересно посмотреть, как такой код может взаимодействовать с запросами извне.

    Начал работу над пробным проектом Clean Architecture

    Просмотров: 2212Комментарии: 0
    Технологии

    Начал писать код приложения (простой ToDo-менеджер-журнал). Пока что все просто, не знаю, стоит ли что-то пояснять. Описал первые сценарии, вырисовалась структура для Сущностей/Интеракторов/Границ. Предполагается, что на первых порах сценарии будут работать с фиктивными (mock) источниками данных и сервисами. Работу с сессией реализовал в виде сервиса, а не репозитория, поскольку хранение данных текущего пользователя возможно не только в сессии, но и, например, с использованием токенов. Идея сервиса для обработки таких вещей кажется более уместной.

    Столкнулся и с первой архитектурной проблемой. Набор задач логично организовать в виде дерева, с иерархией подзадач. Но как отобразить ее в нашей Сущности задачи? С одной стороны, чего проще — ввести дополнительные поля для работы с Nested Sets или Adjacency List. Но эти поля будут отображением реляционной таблицы в нашу Сущность. А Сущность не должна знать о внутреннем устройстве системы хранения данных! Стал копать гуглогруппу о Clean Architecture - и запутался еще больше. Оказывается, Сущность не должна быть отображением нашего объекта данных.

    Misconception #1: Entities are data.
    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.

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

    Misconception #2: Entities, Database, and Web use the same data
    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.
    ...
    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.

    На этом я пока остановился. Нужно собраться с мыслями и понять, как же должны работать Сущности здорового программиста.

    Валидация в Clean Architecture

    Просмотров: 5080Комментарии: 0
    Технологии

    Валидация приходящих в приложение данных это то, на чем часто заканчивается вся красота и строгость архитектуры и начинается мешанина представления и бизнес-логики. Правила валидации зачастую содержат информацию о структуре Сущностей (в терминах Clean Architecture из прошлого поста), например, что поле e-mail обязательно. Нередко они говорят о каких-то частных особенностях данных, например, для обычных юзеров можно создать не более десяти счетов, а для премиумных ограничения нет. Наконец, какие-то особенности представления: формат номера телефона, кредитной карты и т.д. Добавить к этому выдачу клиенту сообщения об ошибке - вот и нанесен удар нашему чувству прекрасного. Фреймворки по-разному решают проблему организации валидации, мне стало интересно, что с этим делать в рамках Clean Architecture с ее жесткой изоляцией слоев. Довольно быстро нагуглилась ветка из Гуглогрупп (группы, посвященные обсуждению методики, здесь), где в обсуждении принял участие Uncle Bob.

    Из обсуждения я извлек несколько тезисов:

  • Сущности (Entities) могут включать функциональность валидации, но только в том случае, если правила валидации максимально общие и не зависят от приложения. Например, требование поля электронной почты для подписки у сервиса почтовой рассылки.
  • Специфичная для приложения валидация должна осуществляться в интеракторах (Interactors) как более изменчивых объектах. Общий принцип: объекты, изменяющиеся по подобным причинам, должны быть сгруппированы вместе. И наоборот, изменяющиеся по разным причинам должны быть разделены.
  • При нарушении правил валидации интерактор выбрасывает исключение, задача отображения сообщений клиенту ложится на логику отображения.

  • Это полезно, но общо и теоретично, придется писать код, чтоб проверить на практике. Кстати, инициатор обсужения для практики по Clean Architecture пишет браузерную игру. Любопытно посмотреть код.

    Clean Architecture на PHP

    Просмотров: 2499Комментарии: 0
    Технологии

    Посмотрел видео Robert C. Martin об подходе к построению веб-приложений, обеспечивающем такие преимущества хорошей архитектуры, как

    1. возможность отложить принятие важных архитектурных решений
    2. возможность минимизировать количество принимаемых на каждом этапе архитектурных решений

    В печатном виде изложение можно почитать на 8thlight.com. Если кратко, суть подхода в максимальной изоляции бизнес-логики приложения от фреймворка/сервисов/среды выполнения. Сердцевиной приложения являются Сущности (Entities), которые содержат самую общую и высокоуровневую бизнес-логику системы. Уровнем ниже лежат Сценарии (Use Cases), или Взаимодействия (Interactors), связывающие данные Сущностей для реализации бизнес-логики приложения. Ни этот, ни более высокий уровень не должны зависеть от тленных земных вещей типа пользовательского интерфейса, библиотек фреймворка или сервиса базы данных. Интерфейсные адаптеры (Interface Adapters), или Границы (Boundaries), обеспечивают взаимодействие между бизнес-логикой и окружением. Тут работают шлюзы, сервисы БД и внешних API и прочая. Именно с этим слоем взаимодействует фреймворк, если его использовать в разработке. Границы преобразуют потоки данных из внешнего мира в пригодные для обработки высокоуровневым ядром, и наоборот, возвращают от ядра ответ в браузер, UI или куда еще. Основное правило при всем этом - более высокий уровень абстракции не должен зависеть от более низкого уровня.

    Изоляция бизнес-логики приложения кроме возможности гибкой работы с окружением позволяет плотно и на самых ранних этапах разработки использовать тестирование. В идеале, можно написать и покрыть тестами систему, ничего еще не зная о фреймворке, базе данных и даже о том, будет ли приложение работать в вебе или на десктопе с планшетом.

    В теории все это заманчиво и воодушевляет, но насколько реально сделать такую штуку в коде? Не разобьется ли эта неземная красота, эти почти Платоновы идеи-сущности, о грубость техзадания? Интересно было бы посмотреть варианты реализации чего-нибудь как на Ruby, например, так и на кондовом PHP. Лучшее из того, что я видел по теме, это цикл статей Jeremy Bush aka zombor (между прочим, именно из этого цикла и узнал о сабже). К сожалению, рассказ прервался на самом интересном и до рабочего кода не дошел. На Гитхабе тоже негусто. Не знаю, будет ли время, но интересно было бы написать приложение в подобном стиле.

    Что вы думаете о Clean Architecture в реальной разработке? Может быть, даже случалось делать красивую архитектуру?