Ad-social Bot

Smmok Bot

Vkserfing Bot

Vkstorm Bot

Vktarget Bot

Привет, меня зовут Pavel Germanika

Спасибо, что зашли на мой сайт! Хочу рассказать немного о себе и о том, что вы cможете найти для себя полезного на страницах моего блога.


 

Может ли человек, проживая в унылом бесперспективном городе, чего-то добиться, имея под рукой лишь старый ноутбук и интернет? Можно ли без всяких офисов, начальных капиталов построить компанию, приносящую неплохую прибыль? Ответ на этот вопрос вы сможете узнать в моем блоге. Я Pavel Germanika, добро пожаловать!

Всю свою жизнь я прожил в мечтах. Это было какое-то полугипнотическое состояние. Я любил гулять по улицам или лежать на диване, представляя себя успешным человеком. Будь то бизнесменом, известным футболистом, ученым, которому вручают нобелевскую премию и прочими персонажами. Любые дела я всегда откладывал на потом. Все жизненные перспективы я старался не замечать. Думаю, многие люди со мной схожи.

И так проходила вся моя жизнь, пока, однажды, одним субботним утром не произошло чудо. Я до сих пор не могу ответить на вопрос, что же со мной произошло?. Почему меня переклинило? Но я вдруг перевел свою жизнь из пассивного состояния в активное. Я взял себя в руки и стал реализовывать все идеи, которые приходили в мою голову. И это коренным образом перевернуло все мое существование.

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

Мой Блог — это реалити-шоу обычного заурядного парня, который пытается добиться успеха с полного нуля. Никакого начального капитала, никаких знакомств, никаких особых способностей. Только идеи, анализ и компьютер. Я хочу быть максимально открытым и делиться с вами всеми своими мыслями и результатами работы.

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

Любой из вас может связаться со мной. Я рад каждому! Пишите на мой Telegram.

Концепция MAST в Биткоине

В рамках данной статьи мы поговорим о концепции MAST и ее применении в протоколе Биткоин. Мы рассмотрим свойства, которых позволяет добиться MAST, а также пользу от его применения. Статья будет интересна читателям, которые увлекаются протоколом Биткоина и другими инновационными платежными системами. Этой теме также посвящена отдельная лекция в рамках онлайн-курса по Blockchain “MAST в Биткоине”.

Концепция MAST подразумевает использование деревьев Меркла и абстрактных синтаксических деревьев, чтобы задавать условия траты монет на выходах транзакций. Рассмотрим по порядку, как это устроено.

Merkle Tree

Так можно схематично изобразить Merkle Tree.

image

Есть кусочки данных, для которых нужно получить контрольную сумму, т. е. вычислить хеш-значение от всех кусочков. Но вместо того, чтобы все их конкатенировать и подать на вход хеш-функции одним значением, Merkle Tree предлагает другой подход. Каждый кусочек данных хешируется по отдельности. Потом получившиеся хеш-значения попарно конкатенируются и снова хешируются. И так до тех пор, пока не получится одно хеш-значение, которое покрывает все порции данных. Это значение называется Merkle Root.

Merkle Tree позволяет проверить вхождение отдельного кусочка данных в Merkle Root, не имея при этом всех остальных кусочков данных. Это ценное свойство.

Допустим, пользователь имеет Merkle Root и данные одной транзакции (на схеме выше она обозначена красным цветом). Тогда пользователь может взять цепочку недостающих хеш-значений (на схеме они обозначены синим цветом) для того чтобы проверить что данная транзакция входит в Merkle Root. Недостающие хеш-значения называются Merkle Branch. Для конкретной транзакции их можно запросить у того узла сети, который хранит полный блок.

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

Abstract Syntax Tree

Теперь давайте познакомимся с абстрактными синтаксическими деревьями (Abstract Syntax Tree). На схеме ниже изображено синтаксическое дерево, которое описывает очень простой цикл. Здесь синим цветом обозначены узлы дерева, которые означают операции, зеленым обозначены переменные, а красным — константы. Ребра дерева обозначают переходы между операциями.

image

Таким образом, описан цикл, который выполняется в определенной последовательности. Сначала проверяется равенство переменной А и константы 32. Если оно не выполняется, то переходим к телу цикла, где выполняется присвоение переменной А суммы двух значений: самой переменной А и константы 2. Так устроено абстрактное синтаксическое дерево в общих чертах.

Что же такое MAST?

Теоретическую почву мы подготовили, теперь определим, что такое MAST и какова его польза. MAST — это Merkelized Abstract Syntax Tree, где применяются идеи дерева Меркла и абстрактного синтаксического дерева для задания взаимоисключающих условий траты монет. При этом в качестве языка описания условий выступает, как обычно, Bitcoin Script. Концепция MAST позволяет повысить конфиденциальность и уменьшить размер транзакций.

Развитие концепции и текущее положение

Развивать и продвигать идею MAST в сообществе Биткоина начали такие люди, как Russell O’Connor, Pieter Wuille, Peter Todd и Johnson Lau. В начале 2016-го года было опубликовано предложение по улучшению протокола Биткоин под номером 114 (BIP114), где была описана спецификация одного из вариантов реализации данного подхода с использованием witness programs, которые в свою очередь были введены с обновлением SegWit. BIP114 также предлагает программную реализацию, которая добавляет новые правила достижения консенсуса в протокол Биткоина.

Позже, в 2017-ом году, предложили альтернативный вариант реализации концепции MAST, который описан в BIP117. Он основан на BIP114 и вносит некоторые модификации. На момент 2018-го года оба предложения остаются на стадии рассмотрения.

Отметим, что MAST может быть интегрирован в Биткоин с помощью softfork обновления протокола. И это, пожалуй, самая важная особенность данной концепции.

MAST на схеме

Схематично Merkelized Abstract Syntax Tree будет выглядеть так.

image

Здесь MAST Root — это корневое хеш-значение, которое будет помещаться в выход транзакции. Синим цветом обозначены хеш-значения веток дерева, которые ведут к условиям траты монет. Таким образом, эти ветки содержат взаимоисключающие условия, по которым монеты могут быть потрачены. Следовательно, тот, кто тратит монеты, будет использовать либо одну ветку, либо другую.

Желтым цветом обозначены условия, которые задаются с помощью Bitcoin Script. Причем те условия, по которым монеты будут потрачены вероятнее всего, рекомендуется помещать как можно ближе к корню дерева — это сделает доказательство владения монетами меньшим по размеру.

Проблемы с транзакциями в Биткоине

Давайте обозначим проблемы, которые возникают при обычном задании условий траты монет с помощью Bitcoin Script. Первая, и самая важная из них, состоит в том, что получателю нужно описать или передать условия, на которых он хочет получить платеж, чтобы отправитель указал их в выходе своей транзакции. MAST и P2SH решают эту проблему.

Вторая проблема: сложные условия занимают большой объем памяти в выходе транзакции. Как результат, отправитель должен оплачивать комиссию за установление таких сложных условий получения монет, хотя их диктует получатель. P2SH и MAST также справляются с этим, перекладывая необходимость включения больших объемов данных в транзакцию, которая будет тратить, а соответственно повышенную комиссию будет платить уже получатель, а не отправитель.

Третья проблема состоит в том, что ScriptPubKey, который помещается в выходе транзакции, ограничен по размеру и количеству операций, т. е. OP_CODEs. Концепция MAST позволяет практически полностью уйти от этих ограничений без ущерба для надежности за счет взаимоисключающих условий.

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

Свойства, которые дает использование MAST в Биткоине

Одно из них — повышение уровня конфиденциальности пользователей за счет скрытия условий траты, которые в итоге не использовались. Данное свойство достигается путем доказательства того, что только определенные условия входят в MAST Root и удовлетворения этим условиям.

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

Кроме того, появляется возможность фиксировать в блокчейне данные произвольного объема без увеличения размера транзакции.

image

На этой схеме приведен вариант структуры MAST в соответствии с BIP114. Синим цветом обозначены хеш-значения, желтым — Bitcoin Script, а красным — произвольные данные в качестве дополнительного сообщения. В верхней части дерева включено значение версии.

Упрощенная схема MAST

image

Здесь задано два взаимоисключающих условия траты монет. В первом случае монеты можно потратить, предоставив одну подпись и дождавшись наступления определенного времени, а во втором — нужно предоставить несколько подписей. Пользователи могут прибегнуть к одному из вариантов, при этом условия второго не будут разглашены.

Применение MAST на практике

В первом случае MAST можно применить для более оптимизированной реализации HTLC (Hashed Time-Lock Contracts), которые применяются в протоколе Lightning Network. В другом — для более оптимизированной реализации Escrow.

MAST дает возможность реализовать очень большие конструкции с использованием multisignature. Это поможет решить такие насущные проблемы, как кража или потеря биткоинов, а в некоторых случаях позволит даже отказаться от cold storage.

Благодаря MAST во многих случаях можно отказаться от операции OP_RETURN для добавления данных в блокчейн Биткоина. Вместо этого можно включать эти данные в дерево и при необходимости доказывать, что конкретные данные были зафиксированы в блокчейне Биткоина. При этом не понадобится увеличивать размер самого блокчейна.

Оптимизация объема данных

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

image

Синей линией обозначена зависимость объема данных от количества условий без использования MAST. Красной линией обозначена зависимость объема данных от количества условий с использованием MAST. Голубая линия — это лимит размера Bitcoin Script для P2SH. Зеленая линия — это лимит размера Bitcoin Script в структуре witness.

Вывод простой. Концепция MAST позволяет хранить значительно меньший объем данных при той же надежности проверки и намного большей функциональности.

А теперь перейдем к часто задаваемым вопросам по этой теме.

Часто задаваемые вопросы

— Будет ли MAST Root задаваться в структуре witness или где он будет указан?

MAST Root вместе данными, которые его определяют, будет указываться в ScriptPubKey на выходе транзакции. Эти данные будут занимать 25-35 байт и, скорее всего, они будут легко кодироваться в привычный Биткоин адрес. А в структуре witness, где доказывается владение монетами, будет указан Merkle Branch и данные, которые удовлетворяют условиям траты, например электронные подписи.

— Будет ли расширено множество доступных OP_CODEs в языке Bitcoin Script?

На данный момент еще не ясно, потому что предложение на стадии рассмотрения и еще могут быть внесены дополнительные правки и улучшения. Вероятно, будет добавлен такой OP_CODE, как OP_MERKLEBRANCHVERIFY, для гибкости использования MAST. Возможно, предложат еще что-то полезное, но это пока неточно.

— Есть ли вероятность интеграции MAST в ближайшее время?

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

Метки:
Похожие публикации

Source: habr1

[Из песочницы] История рождения онлайн сервиса поиска и букинга авторских путешествий по всему миру: слово от разработчика

С чего все начиналось
Идейные муки
Технологии и как они не однозначны
Как хранить и где?
Не только хранить, но и искать
Это загадочное SEO
CDN наше все
Подытожим

С чего все начиналось

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

Начну с того, что это за сервис, и зачем нужно было его создавать. Долгое время наша команда работала над различными крупными проектами для бизнес клиентов. Это порталы для банков, предприятий, крупных холдингов, а также системы документооборота. Естественно, работа с таким сегментом предполагает удовлетворение узкого круга заинтересованных сотрудников и не всегда заканчивается долгим и успешным использованием.

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

Так вот, после всего этого опыта, решили мы попробовать себя на масмаркете, где фидбек от клиента молниеносный, интерес к продукту ты понимаешь максимально быстро и видишь использование твоего сервиса каждый день.
Как оказалось, на этом наши спокойные дни закончились!

Идейные муки

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

При старте, багаж технологий у нас был не очень jQuery и C# (которые мы использовали в наших предыдущих проектах). Данные инструменты не давали нам возможности быстро и гибко отвечать поставленным вызовам. Благо мы уже рассматривали новые подходы как для клиентской, так и для серверной разработки. Наш выбор пал на Angular 2 и Node.js. Данное решение нам позволило быстро формировать компоненты и модули, которые мы могли видоизменять в кратчайшие сроки (в день мы могли переделывать их по два три раза).

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

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

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

Что же это?

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

Технологии и как они не однозначны

Как хранить и где?

Как я уже писал, после выбора инструментария для создания сервиса, возник вопрос выбора хранилища данных. Конечно, за многие годы мы привыкли к реляционным базам данных и к SQL Server, в частности. Но, необходима была платформа для минимальной конфигурации при старте и минимуме усилий при дальнейшей поддержке, а также возможности масштабирования в процессе развития нашего сервиса и росте посетителей.

Таким образом в процессе поиска было найдено решение, которое покрыло все наши требования, это был Firebase Realtime Database. Данный сервис помог решить нам вопросы хранения данных, хостинга, сервиса аутентификации, стореджа для хранение статических данных. Плюс данный сервис находится под крылышком у Google, что в свою очередь дало нам приятные бонусы, так как предоставляло отдельные библиотеки для работы с Angular 2 и это было удобно и быстро. Но и самое крутое, что мы получили — это RealTime Database из коробки. Первые наши ощущения были просто фантастическими.

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

Не только хранить, но и искать

И вот как только была готова первая бета возник вопрос в фильтрации данных, и мы осознали первые минусы в Firebase. Как оказалось, процесс выборки данных по большому количеству условий, просто не поддерживается. Есть возможность, отбирать данные только с одним условием, либо собирать несколько значений в одно поле и потом по нему выполнять фильтрацию. Данный подход нас не устраивал, и мы опять приступили к поиску решения.
Конечно, отказывается от Firebase мы не стали, так как этот один минус не перекрывал ту массу достоинств, предоставляемых этим сервисом. Благо, у нас был опыт использования Google Big Query, который мы получили в процессе наших изысканий, и мы решили его применить. Первый плюс то, что это Google, второй — родные и любимые SQL запросы ну и дешевизна владения 1TB данных в месяц бесплатно.

Снова все стало ясно и понятно, написали сервис отправки данных и успешно прикрутили его к Cloud Function. Забыл сказать, про бек в Firebase тоже позаботились, вы можете писать собственные триггеры на Nodejs и вешать их на любое событие в базе данных, а так же на http запрос.

Как вы можете заметить процесс поиска решений и подходов для нас стал ежедневной задачей, так как почти каждый день мы сталкивались с новыми вызовами, которые надо было оперативно решать.

Не успели мы расслабится и спокойно продолжать создавать наш сервис, как началось тестирование фокус группой, и мы осознали, что пользователи привыкли очень быстро переключать фильтры и хотят сразу видеть результат их работы. Такие требования заставили нас отказаться от Big Query и искать что-то новое. Так как Big Query нам давал скорость ответа максимум 2 секунды и это при минимальном объёме данных. Тут их конечно не за чем ругать, так как сервис этот предназначен для обработки больших объемов информации, а не для быстрой реакции на кучу последовательных запросов.

В результате мы остановили свой выбор на Elastic Search. Данный продукт позволил нам построить быстрый поисковый движок, наша фильтрация стала отвечать требованиям наших пользователей. Тут много рассказывать не буду, так как данный продукт стал набирать популярность и информации по нему достаточно. Единственное, что хочу отметить, для данного продукта нужна виртуальная машина, которую надо где-то хостить. Данную возможность предоставляет как Google так и Microsoft, так что выбор за вами. Сконфигурировать ее так же просто используя ресурс bitnami. Мы для себя выбрали Azure, данный выбор был не столько из-за технологических особенностей, а больше из-за сторонних факторов).

Это загадочное SEO

И вот сервис обкатывается, платформы осваиваются и все вроде хорошо, стремимся к светлому будущему. Но, тут возникает вопрос продвижения нашего сервиса и ключевой вопрос SEO. Никогда не мог подумать, что этот вопрос может быть настолько не проработанным со стороны создателей Angular. Как оказалось, Single Page Application очень слабо предоставляет эту возможность, а если сказать честно — вообще не предоставляет. Да, вы можете зашить статические данные в мета теги и при обходе краула или при шаринге выдавать одну и ту же информацию, ну это будет как-то неправильно и безрезультативно. Прошерстив просторы интернета, мы наткнулись на такой чудесный сервис, который входит в состав Angular 4, Angular Universal. Почитав описание, мы поняли, что это то что нужно и что зря мы ругали разработчиков framework’а.

Началась эпопея с прикручиванием данного счастья к нашему проекту, замечу, на этот момент было уже написано порядка 10 крупных модулей и использовалось примерно 12 сторонних npm пакетов. Первая конфигурация чистого проекта прошла отлично, благодаря мануалам в интернете, и вроде все завелось. Причем серверную часть мы крутили все на том же Cloud Function от Firebase. Ну а теперь надо ж и боевой код пробовать, и тут появились проблемы. Первое, как оказалось все сторонние npm пакеты должны поддерживать Angular 4, в коде на серверной части нельзя использовать переменные window, document и т.д., ну и отладить это все счастье просто не реально.

Я не буду описывать все наши муки, с этим сервисом, так как это было много и больно. Скажу одно, мы его так и не побороли, не знаю или до конца не поняли или просто он еще сыроват и не готов к продуктивному использованию. В целом решать вам, может у кого и получится, но мы решили на этом остановиться. В результате, был написан сервис, который слушает все http запросы и при запросе index.html возвращает его, но перед этим, подкидывает в него необходимые мета теги. В результате получилось хорошо и уже 3 месяца полет нормальный. Кстати, хостим мы все это тоже на Azure по все тем же сторонним факторам.

CDN наше все

Вот и снова некоторое время стабильности, и относительно спокойной работы. И не кто не думал, что сюрприз нас ждет со стороны Facebook. В один прекрасный день оказалось, что шаринг в FB не работает. Сначала мы думали, что это связанно с ужесточением политик безопасности в FB, потом с блокировкой IP, но так причины мы и не нашли. Обращались в поддержку как FB так и Firebase, но каждый пинал на другого.

Единственное, мы определили, что проблема в урлах к картинкам, которые у нас хранились в сторедже Firebase, а урл, скажу вам сразу, там очень специфический. Решили мы перевести весь статический контент так же на Azure и скажу я вам это решение было правильным, так как скорость загрузки фото возросла, ну и управлять этим всем, можно более гибко и прозрачно.

Подытожим

На данный момент мы уже в продуктиве 3 – тий месяц, постоянно ведем улучшение и расширение функционала. Для управления версиями конечно же используем Git, понемногу автоматизируем сборки и деплой. В день получаем порядка 450 новых уникальных заходов, бывают скачки до 1000 пользователей. И все это работает.

Что бы хотелось просуммировать из всего сказанного:

  1. Не надо пытаться за счет одного сервиса или одной технологии решать все задачи, которые появляются у вас в проектах.
  2. Старайтесь разрабатывать универсальные модули для большей гибкости в будущем.
  3. Выбор поставщика облачных сервисов вопрос сугубо личный, так как в целом все они предоставляют одинаковый набор сервисов. Остается вопрос в цене и ваших предпочтениях.
  4. Разрабатывайте свое решение так, чтобы иметь возможность мигрировать между разными поставщиками сервисов и технологиями или хотя бы продумывайте стратегию возможного переезда.
  5. Ну и не бойтесь экспериментировать.
Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

[Из песочницы] Расширение процесса сборки с помощью MSBuild

В данной статье речь пойдет о том, как расширить процесс сборки проекта с помощью MSBuild.

Меню

Основные понятия (Меню)

MSBuild устроен таким образом, что сборка проекта разбита на несколько этапов.

Target — это некоторый этап (событие), происходящее во время сборки проекта. Можно использовать стандартные таргеты, либо определять собственные.

Task — это некоторая задача, которая может выполняться на определенном этапе. Можно использовать стандартные таски или создавать собственные.

Цитата из документации о таргетах (https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-targets):

Targets group tasks together in a particular order and allow the build process to be factored into smaller units.
For example, one target may delete all files in the output directory to prepare for the build, while another
compiles the inputs for the project and places them in the empty directory.

Жизненный цикл сборки MSBuild (Меню)

Для работы MSBuild Microsoft определил ряд стандартных таргетов (в файлах Microsoft.Common.targets, Microsoft.CSharp.targets и т.д.). Довольно тяжело найти информацию о том, какие таргеты уже определены, но опытным путём было выявлено, что есть следующие (упорядочены, могут быть указаны не все):

Список таргетов (спойлер)

  • BeforeRebuild
  • Clean
  • BeforeBuild
  • BuildOnlySettings
  • PrepareForBuild
  • PreBuildEvent
  • ResolveReferences
  • PrepareResources
  • ResolveKeySource
  • Compile
  • UnmanagedUnregistration
  • GenerateSerializationAssemblies
  • CreateSatelliteAssemblies
  • GenerateManifests
  • GetTargetPath
  • PrepareForRun
  • UnmanagedRegistration
  • IncrementalClean
  • PostBuildEvent
  • AfterBuild
  • AfterRebuild

Таргеты BeforeBuild и AfterBuild специально созданы для переопределения и их можно использовать. Остальные таргеты из списка не рекомендую использовать, чтобы ничего не сломалось.

Подготовка окружения для примеров (Меню)

Для примеров необходимо:

  • Установленная среда разработки Visual Studio
  • Создать проект типа Console Application с именем MSBuildExample
  • Открыть папку проекта и найти там файл MSBuildExample.csproj
  • Открыть файл MSBuildExample.csproj в блокноте или другом редакторе

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

image

Внимание! В файле .csproj регистр букв важен.
Для запуска примера необходимо запускать build в среде разработки Visual Studio. Для некоторых примеров потребуется выбирать solution конфигурацию.

image

Результат будет выводиться в окно Output в Visual Studio (внизу). Если его нет, то откройте его через пункты меню View => Output.

image

Таргеты в MSBuild (Меню)

Для примеров будем использовать таск Message, который будет выводить информацию в окно Output в Visual Studio. Как говорилось ранее есть стандартные таргеты BeforeBuild и AfterBuild, воспользуемся ими. Про подготовку читать в разделе Подготовка окружения для примеров.

Пример использования таргетов (спойлер)

Код примера:

<Target Name="AfterBuild">
  <Message Text="AfterBuild event" Importance="high"></Message>
</Target>
<Target Name="BeforeBuild">
  <Message Text="BeforeBuild event" Importance="high"></Message>
</Target>

Результат выполнения (лишнее исключено):


BeforeBuild event

AfterBuild event

Как видно, был выполнен task Message, который вывел указанный нами текст в момент BeforeBuild и AfterBuild в окно Output в Visual Studio.
При определении таргета с одним и тем же именем он перезаписывается!

Пример перезаписи таргета (спойлер)

Код примера:

<Target Name="BeforeBuild">
  <Message Text="First message" Importance="high"></Message>
</Target>
<Target Name="BeforeBuild">
  <Message Text="Second message" Importance="high"></Message>
</Target>

Результат выполнения (лишнее исключено):


Second message

Вывело только второе сообщение, потому что использовали таргеты с одним именем и он был перезаписан вторым значением.

Создание собственного таргета MSBuild (Меню)

Если таргетов BeforeBuild и AfterBuild недостаточно или нужно, чтобы таски выполнялись на другом этапе жизненного цикла сборки, то можно определить собственный таргет. Для этих целей есть параметры BeforeTargets и AfterTargets.

Пример определения собственных таргетов (спойлер)

Код примера:

 <Target Name="BeforeBuild">
    <Message Text="BeforeBuild event" Importance="high"></Message>
  </Target>
  <Target Name="MyCustomBeforeTarget" BeforeTargets="BeforeBuild">
    <Message Text="MyCustomBeforeTarget event" Importance="high"></Message>
  </Target>
  <Target Name="MyCustomAfterTarget" AfterTargets="BeforeBuild">
    <Message Text="MyCustomAfterTarget event" Importance="high"></Message>
  </Target>

Результат выполнения (лишнее исключено):


MyCustomBeforeTarget event
BeforeBuild event
MyCustomAfterTarget event

Было определено два собственных таргета — MyCustomBeforeTarget и MyCustomAfterTarget.
Таргет MyCustomBeforeTarget выполняется до таргета BeforeBuild, потому что мы указали:

BeforeTargets="BeforeBuild"

Таргет MyCustomAfterTarget выполняется после таргета BeforeBuild, потому что мы указали:

AfterTargets="BeforeBuild"

Таски в MSBuild (Меню)

В данной статье не рассматривается как можно писать собственные таски, но прежде чем писать таск, ознакомьтесь со списком тасков, предоставляемых Microsoft.

Рассмотрим несколько примеров использования тасков и макросов.

Параметр Condition (спойлер)

Параметр Condition присутствует у всех тасков. Цитата из документации docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-task-reference:

A Boolean expression that the MSBuild engine uses to determine whether this task will be executed.

Код примера:

<Target Name="BeforeBuild">
    <Message Text="Current configuration is Debug" Condition="'$(Configuration)' == 'Debug'" Importance="high"></Message>
    <Message Text="Current configuration is Release" Condition="'$(Configuration)' == 'Release'" Importance="high"></Message>
</Target>

Если будет выбрана solution конфигурация Debug, то результат будет выглядеть так (лишнее исключено):


Current configuration is Debug

Если будет выбрана solution конфигурация Release, то результат будет выглядеть так (лишнее исключено):


Current configuration is Release

Информацию о макросе $(Configuration) и других макросах можете найти в разделе переменные и макросы в .csproj.

Информацию о синтаксисе условий можно прочитать там https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-conditions

Определение переменной в csproj (спойлер)

В примере выше у нас есть текст, который можно унифицировать. Чтобы исключить дублирование вынесем в отдельную переменную текст сообщения.

Код примера:

<PropertyGroup>
    <MessageText>Current configuration is $(Configuration)</MessageText>
  </PropertyGroup>
  <Target Name="BeforeBuild">
    <Message Text="$(MessageText)" Condition="'$(Configuration)' == 'Debug'" Importance="high"></Message>
    <Message Text="$(MessageText)" Condition="'$(Configuration)' == 'Release'" Importance="high"></Message>
  </Target>

Для определения собственной переменной используется элемент PropertyGroup.

Проверка существования файла, выдача ошибки (спойлер)

В данном примере сделаем таск, который проверяет создан ли файл App.Debug.config. Если он не создан, то выдаем ошибку. В случае ошибки билд будет остановлен и ошибка будет отображена как ошибки компиляции в окне Error List.
Используем для этого таск Error и уже знакомый нам параметр Condition.

Код примера:

<Target Name="BeforeBuild">
  <Error Condition="!Exists('App.Debug.config')" Text="File App.Debug.config not found"></Error>
</Target>

Результат:
image

В условии Exists используется относительный путь от папки, в которой находится файл .csproj. Для обращения к папке выше текущей использовать ‘../’. Если нужно обратиться к вложенной папке, то использовать формат ‘[DirectoryName]/App.Debug.config’.

Копирование файлов (спойлер)

В данном примере будем использовать таск Copy. С помощью таска скопируем файл App.config в папку bin/[Configuration]/Config в два файла App.config и App.test.config.

Код примера:

<Target Name="BeforeBuild">
    <Copy SourceFiles="App.config;App.config" DestinationFiles="$(OutputPath)/Test/App.config;$(OutputPath)/Test/App.test.config"></Copy>
</Target>

Свойство SourceFiles — массив файлов, которые необходимо скачать. Указывать без кавычек, через точку с запятой.

Свойство DestinationFiles — массив файлов куда будут копироваться файлы. Указывать без кавычек, через точку с запятой.

Подробнее о макросе $(OutputPath) читать в разделе переменные и макросы в .csproj.

Переменные и макросы в .csproj (Меню)

В файле .csproj можно использовать ряд стандартных макросов, их список можно найти здесь https://msdn.microsoft.com/en-us/library/c02as0cs.aspx и здесь https://msdn.microsoft.com/en-us/library/bb629394.aspx. Рассмотрим некоторые полезные макросы:

  • $(MSBuildToolsPath) — указывает на путь к папке MSBuild. Например, C:Program Files (x86)MSBuild.0Bin. Данный макрос при комбинировании пути использовать со слешем. Например, $(MSBuildToolsPath)Microsoft.Web.Publishing.Tasks.dll. Иначе он может некорректно формировать путь и выдавать ошибку, что файл не найден.
  • $(OutputPath) — относительный путь к выходной папке. Например, binStage. Данный макрос использовать со слешем, например, $(OutputPath)$(TargetFileName).config.
  • $(TargetFileName) — имя выходного файла вместе с расширением. Например, MSBuildExample.exe. Расширение и формат имени выходного файла может отличаться от различных типов проектов. С помощью этого макроса можно безопасно определить какое будет имя у файла конфига. Может быть полезно для трасформаций конфигов.
  • $(Configuration) — имя текущей конфигурации. Например, Release, Debug
  • $(IntermediateOutputPath) — путь к папке obj. Например, objStage.

Для определения собственных параметров использовать PropertyGroup . Пример определения собственной переменной можно найти в разделе таски в MSBuild.

Ссылки (Меню)

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

Обзор Microsoft Arc Mouse

Это уже четвертая реинкарнация мыши Microsoft Arc, которая в этом году отмечает свое десятилетие. Она стала еще более стильной, а вся кнопочная поверхность превратилась в одну большую область прокрутки, как вертикальной, так и горизонтальной.

Эпоха сенсорных дисплеев и развлекательного контента существенно изменила наше представление об эргономике компьютеров и их роли в повседневной жизни. Всё больше людей просматривают сайты и общаются в сети со смартфонов и планшетов, называя пережитком прошлого привычные клавиатуры и мыши. Но стоит зайти в любой офис и звуки этого «пережитка прошлого» услышишь со всех сторон. Клавиатуры стучат, мышки щелкают, и никто не согласится провести рабочий день без них. А заменить старую проводную мышь из хлипкого пластика на нещелкающую, инновационную и стильную — всегда пожалуйста. Поговорим как раз о такой: Arc Mouse образца 2017 года, которая которая наконец-то добралась до прилавков в России.

В чем фишка?

Это самая тонкая и компактная беспроводная мышь, которая работает от двух AAA-батареек и не требует никаких дополнений в виде донглов или специального ПО. С компьютером связывается по Bluetooth, а среди фишек — большой тачпад для вертикальной и горизонтальной прокрутки и оригинальный метод включения/выключения. Производитель адресует гаджет тем, кто часто работает вдали от офиса и пользуется несколькими компьютерами.

Комплект поставки

Мышь поставляется в миниатюрной коробке из плотного картона. В ней — сам девайс и парочка буклетов. Батарейки уже внутри устройства, так что можно сразу приступить к знакомству.

Дизайн и внешний вид

При взгляде на Microsoft Arc Mouse в голову сразу приходит пульт управления цифровой техникой будущего. Ничего лишнего: черный прямоугольник с закругленными краями, пара индикаторов и отсек для батарей. Толщина мышки колеблется от семи миллиметров в самом узком месте до 14 — в районе клавиш.

Область клавиш практически квадратная, на клик отвечает достаточно звонким щелчком. Нажимать можно в любой ее части, но лучше — ближе к краям. Посередине ближе к нижнему краю области клавиш расположен светодиодный индикатор питания.

С внутренней стороны на краях устройства находятся пластиковые упоры — для контакта с поверхностью. На тыльной стороне над отсеком для батарей расположен
глазок фирменного лазера Bluetrack и кнопка перевода мышки в режим сопряжения.


Для питания устройства используются два элемента формата AAA. По заверению производителя, их хватит на шесть месяцев активной эксплуатации, и в это легко поверить. Хотя бы по той причине, что большинство современных мышек работают, порой, значительно дольше.

Эргономика

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

Впрочем, проблема симметричных мышей не обошла стороной и Microsoft Arc Mouse. Спустя полчаса активного использования запястье начинает слегка побаливать, требуя минутного перерыва. С другой стороны, мышь одинаково подойдет и для использования левой рукой.

Настройка и фирменный софт

Для проверки работоспособности устройства мы взяли ноутбук под управлением Windows 8.1. Для настройки мыши нажмите и удерживайте кнопку Bluetooth до того, как замигает лазерный датчик — после чего выберите на ноутбуке Arc Mouse в списке доступного оборудования Bluetooth. Все, можно начинать работу. Просто согните мышь, чтобы включить, или разогните, чтобы выключить.

Для переназначения клавиш под левую руку и добавления Hotkey-комбинаций на касание тремя пальцами одновременно нужно установить «Центр Управления мышью и клавиатурой Microsoft», где также можно настроить чувствительность прокрутки. Поддерживается вертикальный и горизонтальный тип прокрутки.

Тесты

У пользователей проводных «грызунов» есть некий скепсис в отношении точности и разрешающей способности сенсоров беспроводных моделей. Во многом это вызвано ультрабюджетными низкокачественными аксессуарами, у которых и вправду бывают проблемы с точностью позиционирования. Но Microsoft Arc Mouse эти огрехи не знакомы: и курсор мягко реагирует на малейшие отклонения, точно следуя за движениями мыши по поверхности. По коврам и ткани мышка двигается замечательно, позволяя даже играть в шутеры.

Мы сделали ряд замеров в утилите Mouse Test, анализирующей поведение мыши в стрессовых ситуациях. Если интересно, можете попробовать прогнать свою мышь по этим тестам, а затем сравнить результаты с приведенными на скриншоте ниже.

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

Для чистоты эксперимента обработка иллюстраций в этом обзоре также велась с помощью Microsoft Arc Mouse. После длительной потоковой обтравки фотографий эргономику этой мыши можно оценить на троечку, ведь каждые 10-12 минут приходилось делать перерыв, чтобы расслабить кисть. Если же бродить по сайтам и собирать информацию, выделяя куски текста и перемещаясь между окнами и страницами, рука начнет затекать лишь через полчаса. В целом результат весьма неплохой и вполне коррелирует с похожими по стилю манипуляторами.

Итоги

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

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

Метки:
Похожие публикации

Source: habr1

[Перевод] Ричард Хэмминг: Глава 11. Теория кодирования — II

  • Перевод

«Цель этого курса — подготовить вас к вашему техническому будущему.»

imageПривет, Хабр. Помните офигенную статью «Вы и ваша работа» (+219, 2442 в закладки, 393k прочтений)?

Так вот у Хэмминга (да, да, самоконтролирующиеся и самокорректирующиеся коды Хэмминга) есть целая книга, написанная по мотивам его лекций. Мы ее переводим, ведь мужик дело говорит.

Это книга не просто про ИТ, это книга про стиль мышления невероятно крутых людей. «Это не просто заряд положительного мышления; в ней описаны условия, которые увеличивают шансы сделать великую работу.»

Мы уже перевели 25 (из 30) глав. И ведем работу над изданием «в бумаге».

11. Теория кодирования — II

(За перевод спасибо erosinka, которая откликнулась на мой призыв в «предыдущей главе».) Кто хочет помочь с переводом — пишите в личку или на почту magisterludi2016@yandex.ru

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

Таким образом, мы хотим мгновенно однозначно декодируемый код для данного набора входных символов, si, вместе с их вероятностями, pi. Какую длину li мы должны установить (учитывая что мы должны подчиняться неравенству Крафта), чтобы получить минимальную среднюю длину кода? Хаффман решил эту проблему дизайна кода.

Хаффман первым показал, что следующие неравенства должны быть верны для кода минимальной длины. Если pi расположены в убывающем порядке, то li должны быть в возрастающем порядке.

image

Допустим, pi в указанном порядке, но хотя бы одна пара li — нет. Рассмотрим эффект перестановки символов, связанных с теми двумя, которые не в указанном порядке. Перед перестановкой вклад этих двух членов уравнения в среднюю длину кода L

image

и после перестановки

image

Все остальные члены в сумме L остаются те же. Разница может быть записана как

image

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

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

image

Для иллюстрации кода ХАффмана мы используем классический пример. Пусть p(s1) = 0.4, p(s2) = 0.2, p(s3) = 0.2, p(s4) = 0.1 и p(s5) = 0.1. Это изображено на рисунке 11.I Тогда Хаффман утверждал на основании значений выше, что он мог комбинировать (объединить) два наименее частых символа (которые должны иметь одинаковую длину) в один символ с общей вероятностью с общими битами вплоть до последнего бита, который отбрасывается, таким образом получая код на один символ меньше. (?) Повторяя это снова и снова он приходил к системе с двумя символами, для которых он знал, как приписать представление кода, а именно одному символу — 0, а другому — 1.

image

Теперь идя в обратную сторону, нам нужно на каждой стадии разделить символ, который получился из комбинации двух символов, сохраняя те же ведущие биты, но добавляя к одному символу 0, а к другому — 1. Таким методом мы придем к коду минимальной длины L, снова смотрите рисунок 11.I Так как если бы существовал другой код с меньшей длиной L’, то выполняя шаги вперед, которые изменяют среднюю длину кода на заданное число, он бы пришел к двум символам со средней длиной кода меньше, чем 1, что невозможно. Следовательно, код Хаффмана имеет минимальную длину. Смотрите рисунок 11.II с соответствующим декодирующим деревом.

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

Если поместить комбинированные члены как можно выше, мы получим рисунок 11.III с соответствующим декодирующим деревом на рисунке 11.IV. Средняя длина двух кодов одинакова, но коды и декодирующие деревья отличаются; первое — длинное, а второй — “ветвистое”, и второе менее изменчиво чем первое.

Теперь мы приведем второй пример, чтобы вы были уверены в том, как работает кодирование Хаффмана, так как это естественное желание использовать в процессе разработки кодирующей системы код с как можно более короткой средней длиной. Например, у вас может быть очень много данных предназначенных для хранилища бэкапов, и известно, что ее кодирование с подходящим кодом Хаффмана позволит сэкономить более, чем половину ожидаемого объема хранилища. Пусть p(s1) = ⅓, p(s2) = ⅕, p(s3) = ⅙, p(s4) = 1/10, p(s5) = 1/12, p(s6) 1/20, p(s7) = 1/30, p(s8) = 1/30. Сначала мы проверим, что сумма вероятностей равна 1. Общий знаменатель дробей равен 60. Таким образом мы получаем общую вероятность

image

image

image

Второй пример проиллюстрирован на рисунке 11.V, где мы опустили 60 в знаменателе вероятностей, так как лишь относительные величины имеют значение. Какова средняя длина кода на символ? Мы вычисляем

image

Для блока кода в 8 символов каждый символ будет иметь длину 3 и средняя длина будет равняться 3, что больше, чем 2.58

Заметьте, насколько этот механический процесс подходит для машины. Каждый прямой шаг для кодирования Хаффмана это повторение одного и того же процесса: комбинировать 2 наименьшие вероятности, поместить новую сумму в правильное место в массиве и отметить его. В обратном процессе, мы берем отмеченный символ и разделяем его. Эти программы легко написать для компьютера, таким образом компьютерная программа может вычислить код Хаффмана из данных si и их вероятностей pi. Вспомните, на практике вы хотите приписать символу возврата с очень маленькой вероятностью, так чтобы вы могли завершить декодирующий процесс в конце сообщения. В самом деле, вы можете написать программу, которая сможет отобрать данные для хранения и найти оценку вероятностей (маленькие ошибки приводят только к маленьким изменениям L), найти код Хаффмана, провести кодирование и отправить первый декодирующий алгоритм (дерево) и затем закодированные данные, и все это без человеческого вмешательства! В конце декодирования вы уже получили декодирующее дерево. Таким образом единожды написав программу, вы можете использовать ее в случаях, когда вы посчитаете ее полезной.

Коды Хаффмана были использованы даже в некоторых компьютерах в инструкциях, так как они имели очень маленькую вероятность быть использованными. Следовательно, нам нужно посмотреть на улучшение средней длины кода L, которые мы можем ожидать при использовании кодирования Хаффмана, по сравнению с простых блочным кодированием, которое использует одинаковую длину для всех символов.

Если все вероятности одинаковы и имеется точно 2^k символов, тогда исследование кодирование Хаффмана покажет, что вы получите стандартный блочный код с одинаковой длиной. Если имеется не точно 2^k символов, то некоторые из них будут короче, но трудно сказать, будет ли большинство из них короче на 1 бит, или же некоторые будут короче на 2 и более бит. В любом случае, значение L будет таким же, и не намного короче, чем в соответствующем блочном коде.

С другой стороны, если каждая из pi больше ⅔ (сумма всех последующий вероятностей, кроме последней), тогда вы получите код с запятой, в котором 1 символ имеет длину 1 (0), один символ — 2 (10), и так далее до конца, где у вас будет два символа одинаковой длины (q-1): (1111…10) и (1111…11). В этом случае длина L может быть намного короче, чем у соответствующего блочного кода.

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

Когда в процессе ХАффмана появляются две равные вероятности, они могут быть расположены в любом порядке, и таким образом коды могут получиться очень разными, хотя средняя длина кода L в обоих случаях будет одинаковой. Естественно спросить, какой порядок следует выбрать в случае двух равных вероятностей. Разумным критерием является минимизация вариации кода так, что сообщения одинаковой длины в исходных символах имеют примерно одинаковую длину в закодированном виде, вы не хотите, чтобы исходное короткое сообщение было случайно закодировано длинным сообщением. Правило простое: каждую новую вероятность вставлять в таблицу как можно выше. В самом деле, если вы поместите ее выше символа со слегка большей вероятностью, то вы значительно уменьшите вариацию и лишь слегка увеличите L; так что это хорошая стратегия.

Выполнив все шаги мы перейдем к кодированию исходников (хотя мы ни в коем случае не прошли всю тему). Мы обратимся к кодирующему каналу с моделированным шумом. Канал, по предположению, имеет шум, что означает, что некоторые биты были изменены в процессе передачи (или хранения). Что можно сделать?

Обнаружение единственной ошибки довольно просто. К блоку из (n-1) битов нужно прикрепить n-ный бит с таким значением, что все n битов имеют четное количество 1 (или нечетное, если хотите, но мы будем использовать четное число). Это называется проверкой на четность (нечетность).

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

Для математической пригодности мы делаем предположение, что канал имеет белый шум, что означает 1) каждая позиция в блоке из n бит имеет одинаковую вероятность ошибки с любой другой позицией и 2) ошибки в различных позициях некоррелированы, что означает независимы. С этими предположениями, вероятности ошибок равны

image

Из этого следует, что, если, как обычно, p мало относительно длины блока n (что означает, произведение np мало), то множественные ошибки гораздо менее вероятны, чем единственные ошибки. Выбор длины n для данной вероятности p является инженерным решением. Если n мало, то у вас будет бОльшая избыточность (отношение количества отправленных битов к минимально возможному количеству битов n/(n-1)), чем с бОльшим n, но если np велико, то у вас будет малая избыточность, но более высокая вероятность не обнаружить ошибку. Вы должны принять инженерное решение о том, как сбалансировать эти два эффекта.
При обнаружении единственной ошибки можно попросить переслать сообщение заново, ожидая корректного результата во второй раз, или в третий и так далее. Однако, если хранимое сообщение некорректно, то вы будете просить о повторной передаче до тех пор, пока не появится другая ошибка, и возможно, у вас будет две необнаруженные ошибки в схеме обнаружения одиночных ошибок. Таким образом, повторные передачи должны зависеть от ожидаемой природы ошибок.

Такие коды широко использовались даже во времена реле. Телефонная компания использовала в центральных офисах и в ранних релейных машинах код 2-из-5, что означало, что только 2 из 5 реле были в положении “включено”. Такой код использовался для представления десятичной цифры, так как C(5, 2)=10. Если не точно 2 реле были в положении “включено”, это означало ошибку, и был повтор. Так же существовал код 3-из-7, очевидно, код с проверкой нечетности.

Я впервые познакомился с этими кодами 2-из-5 в процессе использования релейного компьютера Модель 5 в Белл Лабс, и я был впечатлен не только их помощью в получении правильного ответа, но, что более важно по моему мнению, они давали техническому персоналу возможность в действительности обслуживать машины. Любая ошибка обнаруживалась машиной практически в момент совершения, и следовательно указывала техническому персоналу правильное направление, вместо того чтобы водить их за нос, заставляя менять настройки корректно работающих частей в попытках найти неисправность.

Нарушая временную последовательности повествования, но оставаясь в идейной, AT&T (прим. американский транснациональный телекоммуникационный конгломерат) однажды спросил меня, как использовать кодирование, если люди использовали алфавит из 26 букв, 10 десятичных цифр и пробел. Это типично для именования инвентаря, именования частей и многих других наименований вещей, включая именование зданий. Я знал из данных по ошибкам набора телефонных номеров и из долгого опыта в программировании, что у людей есть сильно выраженная склонность к переставлению смежных цифр: 67 может стать 76, а так же к замене изолированных цифр (обычно удваивая цифру: 556 вероятно станет 566). Таким образом, обнаружение однократных ошибок недостаточно. Я привел двоих очень способных людей в переговорную комнату и задал им вопрос. Я отвергал предложение за предложением как недостаточно хорошие, пока наконец один из них, Эд Гильберт, не предложил взвешенный код. В частности, он предложил обозначить числами 0, 1, 2, … 36 символы 0, 1, … 9, A, B, …, Z, пробел. Затем он вычислял не сумму значений, а имел ли к-тый символ значение (отмеченное для удобства) Sk, тогда для сообщения из n символов мы вычисляем

image

“По модулю” здесь означает, что взвешенная сумма делится на 37 и только остаток от деления используется. Чтобы закодировать сообщение из n символов, оставьте первый символ, k=1, пустым и независимо от значения остатка, которое меньше 37, вычьте его из 37 и используйте соответствующий символ для проверки, который нужно поставить на первую позицию. Таким образом, все сообщение с проверяющим символом на первой позиции будет иметь проверочную сумму равную 0. Если вы рассмотрите перестановку любых двух различных символов или замену единственного символа, вы заметите, что это сломает взвешенную проверку четности, по модулю 37 (при условии, что заменённые символы находятся на расстоянии не равном 37 символов). Не вникая в детали, отметим, что важно, чтобы модуль был простым числом, каким 37 и является.

Чтобы получить взвешенную сумму символом (фактически, их значения), при желании вы можете избегать произведений и использовать только сложения и вычитания. Расположите символы по порядку в столбце и вычислите промежуточные суммы, затем промежуточные суммы промежуточных сумм по модулю 37, затем дополните это по отношению к 37, и вы получите контрольный символ. Как иллюстрация с использованием w, x, y, z.

image

На принимающей стороне вы повторно вычитаете модуль до тех пор, пока не получите или a-0 (корректный символ) или a — отрицательное число (неправильный символ).

Если вам необходимо использовать это кодирование, например, для наименования инвентаря, то если неправильное название появилось впервые во время передачи, если не раньше (возможно, в предварительном процессе), то ошибка будет обнаружена, вам не придётся ждать до тех пор, пока заказ не будет доставлен до штаб-квартиры, чтобы позднее получить ответ, что не существует такого наименования, или получить неправильный заказ. Ошибка будет обнаружена до того, как заказ покинет вас и следовательно, её легко исправить. Просто? Да! Эффективно против ошибок человека (в отличие от примера с белым шумом), да!

Действительно, в наши дни вы можете увидеть подобный код на книгах с ISBN номером. Это тот же код, только в нем используется 10 десятичных цифр, и число 10 не является простым числом, поэтому им пришлось ввести 11-й символ X, который может появляться временами во время проверки на четность — действительно, примерно каждая 11-я книга будет иметь X как последний символ в номере ISBN для проверки на четность. Тире в основном выполняют декоративную функцию и не используются в кодировании. Проверьте это сами на ваших учебниках. Многие другие крупные организации могли бы использовать такие коды для хорошего эффекта, если бы они хотели приложить усилия.

Я многократно указывал, что я верю, что в будущем информация в форме символов будет важна, и материальные вещи будут менее важны, и следовательно, теория кодирования (представления) информации в удобные коды — это нетривиальная тема. Материал выше дает простой код с обнаружением ошибок для машин, и взвешенный код для использования человеком. Это всего лишь 2 примера, как теория кодирования может помочь в ситуациях, где возможна машинная и человеческая ошибка.

Когда вы думаете об интерфейсе человек-компьютер, одна из вещей, которая вам может пригодиться, это необходимость сделать как можно меньше нажатий клавиш человеком — кодирование ХАффмана под прикрытием! Очевидно, при данных вероятностях различных ветвлений в программных меню вы можете при желании придумать способ уменьшить суммарное количество нажатий клавиш. Таким образом один и тот же набор меню может быть настроен под привычки различных людей, вместо того, чтобы предлагать всем одинаковый интерфейс. В более широком смысле “автоматизированное программирование” в языках высокого уровня является попыткой достичь чего-то наподобие кодирования Хаффмана, чтобы для решения желаемых задач использовать сравнительно небольшое количество нажатий клавиш, а для остальных задач использовать другие клавиши.

Продолжение следует…

Кто хочет помочь с переводом, версткой и изданием книги — пишите в личку или на почту magisterludi2016@yandex.ru

Кстати, мы еще запустили перевод еще одной крутейшей книги — «The Dream Machine: История компьютерной революции»)

Содержание книги и переведенные главы

Предисловие

  1. Intro to The Art of Doing Science and Engineering: Learning to Learn (March 28, 1995) Перевод: Глава 1
  2. «Foundations of the Digital (Discrete) Revolution» (March 30, 1995) Глава 2. Основы цифровой (дискретной) революции
  3. «History of Computers — Hardware» (March 31, 1995) Глава 3. История компьютеров — железо
  4. «History of Computers — Software» (April 4, 1995) Глава 4. История компьютеров — Софт
  5. «History of Computers — Applications» (April 6, 1995) Глава 5. История компьютеров — практическое применение
  6. «Artificial Intelligence — Part I» (April 7, 1995) Глава 6. Искусственный интеллект — 1
  7. «Artificial Intelligence — Part II» (April 11, 1995) Глава 7. Искусственный интеллект — II
  8. «Artificial Intelligence III» (April 13, 1995) Глава 8. Искуственный интеллект-III
  9. «n-Dimensional Space» (April 14, 1995) Глава 9. N-мерное пространство
  10. «Coding Theory — The Representation of Information, Part I» (April 18, 1995) (пропал переводчик :((( )
  11. «Coding Theory — The Representation of Information, Part II» (April 20, 1995)
  12. «Error-Correcting Codes» (April 21, 1995) (готово)
  13. «Information Theory» (April 25, 1995) (пропал переводчик :((( )
  14. «Digital Filters, Part I» (April 27, 1995) Глава 14. Цифровые фильтры — 1
  15. «Digital Filters, Part II» (April 28, 1995) Глава 15. Цифровые фильтры — 2
  16. «Digital Filters, Part III» (May 2, 1995) Глава 16. Цифровые фильтры — 3
  17. «Digital Filters, Part IV» (May 4, 1995) Глава 17. Цифровые фильтры — IV
  18. «Simulation, Part I» (May 5, 1995) (в работе)
  19. «Simulation, Part II» (May 9, 1995) Глава 19. Моделирование — II
  20. «Simulation, Part III» (May 11, 1995)
  21. «Fiber Optics» (May 12, 1995) Глава 21. Волоконная оптика
  22. «Computer Aided Instruction» (May 16, 1995) (пропал переводчик :((( )
  23. «Mathematics» (May 18, 1995) Глава 23. Математика
  24. «Quantum Mechanics» (May 19, 1995) Глава 24. Квантовая механика
  25. «Creativity» (May 23, 1995). Перевод: Глава 25. Креативность
  26. «Experts» (May 25, 1995) Глава 26. Эксперты
  27. «Unreliable Data» (May 26, 1995) Глава 27. Недостоверные данные
  28. «Systems Engineering» (May 30, 1995) Глава 28. Системная Инженерия
  29. «You Get What You Measure» (June 1, 1995) Глава 29. Вы получаете то, что вы измеряете
  30. «How Do We Know What We Know» (June 2, 1995) пропал переводчик :(((
  31. Hamming, «You and Your Research» (June 6, 1995). Перевод: Вы и ваша работа

Кто хочет помочь с переводом, версткой и изданием книги — пишите в личку или на почту magisterludi2016@yandex.ru

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

Разбираем популярный миф: «Вещество на 99% состоит из пустоты»

При обсуждении строения атома и вещества часто можно прочитать, что вещество на 99.99…% состоит из пустоты, с разными версиями количества девяток. Как мы сейчас увидим, это утверждение имеет весьма шаткие основания, а попытки оценить долю пустоты в веществе могут с одинаковым успехом дать любое число от 0 до 100%. Последовательное же рассмотрение вопроса в рамках квантовой механики показывает, что от пустоты вещество отличается довольно сильно.

Что не так с 99%?

Традиционная линия рассуждений(*) выглядит так: в атоме, имеющем размер около одного ангстрема (10–10 метра), электроны вращаются вокруг ядра, размер которого в 100 000 раз меньше (около 10–15 метра). Размер самого электрона равен нулю, это точечная частица(**), поэтому атом оказывается практически пустым: в нем «непустое» лишь ядро. Чтобы получить долю объема атома, занимаемого ядром, нужно возвести в куб отношение их размеров. Получаем, что ядро занимает 10–15 объема атома, остальную долю объема — это 99.99…% с 13 девятками после запятой — занимает пустота.

Если атом растянуть до размеров футбольного поля, то ядро будет величиной с маковое зернышко.

Что не так в этих рассуждениях? Давайте продолжим ту же логику, рассматривая уже на атом, а его ядро. Мы считали атомное ядро непустым, но ведь оно состоит из протонов и нейтронов, которые, в свою очередь, состоят из фундаментальных частиц — кварков и глюонов(***). По современным представлениям, кварки и глюоны тоже являются точечными частицами, как и электрон. Следуя такой же линии рассуждений, как и в случае атома, получим, что ядро — тоже пустота, в которой летают частицы нулевых размеров. Итог: вещество ровно на 100% состоит из пустоты. Эта линия рассуждений завела нас в никуда.

Что говорит квантовая механика?

Квантовая механика говорит нам, что электрон в атоме является не маленьким шариком, летающим по орбите вокруг ядра, а размазан по пространству в виде вероятностного облака, называемого орбиталью. Плотность этого облака, или просто электронная плотность $n(vec{r})$, зависит от координаты $vec{r}$. Эта зависимость своя для каждой орбитали, тем не менее, есть общая закономерность: $n(vec{r})$ заметно отлична от нуля в области пространства размерами порядка ангстрема, а на больших расстояниях от ядра экспоненциально убывает.

Типичное поведение электронной плотности в атоме для разных электронных орбиталей. Источник.

Отсюда берется характерный размер атома в один ангстрем, использованный выше при сравнении размеров атома и ядра. Какой же количественный ответ на вопрос о доле пустоты в веществе может дать нам квантовая механика? Для этого нужно оценить суммарный объем, занимаемый электронными орбиталями всех атомов. А для этого, в свою очередь, следует провести четкую границу между атомом и окружающей его пустотой. Но как это сделать? Формально электронная плотность $n(vec{r})$, хоть и стремится к нулю при удалении от ядра, никогда в ноль не обращается, поэтому каждая атомная орбиталь заполняет если не всю Вселенную, то, как минимум, весь объем рассматриваемого куска вещества. В этом случае получается, что пустоты в веществе нет — в любой точке есть отличная от нуля вероятность найти электрон.

Можно определить границу атома как место, где электронная плотность достигает 1/2 от максимальной. Или 1/15 — такая граница будет отстоять дальше от ядра. Или как поверхность, внутри которой содержится 1/2 всей суммарной электронной плотности. Можно ухватить и больше объема, проведя поверхность, внутрь которой попадает, например, 9/10 всей плотности.

Плотность электронного облака для орбитали $3p_{m=0}$ в атоме водорода (показана белым цветом) и разные варианты проведения условной границы атома.

Как видим, по-разному проводя условные границы атомов, можно получать разные величины занимаемого ими объема. Поэтому и для доли пустоты в веществе можно получить любой ответ от 0 до 100%. Например, в этом видео доля пустоты оценивается как 90%. Почему именно 90, а не 80 или 95? Видимо, автор взял какой-то «стандартный» размер атома в районе одного ангстрема.

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

Пример поверхности (она зеленая и полупрозрачная), на которой электронная плотность в кристалле принимает постоянное значение. Источник.

А так выглядят поверхности постоянной плотности в некоторых белках. Источник.

Что говорит квантовая теория поля?

Даже если вещество от пустоты нельзя четко отделить, можно ли хотя бы ответить на вопрос, чем вообще, с точки зрения квантовой теории, вещество отличается от пустого пространства? Для ответа обратимся к квантовой теории поля, изучающей системы многих частиц и вакуум. В этой теории любое состояние системы (точнее, квантованного поля), в которой может находиться 0, 1, 2 и т.д. частиц, характеризуется вектором, длина которого равна единице.

Подробнее

Каждый вектор $vec{a}$ можно задать его проекциями $a_1,,a_2,,ldots$ на координатные оси, число которых равно размерности пространства $D$: $vec{a}={a_1,a_2,ldots,a_D}$. Квантовые системы описываются векторами в бесконечномерном пространстве, то есть такими векторами, число проекций которого бесконечно: $vec{a}={a_1,a_2,ldots}$. Сами же проекции $a_1,,a_2,,ldots$ в квантовой механике являются комплексными числами, это обстоятельство важно при описании явлений интерференции.

Если в системе нет ни одной частицы (пустота), ее состояние называют вакуумом, и соответствующий вектор принято обозначать как $|0rangle$. Атом с одним электроном на любой орбитали — это состояние системы с одной частицей, вектор которого можно обозначить как $|psirangle$. Насколько отличаются эти два состояния друг от друга? Существуют разные способы описания «расстояния» между векторами, наиболее простой и часто используемый(****) — посчитать длину разности векторов $|psirangle-|0rangle$. Можно показать, что векторы $|0rangle$ и $|psirangle$ взаимно перпендикулярны, это обычная ситуация для существенно отличающихся друг от друга квантовых состояний. Выходит, что, с точки зрения квантовой теории поля, «расстояние» между пустотой и электроном, находящимся на атомной орбитали, равно $sqrt{2}$.

Два взаимно перпендикулярных вектора состояния — вакуум и один электрон на атомной орбитали, — и расстояние между ними.

Получаемый ответ — что вещество даже всегда радикально отличается от пустоты, даже если содержит одну частицу на кубический километр, — не очень удовлетворителен, потому что из него начисто выпадает распределение вещества в пространстве. Можно ли ввести меру отличия вещества от пустоты, показывающую, насколько сильно они отличаются не в целом, а локально, в каждой точке $vec{r}$? Да, такую меру найти можно, и ей является не что иное как электронная плотность $n(vec{r})$. Там, где электронная плотность спадает до предельно малых значений, отличие вещества от пустоты также становится несущественным.

Пара формул

Это можно понять, если учесть, что квадрат расстояния $||psi-0||^2$ представляется в виде:

$||psi-0||^2=langle0|0rangle+langlepsi|psirangle=1+int|Psi(vec{r}_1ldotsvec{r}_N)|^2:dvec{r}_1ldots dvec{r}_N=1+frac1Nint n(vec{r}):dvec{r},$

где $Psi(vec{r}_1ldotsvec{r}_N)$ — волновая функция многоэлектронной системы, $N$ — число электронов. Как видим, квадрат расстояния складывается из двух частей: одна из них равна единице, другая набегает за счет интеграла от электронной плотности по пространству.

Линии равных электронных плотностей в кристалле Na2GeS3. Чем дальше от атомных ядер, тем ниже плотность, и тем ближе пустота. Источник.

Итак, мы видим, что:

  • Если рассуждать в духе «в атоме непустым является лишь ядро», то придется признать, что вещество — ровно на 100% пустота, потому что ядро — это такой же пустой «атом», только состоящий из других частиц.
  • В квантовой механике электронные оболочки атомов размазаны в пространстве, и невозможно точно сказать, где кончается атом и начинается окружающее его пустое пространство. Как следствие, нельзя и точно сказать, какова доля пустоты в веществе — с одинаковым успехом можно взять любое число от 0 до 100%.
  • С точки зрения квантовой теории поля, вещество даже с одним электроном существенно отличается от вакуума — эти два квантовых состояния представляются взаимно перпендикулярными векторами, расстояние между которыми равно $sqrt{2}$.
  • Однако можно, в каком-то смысле, ввести меру отличия вещества от вакуума не в целом, а локально, в каждой точке пространства. Этой мерой является электронная плотность $n(vec{r})$. К сожалению, электронная плотность — размерная величина, она имеет размерность м–3, и поэтому не дает нам ответа на вопрос «на сколько процентов вещество вот в этой точке отличается от пустоты». С ее помощью можно лишь судить о том, где вещество сильнее отличается от пустоты, а где слабее. Вблизи центров атомов $n(vec{r})$ максимальна, там вещество отличается от пустоты сильнее всего, а на больших расстояниях от атомов она очень быстро убывает, и отличие вещества от пустоты становится несущественным.

(*)Вот примеры такого рода рассуждений, в которых, впрочем, соотношение размеров атома и ядра иногда преувеличивают в миллионы раз:
www.popmech.ru/science/10566-zhizn-v-pustote-kvantovoe-osoznanie
www.yaplakal.com/forum7/topic1503279.html
pikabu.ru/story/tyi_nichto_561687
thequestion.ru/questions/10102/atom-sostoit-iz-pustoty-vsyo-materialnoe-sostoit-iz-atomov-kak-materialnoe-mozhet-sostoyat-iz-pustoty

(**)По крайней мере, эксперименты на Большом электрон-позитронном коллайдере показали, что размер электрона не превышает 10–19 м. Более поздние сверхточные измерения магнитного момента электрона дали верхнюю оценку размера электрона, равную 10–20 м. Эти оценки показывают, что электрон, как минимум, в десятки тысяч раз меньше ядра.

(***)Интересный факт: три кварка, из которых состоит протон, дают лишь менее 2% его массы. Остальная часть массы — это виртуальные частицы (кварки и глюоны), возникающие в результате взаимодействия трех исходных кварков. Этих частиц так много, что они образуют целое «море», и поэтому называются «морскими» кварками и глюонами.

(****)В случае двух чистых квантовых состояний $0rangle$ и $psirangle$ такие меры расстояния между ними, как метрика Гильберта-Шмидта и метрика Фубини-Штуди, сводятся именно к длине вектора $psirangle-0rangle$.

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

В деятельности “Роскосмоса” выявлены нарушения на 760 миллиардов рублей

  • Новость
На днях появилась информация о том, что Счетная плата недовольна финансовыми результатами деятельности госкорпорации «Роскосмос». Председатель Счетной палаты Алексей Кудрин сообщил, что в 2017 году в госпредприятиях было выявлено множество нарушений, и 40% из них относятся к деятельности «Роскосмоса», пишет «Интерфакс».

«Общая сумма выявленных нарушений, недостатков поступлений и использования средств составила 1,865 триллиона. Это почти вдвое больше, чем в 2016 году и 3,5 раза больше, чем в 2015-м. Сразу скажу, что 760 миллиардов из этой суммы — это нарушения по учету в «Роскосмосе». В том числе и по результатам этих проверок открыты и уголовные дела», — заявил Кудрин на пленарном заседании в Госдуме во время выступления с годовым отчетом о деятельности Счетной палаты за 2017 год.

По данным Счетной палаты, 43,6% нарушений от общего объема обнаруженных в «Роскосмосе» проблем являются нарушениями бухгалтерского учета. Еще 32% составляют нарушения при формировании и исполнении бюджетов.

В феврале 2018 было объявлено, что «Роскосмос» погасил свою задолженность перед Министерством Финансов в размере 46,9 млрд руб. До этого корпорацию признали худшим должников из всех, поскольку из 52 млрд руб. долгов ею было выплачено всего 9,5 млрд руб. Между тем в 2017 году госкорпорация получила из бюджета страны 138 млрд руб. Это значительно меньше, чем 2016 году, когда государство перечислило на счета «Роскосмоса» 201 млрд руб., но сумма все равно огромная. Расходы, запланированные на 2018 год, составляют 129 млрд руб.

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

Доступ к данным в многопользовательских приложениях

Вопрос ограничения доступа к данным встает при разработке многопользовательских систем почти всегда. Основные сценарии следующие:

  1. ограничение доступа к данным для пользователей не прошедших аутентификацию
  2. ограничение доступа к данным для аутентифицированных, но не обладающих необходимыми привелегиями пользователей
  3. предотвращение несанкционированного доступа с помощью прямых обращений к API
  4. фильтрация данных в поисковых запросах и списковых элементах UI (таблицы, списки)
  5. предотвращение изменения данных, принадлежащих одному пользователю другими пользователями

Сценарии 1-3 хорошо описаны и обычно решаются с помощью встроенных средств фреймворков, например role-based или claim-based авторизации. А вот ситуации, когда авторизованный пользователь может по прямому url получить доступ к данным «соседа» или совершить действие в его аккаунте случаются сплошь и рядом. Происходит это чаще всего из-за того что программист забывает добавить необходимую проверку. Можно понадеяться на код-ревью, а можно предотвратить такие ситуации применив глобальные правила фильтрации данных. О них и пойдет речь в статье.

Списки и таблицы

Типовой контроллер для получения данных в ASP.NET MVC может выглядеть как-то так:

        [HttpGet]
        public virtual IActionResult Get([FromQuery]T parameter)
        {
            var total =  _dbContext
                .Set<TEntity>()
                .Where(/* some business rules */)
                .Count();
            var items=  _dbContext
                .Set<TEntity>()
                .Where(/* some business rules */)
                .ProjectTo<TDto>()
                .Skip(parameter.Skip)
                .Take(parameter.Take)
                .ToList();
            return Ok(new {items, total});
        }

В данном случае вся ответственность за фильтрацию данных ложится только на программиста. Вспомнит ли он о том, что необходимо добавить условие в Where или нет?

Можно решить проблему с помощю глобальных фильтров. Однако, для ограничения доступа нам потребуется информация о текущем пользователе, а значит конструирование DbContext придется усложнить, чтобы проинициализировать конкретные поля.

Если правил много, то реализации DbContext неизбежно придется узнать «слишком много», что приведет к нарушению принципа единственной ответственности.

Слоеная архитектура

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

Добавляем абстракцию

В .NET для доступа к данным уже есть IQueryable. Заменим прямой доступ к DbContext на доступ вот к такому провайдеру:

    public interface IQueryableProvider
    {
        IQueryable<T> Query<T>() where T: class;
        IQueryable Query(Type type);
    }

А для доступа к данным вот такой фильтр:

     public interface IPermissionFilter<T>
    {
        IQueryable<T> GetPermitted(IQueryable<T> queryable);
    }

Реализуем провайдер таким образом, чтобы он искал все объявленные фильтры и автоматически применял их:

     public class QueryableProvider: IQueryableProvider
     {
        // ищем фильтры и запоминаем их типы
        private static Type[] Filters = typeof(PermissionFilter<>)
            .Assembly
            .GetTypes()
            .Where(x => x.GetInterfaces().Any(y =>
                y.IsGenericType && y.GetGenericTypeDefinition()
                    == typeof(IPermissionFilter<>)))
            .ToArray();
        private readonly DbContext _dbContext;
        private readonly IIdentity _identity;
        public QueryableProvider(DbContext dbContext, IIdentity identity)
        {
            _dbContext = dbContext;
            _identity = identity;
        }
        private static MethodInfo QueryMethod = typeof(QueryableProvider)
            .GetMethods()
            .First(x => x.Name == "Query" && x.IsGenericMethod);
        private IQueryable<T> Filter<T>(IQueryable<T> queryable)
           => Filters
                // ищем фильтры необходимого типа
                .Where(x => x.GetGenericArguments().First() == typeof(T))
                // создаем все фильтры подходящего типа и применяем к Queryable<T>
                .Aggregate(queryable,
                   (c, n) => ((dynamic)Activator.CreateInstance(n,
                       _dbContext, _identity)).GetPermitted(queryable));
        public IQueryable<T> Query<T>() where T : class
            => Filter(_dbContext.Set<T>());
        // из EF Core убрали Set(Type type), приходится писать самому :(
        public IQueryable Query(Type type)
            => (IQueryable)QueryMethod
                .MakeGenericMethod(type)
                .Invoke(_dbContext, new object[]{});
    }

Код получения и создания фильтров в примере не оптимален. Вместо Activator.CreateInstance а лучше использовать скомпилированные Expression Trees. Во некоторых IOC-контейнерах реализованна поддержка регистрации открытых generic’ов. Я оставлю вопросы оптимизации за рамками этой статьи.

Реализуем фильтры

Реализация фильтра может выглядеть, например, так:

     public class EntityPermissionFilter: PermissionFilter<Entity>
     {
        public EntityPermissionFilter(DbContext dbContext, IIdentity identity)
            : base(dbContext, identity)
        {
        }
        public override IQueryable<Practice> GetPermitted(
            IQueryable<Practice> queryable)
        {
            return DbContext
                .Set<Practice>()
                .WhereIf(User.OrganizationType
                    == OrganizationType.Client,
                    x => x.Manager.OrganizationId == user.OrganizationId)
                .WhereIf(User.OrganizationType == OrganizationType.StaffingAgency,
                    x => x.Partners
                        .Select(y => y.OrganizationId)
                        .Contains(User.OrganizationId));
        }
    }

Исправляем код контроллера

        [HttpGet]
        public virtual IActionResult Get([FromQuery]T parameter)
        {
            var total = QueryableProvider
                .Query<TEntity>()
                .Where(/* some business rules */)
                .Count();
            var items = QueryableProvider
                .Query<TEntity>()
                .Where(/* some business rules */)
                .ProjectTo<TDto>()
                .Skip(parameter.Skip)
                .Take(parameter.Take)
                .ToList();
            return Ok(new {items, total});
        }

Изменений совсем не много. Осталось запретить прямой доступ к DbContext из контроллеров и если фильтры правильно написаны, то вопрос доступа к данным можно считать закрытым. Фильтры достаточно маленькие, поэтому покрыть их тестами не составит труда. Кроме того эти-же самые фильтры можно использовать, чтобы написать код авторизации, предотвращающий несанкционированный доступ к «чужим» данным. Этот вопрос я оставлю для следующей статьи.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

А как вы управляете доступом к данным?

Проголосовали 3 пользователя. Воздержался 1 пользователь.

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

[Из песочницы] Как собрать аналитику и не убить производительность

Аналитика — это неотъемлемая часть современного мобильного приложения. Аналитика позволяет собрать информацию о пользователе, чтобы развивать и совершенствовать продукт.

Часто сбор информации снижает производительность приложения. Процесс дополнительно нагружает CPU и память, а это высокая цена. Медленная работа приложения может стать причиной негативных отзывов пользователей, снизить рейтинг и привести к потере аудитории.

С такой проблемой столкнулась и наша команда Android-разработчиков во время работы над очередным проектом, который был связан с новостями. Нам нужно было регистрировать отображение каждой новости в списке.

Попытка №1

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

Каждый воспринимает подвисание по-разному, так что мы нуждались в фактах и доказательствах. Чтобы измерить подвисание, выбрали показатель FPS (Frames Per Second), а для измерения показателя — FPS-meter TinyDenser. После подключения утилиты команда получила объективное подтверждение проблемы — показатель падал, временами достаточно заметно: меньше 30 кадров в секунду, запись экрана с включенной утилитой показана на Рисунке 1.

image

Рисунок 1. Запись экрана до оптимизации

Попытка №2

А если отложить отправку событий, пока пользователь скроллит список? «Хммм», — подумала команда, и решила создать очередь из событий и отправлять их после того, как скролл остановится. Тут все просто: добавляем OnScrollListener в RecyclerView и ждем, пока newState будет ровным SCROLL_STATE_IDLE — задача частично решена.

class IdleStateScrollListener(private val analyticsFacade: AnalyticsFacade)
      : RecyclerView.OnScrollListener() {
    fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        analyticsFacade.setPending(newState != RecyclerView.SCROLL_STATE_IDLE)
    }
}

Следующий шаг — реализовать накопление событий и их отправку.

Для управления очередью создали класс, который отвечал за добавление событий в очередь и отправку аналитики в сервис. Для периодической отправки выбрали ScheduledExecutorService с одним потоком, который запускал Runnable каждую секунду, время подобрали эмпирическим способом.

Это сразу дало результаты, значительный прирост FPS. В принципе, задача была решена, на Рисунке 2 видим результат работы приложения после второй попытки. Но осталась одна задачка — события отправлялись в сервис, что приводило к частому генерированию объектов класса Intent, а это дополнительно нагружало GC и доставляло «приятности» в виде stop-the-world пауз.

image

Рисунок 2. Запись экрана после второй попытки

Попытка №3

«Отправка не одного события за раз, а списка событий — еще одна чудесная идея», — подумала команда. После короткой доработки класса команда реализовала отправление событий списком и получила стабильные значения показателя на уровне 55–60 кадров в секунду (Рисунок 3).

image

Рисунок 3. Запись экрана после третий попытки

Выводы

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

Можно ли было сделать еще что-то?

Наша команда остановилась на третьем варианте, но это не единственное, что можно было применить.

В текущей реализации при срабатывании метода onViewAttachedToWindow происходит превращение новости в объект события аналитики, соответственно, создание нового объекта. Одно из возможных решений — отложить конвертацию до момента отправки: накапливать в очереди не события, а сами элементы списка. Тогда конвертация будет происходить, когда скролл будет в режиме SCROLL_STATE_IDLE. Также для событий можно было создать пул объектов. В комплексе эти действия могут дать дополнительный прирост производительности приложения.

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1