-Поиск по дневнику

Поиск сообщений в rss_rss_hh_new

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 17.03.2011
Записей:
Комментариев:
Написано: 51

Habrahabr/New








Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://habrahabr.ru/rss/new/.
Данный дневник сформирован из открытого RSS-источника по адресу http://feeds.feedburner.com/xtmb/hh-new-full, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

[Перевод] Самый большой репозиторий Git на свете

Среда, 31 Мая 2017 г. 13:58 + в цитатник
Прошло уже три месяца с тех пор, как я опубликовал свою первую статью о наших попытках масштабировать Git для очень крупных проектов при помощи инициативы, которую мы назвали «Git Virtual File System». Напомню: GVFS в сочетании с некоторыми правками в Git позволяет работать с ОЧЕНЬ большими репозиториями, виртуализируя как папку .git, так и рабочую директорию. Вместо того, чтобы скачивать репозиторий целиком и проверять все файлы, инструмент динамично скачивает только те фрагменты, которые вам нужны, выявляя их на основании того, над чем вы работали до этого момента.

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



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

Windows на Git: прямая трансляция


За эти три месяца мы практически завершили процесс внедрения Git/GVFS для команды, работающей с Windows в Microsoft.

Если в двух словах: кодовая база Windows весит около 3.5 мегабайт; когда заливаешь ее на Git, получается репозиторий размером где-то в 300 гигабайт. Более того, в компании работает около 4000 инженеров; инженерная система ежедневно производит 1,760 сборок по 440 веткам, вдобавок к pull-запросам на валидацию билдов. Все эти три обстоятельства (количество файлов, размер репозитория, темп работы) сильно усложняют дело даже по отдельности, а взятые вместе делают обеспечение позитивного опыта невероятно сложной задачей. До перехода на Git мы пользовались Source Depot и код был распределен по 40 с лишним репозиториям, у нас даже был специальный инструмент, чтобы управлять операциями.

На момент выхода моей первой статьи три месяца назад весь наш код хранился в одном Git репозитории, которым пользовались несколько сотен программистов для обработки очень скромного процента билдов (менее 10%). С тех пор мы в несколько этапов выкатили проект для всего инженерного состава.

Первый, и самый массовый, скачок произошел 22 марта, когда мы перевели на новую систему всю команду Windows OneCore целиком — а это около 2000 человек. Эти 2000 инженеров еще в пятницу работали с Source Depot, а вернувшись в офис после выходных, обнаружили, что их ждет радикально новый опыт с Git. Все выходные моя команда просидела скрестив пальцы и молясь, чтобы в понедельник нас не разорвала разъяренная толпа инженеров, у которых застопорилась вся работа. На самом деле, команда Windows очень хорошо продумала запасные планы на случай, если что-то пойдет не так; к счастью, нам не пришлось к ним прибегнуть.

Но все прошло неожиданно гладко и разработчики с первого же дня сумели приспособиться к новым условиям без ущерба продуктивности — честно говоря, я даже удивился. Несомненно, возникали и сложности. К примеру, команде Windows из-за ее огромных размеров и специфики работы, часто приходилось производить слияние ОЧЕНЬ крупных ветвей (речь идет о десятках тысяч изменений и тысячах конфликтов). Уже в первую неделю стало ясно, что наш интерфейс для pull-запросов и разрешения конфликтов слияния просто не приспособлен для таких масштабных изменений. Пришлось в срочном порядке вирутализировать списки и получать данные командой fetch поэтапно, чтобы интерфейс не подвисал. Через пару дней мы с этим справились и, в целом, неделя прошла на более позитивной ноте, чем мы рассчитывали.

Один из способов, которые мы использовали, чтобы оценить успешность всего мероприятия — это опрос инженеров. Главный вопрос, который мы им задали — это «Довольны ли вы?», хотя, конечно, не забыли расспросить и о подробностях. Первый опрос состоялся через недели после запуска проекта и показал следующие результаты:



(Полностью довольны: 54;
Скорее довольны: 126;
Скорее недовольны: 54;
Крайне недовольны: 17)


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

Другой способ, который мы применяли для оценки успешности, — отслеживание деятельность инженеров, чтобы проверить, выполняется ли необходимый объем работы. Например, мы фиксировали количество залитых фрагментов кода для всех официальных подразделений. Разумеется, половина компании все еще оставалась на Source Depot, в то время как вторая половина уже перешла на Git, поэтому наши замеры отражали некую смесь из их результатов. На графике, приведенном ниже, вы можете заметить ощутимый спад в числе залитых файлов на Source Depot и ощутимый подъем в pull-запросах на Git, но суммарное количество остается примерно одинаковым на всем отрезке. Мы решили, что на основании этих данных можно сделать вывод: система работает и существенных препятствий к использованию не содержит.



22 апреля мы выкатили продукт еще для 1000 инженеров; чуть позже, 12 мая — для следующих 300-400. Адаптация каждой следующей волны происходила по тем же паттернам, что и у предыдущих, и в данный момент 3500 из 4000 инженеров Windows перешли на Git. Оставшиеся команды в данный момент доводят свои проекты до завершения и пытаются определиться с оптимальным временем для перехода, но, думаю, к концу месяца будут охвачены все сотрудники.

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

  • В общей сложности за 4 месяца существования репозитория было совершено более 250,000 Git коммитов;
  • 8,421 пушей в среднем за день;
  • 2,500 pull-запросов и 6,600 инспекторов кода в среднем за рабочий день;
  • 4,352 активных ответвлений;
  • 1,760 официальных сборок в день.

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

Производительность GVFS при работе на масштабных проектах


По результатам опроса видно, что существующим положением вещей довольны не все. Мы собрали много данных на этот счет, и причины самые разные — от того факта, что не все инструменты поддерживают Git, до досады, что приходится осваивать что-то новое. Но основная проблема — производительность, и ее-то я и хочу разобрать досконально. Выкатывая Git, мы знали, что с точки зрения производительности он еще недоработан, да и в процессе внедрения многому научились. Мы отслеживаем производительность для ряда ключевых операций. Вот данные, которые собрали телеметрические системы, по работе 3500 инженеров, использующих GVFS.



Здесь вы видите «цель» (мы рассчитывали ее как худшее из допустимых значений — не то, к чему мы стремимся, а порог, ниже которого нельзя опускаться, чтобы система вообще работала). Также приведены результаты по 80му перцентилю за последние семь дней и разница с результатами предыдущей недели. (Как можете заметить, все замедляется — мы поговорим об этом подробнее чуть позже).

Чтобы вам было с чем сравнивать, скажу так: если бы мы попытались проделать что-то подобное на «классическом Git», прежде чем начали работу над ним, многие из команд выполнялись бы от тридцати минут до нескольких часов, а некоторые вообще никогда бы не дошли до завершения. То, что большинство сейчас обрабатывается за 20 секунд и меньше — это огромный шаг вперед, хотя в постоянных 10-15 секундных интервалах ожидания тоже, конечно, ничего хорошего.

Когда мы только-только выкатили проект, результаты были куда лучше. Это стало для нас одним из главных открытий. Если вы прочитаете вводный пост, где я даю общее представление о GFVS, там говорится о том, как мы работали над Git и GVFS, чтобы сделать ряд операций пропорциональными не общему числу файлов в репозитории, но числу «прочитанных» файлов. Как выясняется, со временем инженеры расползаются по кодовой базе и прикасаются к все большему числу файлов, что приводит к проблеме, которую мы называем «over hydration» (перенасыщение). В итоге мы имеем кучу файлов, которых кто-то когда-то касался, но после этого не использовал и определенно не вносил никаких изменений. Как следствие, производительность падает. Люди могут «подчищать» свои списки заходов, но это лишняя морока и никто этого не делает, а работа системы все замедляется и замедляется.

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

У меня пока что нет всех значений, но я отобрал для примера несколько полей из таблицы выше и вставил соответствующие цифры в колонку O(hydrated). В добавленной колонке O(modified) я привел результаты, которые мы получили по тем же командам с применением оптимизированной версии, которую собираемся выкатить на следующей неделе. Единица измерения там и там — секунды. Как видите, в целом и общем наблюдается заметный прогресс: где-то скорость возросла незначительно, где-то — в два раза, а где-то — в пять. Мы возлагаем большие надежды на эти улучшения и рассчитываем, что они качественно изменят пользовательский опыт. Я не совсем доволен (не успокоюсь, пока Status не станет занимать меньше секунды), но все-таки мы здорово продвинулись.



Другая немаловажная область производительности, которой я не коснулся в предыдущем посте — это географическое распределение команд. Инженеры Windows разбросаны по всему земному шару — США, Европа, Средняя Азия, Индия, Китай и так далее. Pulling большие объемы данных на больших расстояниях, зачастую с далекой от идеала пропускной способностью — серьезная проблема. Чтобы с ней справиться, мы создали прокси-решение на Git для GVFS, которое позволяет кэшировать данные с Git на выходе. Также мы использовали прокси, чтобы разгружать очень большие объемы траффика (скажем, серверы билдов) из главного сервиса Visual Studio Team Services, чтобы пользовательский опыт не страдал даже в часы, когда нагрузка максимальная. В общей сложности у нас 20 прокси для Git (которые, кстати, мы просто инкорпорировали в уже существующий Team Foundation Server Proxy) по всему свету.

Чтобы вы лучше представляли, какой это дало эффект, позвольте привести пример. Аккаунт Windows Team Services находится в дата-центре Azure, на западном побережье США. Выше я указывал, что для инженера Windows операция клонирования по 80му перцентилю занимает 127 секунд. Так как большая часть инженеров работает из Редмонда, это значение актуально в первую очередь для них. Мы провели тест в отделении в Северной Каролине, которое и более удалено от центра, и располагает меньшей пропускной способностью. Без применения прокси на ту же операцию потребовалось около 25 минут. С настроенным и обновленным прокси время сократилось до 70 секунд (то есть быстрее, чем в отделении Редмонда — там команда не пользуется прокси и от Azure их отделяют сотни миль интернет-кабелей). 70 секунд против 25 минут — это улучшение почти на 95%.

В целом, Git с GVFS абсолютно готов к употреблению и может применяться к проектам невероятного масштаба. Результаты показывают, что продуктивность наших инженеров при этом не страдает. Однако нам предстоит еще много работы, прежде чем система будет усовершенствована настолько, чтобы сотрудники были ей довольны. Работа, проделанная в O(modified), которую мы выкатим на следующей неделе, станет большим шагом в этом направлении, но потребуется несколько месяцев дополнительных доработок, чтобы с чистой совестью сказать, что все, что нужно, сделано.

Если хотите подробнее узнать о тех технических сложностях, с которыми мы столкнулись в процессе масштабирования Git и обеспечения хорошего уровня производительности, рекомендую цикл статей о масштабировании Git и GVFS от Saeed Noursalehi. Очень увлекательное чтение.

Попробуйте GVFS сами


GVFS — это проект с открытым кодом, и мы приглашаем всех желающих попробовать с ним поработать. Все, что от вас требуется — скачать и установить его, завести аккаунт в Visual Studio Team Services с репозиторием Git, и можно приступать. С первой публикации GVFS мы основательно продвинулись. Среди самых существенных изменений можно назвать:

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

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

3. GVFS опирается на файловую систему Windows, которую мы называем GVFlt. До сих пор драйвер, доступ к которому мы обеспечили, был неподписанным (так как над ним еще активно велась работа). Очевидно, это значительно усложняло жизнь тем, кто хотел его опробовать. Теперь же мы выпустили подписанную версию GVFlt, в которой устранены все шероховатости (так, вам больше не придется отключать BitLocker для установки). Но хотя у нас появился подписанный GVFlt драйвер, это только временное решение. Мы планируем внедрить соответствующие функции в будущую версию Windows и в данный момент прорабатываем детали.

4. После выступления на конференции Git Merge мы стали активнее обсуждать нюансы масштабирования Git и, в частности, GVFS с широким кругом специалистов, заинтересованных в этой теме. Мы очень продуктивно пообщались с другими крупными компаниями (Google, Facebook), которые сталкиваются с такими же сложностями, и стали делиться своим опытом и подходом. Также мы провели работу с несколькими популярными Git-клиентами, чтобы убедиться, что они совместимы с GVFS. В их число вошли:

  • Atlassian SourceTree — SourceTree стал первым инструментом, который прошел валидацию на совместимость с GVFS; уже вышло обновление, в котором были введены некоторые изменения для более гладкого рабочего процесса.
  • Tower — команда Tower рада сообщить, что они работают над добавлением поддержки GVFS в версию приложения для Windows. В ближайшем будущем соответствующий функицонал будет доступен в бесплатном обновлении.
  • Visual Studio — само собой, неплохо бы и нашему собственному Visual Studio Git нормально работать с GVFS. Мы внедрим поддержку GVFS в версию 2017.3, первое превью которой (со всем необходимым для поддержки) выйдет в начале июня.
  • Git на Windows — в рамках своей инициативы по масштабированию Git мы внесли ряд изменений под Git в Windows (к примеру, командная строка Git), включая поддержку GVFS. Сейчас у нас на Git создано особое ответвление для Windows, но со временем мы хотим все перенести в основную версию кода.


Обобщая сказанное


Мы будем и дальше упорно работать над масштабированием Git, чтобы приспособить его для крупных команд и массивных кодовых баз в Microsoft. С тех пор, как мы впервые заговорили об этом проекте три месяца назад, много чего произошло. В частности, мы:

  • успешно внедрили проект для 3500 инженеров;
  • подключили прокси и доработали продуктивность;
  • обновили открытый код и дали другим пользователям возможность вносить правки/вклады;
  • обеспечили signed GVFlt драйвер, чтобы проще было воспользоваться сервисом;
  • стали сотрудничать с другими командами, чтобы внедрить поддержку в популярные инструменты — SourceTree, Tower, Visual Studio и так далее;
  • опубликовали несколько статей, где с технической точки зрения подробно рассматривается наш подход к масштабированию Git и GVFS.


Это был захватывающий опыт для Microsoft и серьезный вызов для моей команды и команды Windows. Я в восторге от того, чего мы уже добились, но не склонен недооценивать объем работы, который еще остается. Если вы тоже часто оказываетесь в ситуациях, когда приходится работать с кодовыми базами очень больших размеров, но при этом всей душой хотите перейти на Git, призываю вас попробовать GVFS. В данный момент Visual Studio — это единственное бэкенд-решение, которое поддерживает GVFS протокол со всеми нововведениями. В дальнейшем, если проект окажется востребован, мы добавим поддержку GVFS также в Team Foundation Server; также мы провели переговоры с другими сервизами Git, создатели которых рассматривают возможность обеспечить совместимость в будущем.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329878/


Метки:  

[Из песочницы] Реактивная обработка стрима логов с RxJava — Часть 1

Среда, 31 Мая 2017 г. 13:48 + в цитатник

Reactive log stream processing with RxJava — Part l


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


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


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


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


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


 failedLogStream()
     .window(5,TimeUnit.SECONDS)
     .flatMap(window ->
                window
                .groupBy(propertyStringValue("remoteIP"))
                .flatMap(grouped -> grouped
                    .count()
                    .map( failedLoginsCount -> {
                          final String remoteIp = grouped.getKey();
                          return new Pair<>(remoteIp, failedLoginsCount);
                    }))
     )
     .filter(pair -> pair.get > 10)
     .forEach(System.out::println);           

Мы можем инициировать запросы и в других системах и работать с их ответами как с потоками данных, на которые мы можем подписаться и применить несколько привычных операторов для работы со стримами (потоками данных), которые представлены во фреймворках reactive streams (реактивных стримов).


Учим новую парадигму разработки


Хорошо бы разобрать, что такое реактивное программирование стримов, для этого нам нет необходимости разворачивать что-то большое, такое как Kafka Streams Spark or Flink.


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


Самой большой темой, которую принесет Spring5, будет поддержка Реактивного программирования. Новый модуль spring-web-reactive — фреймворк, похожий на spring-web-mvc, который позволит отдавать асинхронные (неблокирующие) ответы для REST сервисов и реактивный веб-клиент, из чего следует возможность применения данного решение для микросервисной архитектуры. Концепция реактивных стримов не специфична для Spring, поскольку существует общая спецификация reactive-streams-jvm, согласованная большинством реактивных фреймворков (пока для нее, может быть, и не существует идентичного наименования, но концепция должна быть достаточно простой, чтобы стать заменой фреймворкам).


Исторически модель реактивные потоки была представлена Rx.NET, а затем при помощи Netflix портирована на java, получив название RxJava. В то же время концепция был также успешно реализована и в других языках, под названием Реактивные расширения (Reactive EXtensions). С тех пор компании движутся в том же направлении, что и спецификация реактивных стримов. Сейчас RxJava, поскольку он был первопроходцем, нуждается в значительном рефакторинге(переписании кода) — соответственно, версия 2.х лучше соответствует спецификации, и, пока Spring reactor еще новичок, компании не составит труда переписать реализацию согласно спецификации. Рекомендуем прочитать больше о том как они взаимосвязаны.


Doug Lea сообщил, что хочет включить реактивные потоки в состав объекта java.util.concurrent.Flow, а это значит, что реактивные стримы будут поставляться в составе Java 9.


Преимущества с точки зрения производительности


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


Never block


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


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


Пример: сервису, такому как Gmail, нужно отображать пользовательские почтовые сообщения (emails). Тем не менее, emails, в свою очередь, могут иметь множество людей в копии (CC). Было бы прикольно отобразить фотографию для тех пользователей, которые находятся в твоих контактах, что означает вызов REST — ContactService.


Получится вот так:


Future> emailsFuture = mailstoreService.getUnreadEmails();  
List emails = emailsFuture.get(); //блокировка текущего потока  
//возможно долгое ожидание, пока не будет получен полный список данных
//можно ли запустить следующий процесс, как только первый фрагмент будет получен?

Future> contacts = getContactsForEmails(emails);  
for(Mail mail : emails) {  
  streamRenderEmails(mail, contacts); //push(отправить) emails клиенту
}

Частично проблема была решена с приходом поддержки реактивного программирования в Java 8 с CompletableFuture (со своими thenCompose, thenCombine, thenAccept и еще 50 методами, хотя это не отменяет того факта, что нужно помнить все, что они делают, а это никак не помогает в прочтении кода).


CompletableFuture> emailsFuture = mailstoreService.getUnreadEmails();

CompletableFuture> emailsFuture  
  .thenCompose(emails -> getContactsForEmails(emails)) //нам все еще нужно ожидать List 
  .thenAccept(emailsContactsPair -> streamRenderEmails(emailsContactsPair.getKey(), emailsContactsPair.getValue()))

Мы можем переключиться на Iterator вместо List-а, и в тоже время не существует методов, говорящих выполнить какое-либо действие при появлении новых значений. В SQL есть такая возможность, к примеру, ResultSet (в котором вы можете выполнить rs.next()) вместо загрузки всех данных в память.


public interface Iterator {  
    /**
     * Возвращает {@code true}, если в итерации больше элементов.
     */
    boolean hasNext();

    /**
     * Возвращает следующий элемент итерации.
     */
    E next();
}

Но нам все еще нужно постоянно спрашивать "а у тебя есть новое значение?"


Iterable emails = mailstoreService.getUnreadEmails();  
Iterator emailsIt = emails.iterator();

while(emailsIt.hasNext()) {  
  Mail mail = emailsIt.next(); //неблокирующее действие все равно тратит много процессорного времени на получение новых значений
  if(mail != null) {
      ....
  }
}

Что нам нужно, так это реактивный итератор, такой тип данных, который сможет подписаться и выполнить действие, как только получено новое значение. Именно здесь начинается reactive stream programming (реактивное программирование стримов).


Так что же такое Stream?


Everything is a stream


Stream по-простому это последовательность упорядоченных во времени событий (событиеX происходит после событияY, так что события не конкурируют между собой).


Stream смоделирован так, что выпускает 0..N событий и одну из двух терминальных операций:


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

Мы можем описать это визуально с помощью 'marble diagrams'.


Marble diagram for Observable


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


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


RxJava определяет Observable (Наблюдаемый) тип данных для моделирования Stream-а событий типа . В Spring Reactor-е он равен типу Flux.

Observable представляет собой stream температур, взятых с различными интервалами.

Observable представляет собой stream продуктов, купленных в нашем веб магазине.

Observable представляет собой одного пользователя (User), вернувшегося по запросу к БД.

    public Observable findByUserId(String userId) {...}
    //пусть будет Single для большей наглядности 
    public Single findByUserId(String userId) {...}

Но Observable это просто тип данных, поэтому, как и в случае с шаблоном проектирования Publish/Subscriber (Публикации/Подписчика), нам нужен Subscriber(Подписчик) чтобы обработать 3 типа событий

        Observable cartItemsStream = ...;

        Subscriber subscriber = new Subscriber() {
            @Override
            public void onNext(CartItem cartItem) {
                System.out.println("Cart Item added " + cartItem);
            }

            @Override
            public void onCompleted() {
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }
        };

        cartItemsStream.subscribe(subscriber);

Реактивные операторы


Но это просто часть Stream-a, а до сих пор мы не применяли ничего необычного, только классический шаблон проектирования Observer (Наблюдатель).


Reactive (Реактивная) же часть означает, что мы можем определить некоторые Function (операторы — функции), которые будут выполнены, когда stream запустит событие.


Это значит, что будет создан другой stream (стримы immutable), на который мы можем подписать другой оператор и т.д.


Observable filteredCartStream = cartStream.filter(new Func1() {  
            @Override
            public Boolean call(CartItem cartItem) {
                return cartItem.isLaptop();
            }
        });

Observable laptopCartItemsPriceStream = filteredCartStream.map(new Func1() {  
            @Override
            public Long call(CartItem cartItem) {
                try {
                    return priceService.getPrice(cartItem.getId());
                } catch(PriceServiceException e) {
                    thrown new RuntimeException(e);
                }
            }
        });

Поскольку операторы (методы) класса Observable (filter, map, groupBy,...) возвращают Observable, это значит, что мы можем использовать цепочку из операторов, чтобы объединить их с лямбда синтаксисом и написать что-нибудь красивое.


Observable priceStream = cartStream  
                        .filter((cartItem) -> cartItem.isLaptop()).
                        .map((laptop) -> {
                             try {
                                  return priceService.getPrice(cartItem.getId());
                            } catch(PriceServiceException e) {
                                 thrown new RuntimeException(e);
                            }
                        });

Обратите внимание, что выше, когда создается priceStream, ничего не происходит — priceService.getPrice() не вызывается, пока нет элемента, проходящего по цепочке операторов. Это означает, что мы создали через rx-оператор подобие плана, как управляемые данные будут спускаться вниз по цепочке(подписание регистрируется).


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


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


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


Его пример с кодом:


Observable mover1 = Observable.create(s -> {  
   while (house.hasItems()) {
    s.onNext(house.getItem());
   }
   s.onCompleted();
});

Observable mover2 = mover1.map(item -> putInBox(item));

Subscription mover3 = mover2.subscribe(box -> putInTruck(box),  
   () -> closeTruck()); //это сработает на событие OnCompleted()


"Грузчик 1 с одной стороны источник Observable. Он создает выбросы за счет того, что выносит вещи из дома. Он вызывает Грузчика 2 с методом onNext(), который выполняет map() операцию. Когда его метод onNext() вызван, он берет вещь и перекладывает в коробку. Затем он вызывает Грузчика 3, конечного Subscriber(подписчика), с методом onNext(), который грузит коробку в машину."


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



Множество Stream операторов помогают составить словарь терминов для обозначения действий, производимых со стримами, которые могут быть реализованы в популярных языках (RxJava, RxJS, Rx.NET, etc) из числа ReactiveX framework (Реактивных расширений).


Эти понятия надо знать даже при использовании различных фреймворков для работы с реактивными стримами, таких как Spring Reactor (в надежде на наличие неких операторов, общих для этих фреймворков).


Пока что мы видели только простые операторы, такие как фильтрация:


**Filter**


Которые только пропускают элементы, попадающие под условие фильтра (один грузчик перенесет только те вещи, которые стоят меньше 100$, вместо того, чтобы передать сразу все другому грузчику)


Однако есть операторы, которые могут разбить стрим на множество отдельных стримов — Observable>(Стрим стримов) — это такие операторы, как groupBy


> **group by**


        Observable values = Observable.just(1,4,5,7,8,9,10);
        Observable> oddEvenStream = values.groupBy((number) -> number % 2 == 0 ? "odd":"even");
        Observable remergedStream = Observable.concat(oddEvenStream);
        remergedStream.subscribe(number -> System.out.print(number +" "));

//Выводит
//1 5 7 9 4 8 10 

и достаточно простой оператор concat, который снова из четных и нечетных стримов создает один-единственный стрим, и устанавливает на него подписку.
> **Concat**


Мы видим, что оператор concat ожидает завершения стрима перед тем, как добавить еще один, снова создавая один стрим. Таким образом, нечетные числа отображаются первыми.


Также у нас есть возможность скомбинировать вместе множество stream-ов, как, например, это делает zip оператор
> **Zip operator**


Zip назван так не потому, что он работает как архиватор, но скорее из-за то, что он, как молния (на куртке), комбинирует события из двух stream-ов.


> Молния (защелка)


Он берет одно событие из одного stream-а и соединяет с событием из другого (делая пару). Как только это выполнено, он применяет оператор склеивания, перед тем, как спуститься дальше по цепочке.


PS: это работает и для большего количества stream-ов.


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


Иметь возможность "ждать" ответа от множества удаленных вызовов, которые мы получаем от stream-ов, на самом деле очень полезно.


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


> Combine latest


Движемся к мышлению на основе Push подхода


Давайте рассмотрим несколько примеров, как на самом деле создают Observables. Наиболее длинный вариант создания:


        log("Before create Observable");
        Observable someIntStream = Observable
                .create(new ObservableOnSubscribe() {
                    @Override
                    public void subscribe(ObservableEmitter emitter) throws Exception {
                        log("Create");
                        emitter.onNext(3);
                        emitter.onNext(4);
                        emitter.onNext(5);
                        emitter.onComplete();
                        log("Completed");
                    }
                });
        log("After create Observable");

        log("Subscribing 1st");
        someIntStream.subscribe((val) -> LOGGER.info("received " + val));
        //мы можем опустить реализацию
        //другие методы(for onError and onComplete) если мы ее хотим сделать, что-то особенное

        log("Subscribing 2nd");
        someIntStream.subscribe((val) -> LOGGER.info("received " + val));

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


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


Когда кто-то подписывается, вызывается метод call() и 3 сообщения проталкиваются вниз по цепочке, следом за ними идет сигнал, что stream завершился.


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


mainThread: Before create Observable  
mainThread: After create Observable  
mainThread: Subscribing 1st  
mainThread: Create  
mainThread: received 3  
mainThread: received 4  
mainThread: received 5  
mainThread: Completed  
mainThread: Subscribing 2nd  
mainThread: Create  
mainThread: received 3  
mainThread: received 4  
mainThread: received 5  
mainThread: Completed  

Важно заметить, что rx операторы не обязательно означают многопоточность. RxJava не внедряет конкурентность по умолчанию между Observable и Subscriber. Поэтому все вызовы происходят на "главном" потоке.


Такой тип Observable, которые начинают распространение, когда кто-нибудь подписан называются cold observables(холодные наблюдатели). Другой вид — hot observables(горячие наблюдатели), они могут выпускать события, даже когда никто не подписан на них.


  • Cold Observables начинают распространять события только когда кто-то подписывается. Каждый подписчик получает одни и те же события. Например, как CD на котором играют одни и те же песни для того, кто включил cd в плеер послушать.
  • Hot Observables события распространяются даже когда на них еще никто не подписался. Как радиостанция которая проигрывает песни через радиовещание, даже когда никто его не включал. И так же, как при включении радиоприемника, ты пропускаешь предшествующие события. Hot observable моделирует события, распространением которых вы не можете управлять. Примерно как в случае записи событий в журнал (лог событий).

Subjects это такой специальный вид Observable, который также является Observer (как Subscriber — который решает, что он может протолкнуть данные (вызовом onNext()) до них) и сделает реализацию горячих Observables проще. Также существует множество реализаций, подобных ReplaySubject, которые сохраняют выделенные события в буфере и воспроизводят их по подписке (конечно, можно указать размер буфера, чтобы предотвратить ошибку OutOfMemory), пока PublishSubject только пропускает события, которые случились после подписания.
И конечно, существует множество статических методов для создания Observables и из других источников.


Observable.just("This", "is", "something")  
Observable.from(Iterable collection)  
Observable.from(Future future) - передает значение после того, как `future` выполнится 

Добавление в наш ELK-стек RabbitMQ эмиттера данных, отправляемых посредством push


По традиции, работая со стеком ELK, мы используем ElasticSearch чтобы запросить данные по логу событий, так что можно сказать, что они в опрашивающем стиле 'pull-based'.


Можем ли вместо этого иметь push-based, где мы собираемся информировать 'незамедлительно' при появлении события в журнале, чтобы дальше уменьшить время реагирования на событие, с того момента как оно произошло и до того как мы начнем его обрабатывать.


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


Возможно вы помните, что Logstash может вести себя как контроллер, и выбирать как ему работать, и куда отправлять/сохранять логируемые событий. Это значит что мы можем отфильтровать те события, которые хотим обработать или указать куда их послать, например, в другие RabbitMQ очереди.


Существует даже возможность напрямую отправлять данные в RabbitMQ через Logback Appender, если вам захочется опустить использование Logstash.


К слову сказать: Пока так называемый AmqpAppender, является скорее специфичной реализацией RabbitMQ AMQP (с версией протокола AMQP 0-9-1, 0-9).


ActiveMQ для примера (пока тоже поддерживает AMQP connector) кажется реализует протокол версии AMQP 1.0, пока spring-amqp библиотека с протоколом версий 0-9-1, 0-9, которые совсем отличаются от 1.0), так что вы может столкнетесь с ошибками по типу 'org.apache.activemq.transport.amqp.AmqpProtocolException: Connection from client using unsupported AMQP attempted'


Однако наше решение было чтобы использовать logstash-logback-encoder и отправлять отформатированный JSON с журналом событий в Logstash. Мы перенаправим logstash вывод на точку обмена RabbitMQ (exchange).


Мы будем использовать docker-compose, чтобы запустить кластер logstash-rabbitmq
Вы можете склонировать репозиторий


docker-compose -f docker-compose-rabbitmq.yml up
и затем вы можете использовать
./event-generate.sh
чтобы сгенерировать некоторое число случайных событий которые будут отправлены на logstash.


Для того, чтобы определить, куда отправлять данные, используйте файл настроек logstash. Мы используем rabbitmq-output-plugin, как ссылку:


output {  
    rabbitmq {
        exchange => logstash
        exchange_type => direct
        host => rabbitmq
        key => my_app
    }
}

RabbitMQ это не классический JMS сервер, вместо этого он использует AMQP протокол, который имеет весьма отличную от остальных концепцию для очередей.


amqp


Издатель отправляет сообщения на именованную точку обмена (exchange) и потребитель забирает сообщения из очереди.


У сообщения есть стандартный заголовок 'routing-key', который используется в процессе называемом ассоциативным привязкой, чтобы связать обмен сообщениями в очереди. Очереди могут фильтровать какие сообщения они получают через ключ привязки, и к тому же можно использовать подставленные знаки в привязке как эти 'logstash.'


Для более подробного объяснения AMQP вы можете прочитать здесь и тут. Так мы настроили Spring соединение c RabbitMq


    @Bean
    ConnectionFactory connectionFactory() {
        return new CachingConnectionFactory(host, port);
    }

    @Bean
    RabbitAdmin rabbitAdmin() {
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory());
        rabbitAdmin.declareQueue(queue());
        rabbitAdmin.declareBinding(bindQueueFromExchange(queue(), exchange()));
        return rabbitAdmin;
    }

    @Bean
    SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setQueueNames(queueName);
        container.setMessageListener(listenerAdapter);

        return container;
    }

    @Bean
    Queue queue() {
        return new Queue(queueName, false);
    }

    DirectExchange exchange() {
        return new DirectExchange("logstash");
    }

    private Binding bindQueueFromExchange(Queue queue, DirectExchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("my_app");
    }

    @Bean
    MessageListenerAdapter listenerAdapter(Receiver receiver) {
        MessageListenerAdapter messageListenerAdapter = new MessageListenerAdapter(receiver,
                new MessageConverter() {
            public Message toMessage(Object o, MessageProperties messageProperties)
                    throws MessageConversionException {
                throw new RuntimeException("Unsupported");
            }

            public String fromMessage(Message message) throws MessageConversionException {
                try {
                    return new String(message.getBody(), "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    throw new RuntimeException("UnsupportedEncodingException");
                }
            }
        });
        messageListenerAdapter.setDefaultListenerMethod("receive"); //the method in our Receiver class
        return messageListenerAdapter;
    }

    @Bean
    Receiver receiver() {
        return new Receiver();
    }

Мы определили очередь и связываем с сервисом обмена 'logstash', чтобы принять сообщения с ключем маршрутизации 'my_app'. MessageListenerAdapter выше определяет, что метод 'receive' должен быть вызван на бине Receiver каждый раз, когда новое сообщение приходит из очереди.


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


public class Receiver {  
    private PublishSubject publishSubject = PublishSubject.create();

    public Receiver() {
    }

    /**
     * Method invoked by Spring whenever a new message arrives
     * @param message amqp message
     */
    public void receive(Object message) {
        log.info("Received remote message {}", message);
        JsonElement remoteJsonElement = gson.fromJson ((String) message, JsonElement.class);
        JsonObject jsonObj = remoteJsonElement.getAsJsonObject();

        publishSubject.onNext(jsonObj);
    }

    public PublishSubject getPublishSubject() {
        return publishSubject;
    }
}

Мы должны знать, что событие SimpleMessageListenerContainer поддерживает наличие более одного потока, который потребляет из очереди (и пропускает события вниз по цепочки). Однако контракт Observable говорит, что мы не можем выделять события конкурентно (вызовы onNext,onComplete, onError должны быть сериализованы):


// ТАК ДЕЛАТЬ НЕ НАДО
Observable.create(s -> {  
                    // Thread A
                    new Thread(() -> {
                        s.onNext("one");
                        s.onNext("two");
                    }).start();

                    // Thread B
                    new Thread(() -> {
                        s.onNext("three");
                        s.onNext("four");
                    }).start();
                });
// ТАК ДЕЛАТЬ НЕ НАДО

//ДЕЛАЙТЕ ТАК
Observable obs1 = Observable.create(s -> {  
                    // Thread A
                    new Thread(() -> {
                        s.onNext("one");
                        s.onNext("two");
                    }).start();
                  });

Observable obs2 = Observable.create(s -> {  
                    // Thread B
                    new Thread(() -> {
                        s.onNext("three");
                        s.onNext("four");
                    }).start();
                });

Observable c = Observable.merge(obs1, obs2); 

Мы можем обойти эту проблему вызывая Observable.serialize() или Subject.toSerialized(), но мы остаемся со значение по умолчанию 1 Thread в ListenerContainer, нет необходимости делать это. Еще вы должны быть в курсе того, что если вы планируете использовать Subjects как шину событий, распространяющихся на несколько потоков. Прочитайте подробное объяснение.


А сейчас вы можете взглянуть на код и репозиторий, как продолжение этого длинного поста Part II (Части 2) или перейдите на Rx Playground там вы найдете больше примеров.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329894/


Метки:  

Microsoft внедрит ДНК-хранилище в одном из своих ЦОД

Среда, 31 Мая 2017 г. 13:46 + в цитатник
В прошлом году компания Microsoft рассказала о своих исследованиях, посвященных разработке ДНК-хранилищ. Ученые заявили, что их технология позволит хранить данные дата-центра в нескольких кубах сахара. И вот на прошлой неделе сотрудник Microsoft Research Даг Кармин (Doug Carmean) сказал, что компания планирует внедрить в одном из своих ЦОД устройство хранения на основе ДНК к 2020 году.

/ фото igemhq CC

Над новым проектом работает исследовательское подразделение компании Microsoft Research, ученым из которого удалось записать на искусственные спирали ДНК 200 мегабайт данных. В молекулы дезоксирибонуклеиновой кислоты записали музыкальный клип в высоком разрешении, Всеобщую декларацию прав человека, переведенную на 100 языков и первые сто книг в списке проекта «Гутенберг».

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




Сначала единицы и нули двоичного кода переводятся в комбинации нуклеотидов — аденин, гуанин, цитозин и тимин. Затем, выполняется синтез искусственной ДНК со всеми этими данными. Для определения конца и начала записываемых файлов в молекулу ДНК вводятся специальные маркеры. Из электронной версии сформированной последовательности компания-подрядчик Twist Bioscience синтезирует фрагменты ДНК длиной в 150 нуклеотидов каждый. Всего для записи понадобилось порядка 1,5 млрд азотистых оснований.

Даг Кармин говорит, что разрабатываемая ими система будет сопоставима по размерам с крупными копировальными аппаратами от Xerox 70-х годов прошлого века. Скорость записи данных пока что составляет всего 400 байт в секунду. Для считывания данных с ДНК используются секвенаторы.

Сейчас массовому внедрению систем хранения данных на основе ДНК препятствуют дороговизна технологии и низкие скорости чтения/записи информации. В Microsoft считают, что для успешного коммерческого внедрения решения необходимо удешевить его в 10 тыс. раз и увеличить скорость записи до 100 мегабайт в секунду.

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

P.S. Другие материалы из Первого блога о корпоративном IaaS:

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329400/


Метки:  

Пятое поколение СХД HPE MSA: удвоенная производительность за ту же цену

Среда, 31 Мая 2017 г. 13:42 + в цитатник
С момента запуска линейки СХД начального уровня HPE MSA в мире уже было развернуто более 500 000 массивов. И уже 8 лет подряд продукты HPE MSA остаются ведущими СХД начального уровня на основе Fibre Channel. Новое поколение MSA, выход которого компания объявила в мае, предлагают вдвое больше производительности – и это за такую же цену, что и предыдущее поколение систем!

HPE MSA: решения для хранения данных, масштабируемые по мере роста компании


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

Семейство продуктов HPE MSA включает в себя СХД начального уровня, которые обеспечивают оптимальную производительность, используя флеш-память для ускорения обработки рабочих нагрузок. Эти платформы обладают встроенной технологией динамического распределения данных по уровням (tiering), которая значительно повышает производительность бизнес-приложений. Системы MSA интегрируются с наиболее популярными гипервизорами для консолидации рабочих нагрузок и сокращения расходов на инфраструктуру ИТ. Расширенные функции программного обеспечения помогают повысить производительность среды хранения данных предприятия и обеспечивают бесперебойную работу бизнес-процессов.

Представляем пятое поколение систем MSA


Новая гибридная система MSA 2052 со встроенными накопителями флеш и базовая модель MSA 2050 (готовая к работе с флеш) предназначены для обеспечения высокой доступности данных приложений. Подключение к хосту осуществляется по протоколам FC, iSCSI и SAS. Кроме того, решения MSA 2050/2052 обладают средствами репликации данных и могут применяться для организации работы удаленных офисов и филиалов. Они просты в установке, управлении и обслуживании.

Расширенные опции HPE для управления данными (в том числе автоматическое распределение данных по уровням, динамическое выделение ресурсов, удаленная репликация и др.) помогают системным администраторам адресовать рост рабочих нагрузок и обеспечить высокую производительность всей инфраструктуры. Массив не требует глубокой настройки и специальных навыков администратора.

Конструкция и архитектура систем MSA пятого поколения


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

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

Системы MSA 2050 и 2052 используют одинаковые контроллеры. Различия связаны с дополнительными опциями. MSA 2052 поставляется с двумя SSD объемом 800 ГБ, лицензией на Advanced Data Services и 512 мгновенных снимков. MSA 2050 поставляется без SSD, но с пакетом Advanced Data Services, за исключением автоматического распределения по уровням производительности (performance tiering). Лицензию на расширенное количество мгновенных снимков также можно докупить за номинальную стоимость.

Новые контроллеры поддерживают работу с существующими моделями дисков 12Gb. Благодаря этому возможно модернизировать системы MSA 2040/2042 путем простой замены контроллеров. Данные приложений при этом остаются доступными.

15 июня мы проведем вебинар, на котором подробно рассмотрим новинки и сможем ответить на ваши вопросы. Регистрация по ссылке.

А пока предлагаем посмотреть обзор ChalkTalk (внизу, на английском) о возможностях MSA нового поколения.




Материалы:
1. Driving Simplicity and Performance with a New Generation of HPE MSA Storage (блог Тима Питерса, вице-президента и главного руководителя по серверам HPE ProLiant и решениям для малого и среднего бизнеса)
2. HPE and Nimble Storage News Ahead of Discover (блог Кэлвина Зито, HPE Storage)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329874/


Метки:  

Сравнение Эльбрус-4С и Эльбрус-8С в нескольких задачах машинного зрения

Среда, 31 Мая 2017 г. 13:05 + в цитатник

Реалистичный Realm. 1 год опыта

Среда, 31 Мая 2017 г. 13:01 + в цитатник

Realm давно известен в среде мобильных (и не только) разработчиков. К сожалению, в рунете почти нет статей об этой базе данных. Давайте исправим эту ситуацию.

Ровно год назад в build.gradle нашего проекта появилась строчка:

classpath "io.realm:realm-gradle-plugin:0.89.1" 

За этот год код Realm вырос до версии 3.3, обзавелся множеством фич и починил кучу багов, реализовал новый функционал и получил облачный бекенд. Давайте поподробнее поговорим о Realm в реалиях Andoroid разработки и обсудим тонкие моменты, возникающие при его использовании.



О нас


Мы разрабатываем приложение для коммуникации внутри команды, что-то среднее между telegram и slack. Android приложение написано на Kotlin, с самого начала использовался подход offline-first, т.е. когда все данные, отображенные на экране, достаются из кэша. Попробовав несколько разных баз данных, мы остановились на Realm и в течении года активно использовали его. Данная статья выросла из внутреннего документа по использованию Realm. Статья не является переводом документации и не претендует на полноту описания, это скорее сборник рецептов и разбор тонких моментов. Для полного понимания строго рекомендуем прочитать официальную документацию. Мы же расскажем о своем опыте и какие шишки набили за этот год. Весь код для статьи написан на Kotlin, найти его вы можете на Github.

Realm как стартап


Если говорить о Realm как о компании, то это датский стартап основанный в 2011 году. Ранее проект назывался tight.db. За время существования привлечено 29M$ инвестиций. Зарабатывать компания планирует на основе Realm Mobile Platform, сама же база данных бесплатная и опенсорсная. Realm под Android появился в 2014 году и с тех пор постоянно развивается. Некоторые апдейты ломают обратную совместимость, однако фиксы можно сделать достаточно легко и быстро.

Realm как база данных


Realm — это база данных для нескольких платформ. О себе они пишут:
The Realm Mobile Platform is a next-generation data layer for applications. Realm is reactive, concurrent, and lightweight, allowing you to work with live, native objects.

Если кратко, то это нативная no-sql база данных для Android (Java, Kotlin), iOS (Objective-C, Swift), Xamarin (C#) и JavaScript (React Native, Node.js).
Так же есть backend, который позволяет синхронизировать данные из всех источников.

Из ключевых особенностей стоит отметить zero copy, MVCC и ACID. Встроенного механизма устаревания и очистки данных нет.

У Realm есть очень хорошая документация и множество примеров на github.
Сотрудники Realm периодически мониторят StackOverflow, также можно завести issue на github.

Hello world


Hello world под Android выглядит следующим образом:

Добавим в build.gradle

build.gradle (Project level) 

classpath "io.realm:realm-gradle-plugin:3.3.0"

build.gradle (App level) 

apply plugin: 'realm-android'

В Application настроим Realm Configuration

Realm.init(this)
val config = RealmConfiguration.Builder()
       .build()
Realm.setDefaultConfiguration(config)

И можно начинать работать с базой данных:

val realm = Realm.getDefaultInstance()

realm.executeTransaction { realm ->
   val dataObject = realm.createObject(DataObject::class.java)
   dataObject.name = "A"
   dataObject.id = 1
}

val dataObject = realm.where(DataObject::class.java).equalTo("id", 1).findFirst()
dataObject.name // => A

realm.executeTransaction { realm ->
   val dataObjectTransaction = realm.where(DataObject::class.java).equalTo("id", 1).findFirst()
   dataObjectTransaction.name = "B"
}
dataObject.name // => B

Сравнение с другими базами данных


На хабре есть статья от 8 апреля 2016 года, где сравниваются 9 ORM под Android, в том числе Realm. Realm там в лидерах, вот графики:

Сравнение с другими ORM
image

image


На своем сайте Realm приводит следующую статистику:

Графики с сайта Realm



Можно выделить три главные особенности, которые необходимо учитывать:
Live Objects — Все объекты, полученные из Realm, являются, по сути, прокси к базе данных. За счет этого достигается zero copy (объекты не копируются из базы)
Transactions — Все изменения привязанных объектов данных нужно проводить внутри транзакции
Open\Close — Необходимость открытия\закрытия instance базы данных

Live Objects


Все объекты из Realm можно получить синхронно или асинхронно.

Синхронное чтение


fun getFirstObject(realm: Realm, id: Long): DataObject? {
   return realm.where(DataObject::class.java).equalTo("id", id).findFirst()
}

Вызываем метод Realm и блокируем поток, пока не получим объект или null. Использовать объекты, полученные в других потоках, нельзя, поэтому для использования в главном потоке, нужно блокировать ui или использовать асинхронные запросы. К счастью, Realm предоставляет нам прокси, а не сам объект, поэтому все происходит достаточно быстро. С объектом можно работать сразу после получения.

Асинхронное чтение


Весьма неочевидный кейс. Как вы думаете, что произойдет в этом коде:

val firstObject = realm.where(DataObject::class.java).findFirstAsync()
log(firstObject.id)

Правильный ответ: получим ошибку java.lang.IllegalStateException
При асинхронном чтении мы хоть и получаем объект сразу, но работать с ним не можем, пока он не загрузится. Проверять это нужно с помощью функции isLoaded() или вызвать блокирующую функцию load(). Выглядит достаточно неудобно, поэтому тут лучше использовать rx. Преобразуем в observable и получаем загруженный объект в OnNext. Асинхронные операции доступны только в потоках с Looper.

fun getObjectObservable(realm: Realm, id: Long): Observable {
   return realm.where(DataObject::class.java).findFirstAsync().asObservable()
}

Основные особенности Realm объектов


  • Получение объектов из базы очень быстрое, десериализации как таковой нет, чтение с диска происходит только при обращении к конкретному полю
  • Именно для этого существует требование делать все поля приватными и обращаться через геттеры
  • Метод copyFromRealm() — позволяет получать отвязанные, полностью собранные объекты, прямо как обычная ORM. Правда и все фишки Realm становятся недоступны. На вход принимается глубина десериализации, по умолчанию MAX_INT
  • В дебагере все поля будут null. Для получения какого-либо значения нам нужно обращаться через геттер
  • Все объекты Live, т.е живые. Изменения распространяются моментально в рамках одного потока. Более сложные кейсы смотрите ниже (многопоточность).
  • Фильтрация объектов осуществляется по полям, причем названия полей вы указываете руками в виде строки. Например так: .equalTo(«id», 1). Это усложняет рефакторинг и приводит к ошибкам в наименовании полей для фильтрации. К сожалению Realm не генерирует переменные с названиями полей, поэтому все выборки лучше прятать внутри функции:

    fun findFirstDataObject(id: Long, realm: Realm) : DataObject
           =  realm.where(DataObject::class.java).equalTo("id", id).findFirst() 

    или использовать генератор имен полей от cmelchior
  • Этот пункт изменился прямо во время написания статьи (яркий пример того, как развивается проект)
    Было: Невозможно использовать DiffUtil при изменении объекта, невозможно понять какие поля у объекта изменились. Т.е. если вам пришла нотификация об изменении объекта, невозможно понять что у него изменилось. Связано это с тем, что оба объекта (старый и новый) являются live объектами и ссылаются на одни и те же данные, они всегда будут равны.
    Стало: Можно использовать RealmObjectChangeListener для понимания что изменилось:
    RealmObjectChangeListener
    Person p = realm.where(Person.class).findFirst();
                p.addChangeListener(new RealmObjectChangeListener() {
                    @Override
                    public void onChange(Person person, ObjectChangeSet changeSet) {
                        if (changeSet.isDeleted()) {
                            hide(); // Object was deleted
                        } else {
                            // Use information about which fields changed to only update part of the UI
                            if (changeSet.isFieldChanged("name")) {
                                updateName(person.getName());
                            }
                        }
                    }
                });
     

  • Любой объект доступен только пока открыт instance realm-a, из которого мы его получили. Проверять можно методами isValid. При обращении к невалидному объекту получим исключение
  • Объекты доступны только в том потоке, в котором созданы. Обращаться из другого потока нельзя, получим исключение

Аналогично списки (RealmResult) объектов (результаты запроса) являются прокси к Realm, это приводит к следующему:

  • Получение списков очень быстрое, по сути мы получаем только count. Все запросы lazy, получить большой список из сложных объектов мы можем очень быстро
  • Списки доступны только для чтения, любые методы изменения приводят к исключению
  • Т.к. мы можем быстро и дешево получать все элементы, можно забыть о проблеме пагинации. Мы всегда отдаем полный список элементов, при скролле обращаемся к объектам, и они быстро получаются из базы. Если нам нужно подгрузить данные, мы запускаем загрузку, получаем данные, сохраняем их в Realm, снова получаем полный список с загруженными элементами и отображаем его
  • До недавнего времени (до версии 3.0) была проблема с перерисовкой всех элементов списка. Если мы используем список для адаптера, то при изменении одного элемента происходит полная перерисовка всего списка. Использовать DiffUtils и сравнивать какие объекты изменились, не получится, т.к. это live объекты. В Realm 3.0 появились OrderedCollectionChangeSet, который сообщает нам DeletionRanges, InsertionRange, ChangeRanges. Стало наконец возможно понять какие объекты и как изменились.

    Пример CollectionChangeListener
    
    private final OrderedRealmCollectionChangeListener> changeListener = new OrderedRealmCollectionChangeListener() {
        @Override
        public void onChange(RealmResults collection, OrderedCollectionChangeSet changeSet) {
            // `null`  means the async query returns the first time.
            if (changeSet == null) {
                notifyDataSetChanged();
                return;
            }
            // For deletions, the adapter has to be notified in reverse order.
            OrderedCollectionChangeSet.Range[] deletions = changeSet.getDeletionRanges();
            for (int i = deletions.length - 1; i >= 0; i--) {
                OrderedCollectionChangeSet.Range range = deletions[i];
                notifyItemRangeRemoved(range.startIndex, range.length);
            }
    
            OrderedCollectionChangeSet.Range[] insertions = changeSet.getInsertionRanges();
            for (OrderedCollectionChangeSet.Range range : insertions) {
                notifyItemRangeInserted(range.startIndex, range.length);
            }
    
            OrderedCollectionChangeSet.Range[] modifications = changeSet.getChangeRanges();
            for (OrderedCollectionChangeSet.Range range : modifications) {
                notifyItemRangeChanged(range.startIndex, range.length);
            }
        }
    };
    


Транзакции


Изменять привязанные к Realm объекты можно только внутри транзакции, при изменении вне транзакции получим ошибку. С одной стороны, не очень удобно, с другой стороны — дисциплинирует и не дает изменять объекты в любой части кода, только в определенном слое (database). Также нужно помнить, что транзакции внутри другой транзакции запрещены.

Как нельзя делать:

val user = database.getUser(1)
button.setOnClickListener { user.name = "Test" }

Как можно:

val user = database.getUser(1)
button.setOnClickListener { database.setUserName(user, "Test") }

Транзакции можно производить синхронно и асинхронно. Давайте подробнее рассмотрим каждый из вариантов:

Синхронные транзакции:


fun syncTransaction() {
   Realm.getDefaultInstance().use {
       it.executeTransaction {
           val dataObject = DataObject()
           it.insertOrUpdate(dataObject)
       }
   }
}

Также можно выполнять транзакции между beginTransaction и commitTransaction, однако рекомендуется использовать именно executeTransaction.

К сожалению, синхронные транзакции не поддерживают onError callback, так что обработка ошибок остается на вашей совести. Есть issue на добавление onError callback c июня 2016 года.

Асинхронные транзакции


Асинхронные транзакции запускаются методом asyncTransaction. На вход отдаем саму transaction и callback onSuccess и onError, на выходе получаем объект RealmAsyncTask, с помощью которого мы можем проверить статус или отменить транзакцию. Асинхронные транзакции запускаются только в тредах с Looper. Пример асинхронной транзакции:

Realm.getDefaultInstance().use {
   it.executeTransactionAsync({
       it.insertOrUpdate(DataObject(0))
   }, {
       log("OnSuccess")
   }, {
       log("onError")
       it.printStackTrace()
   })
}

Пара важных нюансов:

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

val realm = Realm.getDefaultInstance()
val parent = realm.where(Parent::class.java).findFirst()
val children = Children()
// parent.setChildren(children) <-- Error
val childrenRealm = realm.copyToRealmOrUpdate(children)
parent.setChildren(childrenRealm) /// Ok

Много транзакций лучше объединять в одну. В Realm есть внутренняя очередь на транзакции (размером 100) и если вы превысите ее, упадет исключение.

Все асинхронные транзакции работают на одном executor’e

// Thread pool for all async operations (Query & transaction)
static final RealmThreadPoolExecutor asyncTaskExecutor = RealmThreadPoolExecutor.newDefaultExecutor();

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

Open/close realm


Все объекты из базы данных мы получаем, используя конкретный instance Realm-a, и можем работать с ними пока открыт этот instance. Как только мы вызовем realm.close(), любая попытка чтения объекта обернется для нас исключением. Если мы не будем вовремя закрывать Realm, то это приведет к утечкам памяти, т.к. сборщик мусора не умеет корректно работать с ресурсами, используемыми Realm.

В официальной документации рекомендуется открывать\закрывать Realm:

  • для Activity: onCreate / onDestroy
  • для Fragment: onCreateView/onDestroyView

Однако если вы хотите вынести логику работы с Realm из Activity\Fragments в презентеры, вам придется использовать (прокидывать) методы жизненного цикла.

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

Realm.getDefaultInstance().use { // it = realm instance}

Для чтение объектов с помощью Rx можно использовать “изолированные” instance и закрывать их в doOnUnsubscribe (или использовать Observable.using)

// Use doOnUnsubscribe 
val realm = Realm.getDefaultInstance()
realm.where(DataObject::class.java).findAllSorted("id").asObservable().doOnUnsubscribe { realm.close() }

// Use Observable.using
Observable.using(Realm.getDefaultInstance(), realm -> realm.where(DataObject::class.java).equalTo("id", id)
       .findFirstAsync()
       .asObservable()
       .filter(realmObject -> realmObject.isLoaded())
       .cast(DataObject::class.java), Realm::close);

Также есть особенность, связанная с закрытием Realm в onDestroy\onDestroyView. Иногда после закрытия Realm происходит вызов FragmentManagerImpl.moveToState -> ViewGroup.removeView ->… -> RecyclerViewAdapter.getItemCount() и вызывается метод list.size() от невалидной коллекции. Так что тут нужно проверять isValid() или отвязывать adapter от recyclerView

Если вы используете Kotlin Android Extensions, то работать с view (из kotlinx.android.synthetic.*) из Fragment можно только начиная с метода onViewCreated(), лучше настраивать все listeners в этом методе, чтобы не получить NPE.

После разбора трех самых важных особенностей, пробежимся по менее важным:

Notifications, RxJava


Realm поддерживает уведомления об изменении данных, причем как самого объекта, так и вложенных объектов (всех залинкованных объектов). Реализовано это с помощью RealmChangeListener (нам приходит сам объект), RealmObjectChangeListener ( приходит измененный объект и ObjectChangeSet для него, можно понять какие поля изменились) или с помощью RxJava (в onNext получаем объект, в случае асинхронного запроса необходимо проверять isLoaded(), работает только в потоках с Looper).

RxJava2 пока не завезли, issue висит с сентября 2016 года, когда реализуют — неизвестно, используйте Interop.

Аналогично можно слушать изменения коллекций или всего instance Realm. Слушать изменения внутри транзакций запрещено.

Пример Rx:

fun getObjectObservable(realm: Realm, id: Long): Observable {
   return realm.where(DataObject::class.java).equalTo("id", id).findFirstAsync()
           .asObservable().filter({ it?.isLoaded }).filter { it?.isValid }
}

Многопоточность и асинхронность


Realm это MVCC база данных. Википедия говорит про MVCC:
“Управление параллельным доступом с помощью многоверсионности (англ. MVCC — MultiVersion Concurrency Control) — один из механизмов обеспечения параллельного доступа к БД, заключающийся в предоставлении каждому пользователю так называемого «снимка» БД, обладающего тем свойством, что вносимые пользователем изменения в БД невидимы другим пользователям до момента фиксации транзакции. Этот способ управления позволяет добиться того, что пишущие транзакции не блокируют читающих, и читающие транзакции не блокируют пишущих.”

На практике это выглядит следующим образом: мы можем слушать изменения объекта или с помощью RxJava получать измененные объекты в onNext. В случае, если изменения происходят в потоке А, а мы работаем с объектом в потоке B, то поток B узнает об изменениях после закрытия Realm instance в потоке A. Изменения передаются посредством Looper. Если в потоке B Looper-a нет, то изменения не дойдут (можно проверить методом isAutoRefresh()). Выход из данной ситуации — использовать метод waitForChange().

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

  • Нельзя смешивать асинхронные транзакции и синхронные, если смешать, все транзакции станут синхронными
  • Нельзя использовать асинхронные вызовы в потоках без Looper
  • Для длительных транзакций нужно открыть отдельный instance realm, иначе realm может быть закрыт во время транзакции и вы получите исключение
  • Все действия в асинхронной транзакции происходят на отдельном внутреннем executor-е, как следствие вы не можете пользоваться внешними realm объектами, возможно переполнение executor-а, изменения realm object не распространяются между потоками и прочие неудобства

Тестирование


Раньше Realm.java — был final и для тестирования нужен был powerMock или другие подобные инструменты. В данный момент Realm.java перестал быть final и можно спокойно использовать обычный mockito. Примеры тестов в демо проекте или на официальном репозитории

Один Realm хорошо, а три лучше


Работая с Realm мы всегда имеем ввиду стандартный realm, однако существуют еще In-Memory Realm и Dynamic Realm.

Стандартный Realm — можно получить методами Realm.getDefaultInstance() или с помощью конкретной конфигурации Realm.getInstance(config), конфигураций может быть неограниченное количество, это по сути отдельные базы данных.

In-Memory Realm — это Realm, который все записанные данные хранит в памяти, не записывая их на диск. Как только мы закроем этот instance, все данные пропадут. Подходит для кратковременного хранения данных.

Dynamic Realm — используется в основном при миграции, позволяет работать с realm — объектами без использования сгенерированных классов RealmObject, доступ осуществляется по именам полей.

Наследование и полиморфизм


Realm не поддерживает наследование. Любой realm-объект должен или наследоваться от RealmObject или реализовывать интерфейс маркер RealmModel и быть помеченным аннотацией @RealmClass. Наследоваться от существующих Realm объектов нельзя. Рекомендуется использовать композицию вместо наследования. Весьма серьезная проблема, issue висит с января 2015 года, но воз и ныне там.

Kotlin


Realm из коробки работает c Kotlin.
Не работают data class-ы, нужно использовать обычные open class.
Также стоит отметить Kotlin-Realm-Extensions, удобные расширения для работы с RealmObject.

Realm mobile platform


Первое время Realm был представлен только базами данных для разных платформ, сейчас они выкатили сервер для синхронизации между всеми устройствами. Теперь платформа состоит из:
  • Realm Mobile Database – база для хранения данных
  • Realm Object Server – сервер, отвечающий за автоматическую синхронизацию и обработку событий
  • Realm Data Integration API – для подключения и синхронизации данных с существующими БД (Oracle, MongoDB, Hadoop, SAP HANA, Postgres и Redis)

Иллюстрация работы mobile platform


Отладка


Для отладки у нас есть несколько инструментов:

  • RealmLog — выводит лог, есть разные уровни логирования
  • Realm браузер — нужен просмотра базы данных с компьютера. Работает только под Mac. Для просмотра базы на Windows можно использовать Stetho Realm
    Также существуют несколько Android библиотек для удобного просмотра данных на девайсе.
  • WriteCopyTo() — позволяет скопировать базу в файл и отправить ее на анализ.
  • NDK Debugging — для анализа ошибок в нативном коде можно использовать Crashlytics NDK Crash Reporting

Архитектура


Realm отлично подходит для MV* архитектур, когда вся реализация прячется за интерфейсом базы данных. Все обращения и выборки происходят в модуле базы данных (repository), наверх отдаются Observable c автоматически закрываемым realm при unsubscribe. Или принимаем на вход instance realm и производим все действия с ним. При записи объектов мы открываем realm, записываем данные и закрываем его, на вход подается только объект для сохранения. Оба примера смотрите на github.
Увы, использование Realm (без copyFromRealm) накладывает серьезные ограничения на использование clean architecture. Использовать разные модели данных для разных слоев не получится, пропадает весь смысл live объектов и прокси списков. Также сложности возникнут при создании независимых слоев и открытии\закрытии Realm, тк эта операция привязана к жизненному циклу Activity\Fragment. Хорошим вариантом будет изолированный слой получения данных, преобразование объектов и сохранение их в базе данных.

Realm очень удобен при построении offline-first приложений, когда все данные для отображения мы получаем из базы данных.

Полезные ссылки


Для продолжения знакомства и разбора тонких моментов, рекомендуем следующие статьи:

Три статьи статьи от @Zhuinden:
Basics of Realm: A guide to using Realm 1.2.0
How to use Realm for Android like a champ, and how to tell if you’re doing it wrong
Realm 1.2.0 + Android Data Binding

Две статьи про интеграцию Realm от @Viraj.Tank
Safe-Integration of Realm in Android production code, Part-1 with MVP
Deep integration of Realm in Android production code, Part-2, with MVP

Многопоточность, подробный разбор:
Designing a Database: Realm Threading Deep Dive
Docs — Auto-Refresh
Docs — Threading

Недавняя статья на хабре от FairBear:
Как подружиться с Realm

Заключение


Realm сложнее, чем кажется на первый взгляд. Однако все недостатки с лихвой покрываются его мощностью и удобством. Live объекты, нотфикации и Rx, удобное API и множество других вещей упрощают создание приложений. Из конкурентов можно выделить requery, ObjectBox и GreenDao. Полностью же Realm раскрывает себя при построении offline-first приложений, когда все данные мы получаем из кэша и нам необходимы сложные выборки, а также постоянное обновление данных.
Весь приведенный код вы можете найти на Github
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/328418/


Метки:  

Unit-тесты: что, как и когда тестировать?

Среда, 31 Мая 2017 г. 11:00 + в цитатник
Тестирование программного кода — кропотливый и сложный процесс. Львиную долю работы в нем совершают unit-тесты. Пока они не «загорятся зеленым», тестировать дальше смысла нет.

Как же писать unit-тесты правильно? Стоит ли гнаться за 100% покрытием? С какими сложностями приходится сталкиваться инженерам на практике? Своим опытом делятся Marc Philipp и Всеволод Брекелов.





Marc Philipp – один из основных разработчиков фреймворка JUnit 5 – инструмента для Java-тестировщиков. В данный момент работает в качестве инженера в немецкой компании LogMeIn над облачными SaaS-решениями.

Всеволод Брекелов — Senior QA Engineer в компании Grid Dynamics, более 5 лет занимается тестированием, имеет опыт построения автоматизации тестирования с нуля.  

— В статьях про unit-тестирование в качестве примеров обычно приводят тестирование методов и классов калькулятора. Такие примеры могут показать сложность реальных задач? С чем приходится сталкиваться тестировщику полнофункциональных программ?

Marc Philipp: Действительно, на примерах с калькулятором невозможно показать сложность реальных задач. Они выбраны в статьях для того, чтобы читатели могли сосредоточиться на понимании подходов unit-тестирования без необходимости разбора сложного кода. Хотя эти примеры очень простые, они хорошо демонстрируют основную идею и принципы unit-тестирования. В реальной жизни тестируемый код должен быть изначально написан с учетом того, что по нему будет проводиться Unit-тестирование. Один из способов обеспечить это — писать тесты до написания кода или практически одновременно с ним. Когда у вас есть код, адаптированный к тестированию, написание unit-тестов не на много сложнее, чем для калькулятора.

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

К примеру, по запросу «unit тестирование java» можно быстро найти статью на Хабре. Она опубликована довольно давно, но не потеряла своей актуальности.

Что касается особенностей работы, я бы выделил следующие группы тестировщиков (надеюсь никого не обидеть):

  • Back-end – могут писать системные, интеграционные, компонентные, юнит тесты (почему бы и нет?).
  • Front-end – могут писать как e2e тесты, так и компонентные, так и юнит тесты.
  • DB — занимаются тестированием данных/самой БД.
  • Performance – тут вроде бы очевидно.
  • Infrastructure – занимаются больше вопросами «около-девопсными».  
  • Mobile testing(iOS, Androind, IoT) — сейчас очень модно стало отделять таких инженеров, хотя на мой взгляд это все о том же Back-end/Front-end.


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

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

— Каждый тест должен проверять одну вещь. Насколько полно на практике удается выполнить это условие? Как вы боретесь с зависимостями, какие фреймворки используете?

Marc Philipp:
При написании unit-тестов обычно берется один образец входных данных из класса эквивалентности в тестируемой проблемной области. Конечно, вы должны сначала определить эти самые классы эквивалентности. В каждом тесте вы добавляете assertion только для тех свойств, которые релевантны вашему тесту. Не следует копипастить одни и те же assertions в каждый новый тест и прогонять их. Когда у вас есть зависимости, влияющие на работу юнита, подумайте об использовании стабов или моков, чтобы сохранить независимость теста.

Многие наши юнит-тесты для JUnit 5 используют моки, создаваемые mocking-фреймворком (Mockito в нашем случае). Как я уже говорил выше, они очень полезны для тестирования изолированного кода. Главная задача при этом — убедиться, что ваш мок ведет себя аналогично реальному коду. В противном случае тесты станут бессмысленными.

Всеволод Брекелов: Да, есть мнение: один юнит тест — один assertion. На практике такое я видел очень редко. Думаю, что это уже философия команды. Множественные assertions вполне себе имеют место.

Если мы проводим юнит тесты, а не компонентные, то все зависимости изолируем (моки, стабы — все в ваших руках). Тут нет каких-то сложностей на мой взгляд. А если и появляются, то StackOverflow точно поможет.

Так как я пишу на Java/JavaScript(Angular), то использую обычные популярные тулы:
на Java – Mockito/EasyMock. Для компонентных тестов написать свой responsive mock — тоже хорошая идея! Всем советую.

JavaScript – ngMock. Кстати, для компонентых тестов очень классная тема – AngularPlayground.

— Как найти компромисс между трудовыми и финансовыми затратами на тестирование и качеством итогового софта при реализации «горящих» проектов? Как обычно вы аргументируете важность полноценного тестирования в таких случаях?

Marc Philipp: По моему опыту, вы не можете спасти «горящий» проект, пропустив тесты. Написание unit-тестов является неотъемлемой частью разработки программного обеспечения. Без него у вас нет возможности узнать, действительно ли ваш код выполняет то, что, по вашему мнению, он должен делать. Вы не сможете ничего быстро починить, так как не поймете, где что сломалось. Как сказал UncleBob, «единственный способ быстро поехать — это хорошо идти».

Всеволод Брекелов: Думаю, тут нет однозначного ответа. Скорее, помогает опыт работы и тип проекта. Если вы делаете медицинский проект или строите ракету, то о важности тестирования не приходиться говорить. Если пилите стартап за неделю – то какие тесты?

Очень важно организовать процесс, чтобы избежать внезапных багов и неправильно реализованных требований. Что такое правильный процесс? Конечно, есть Agile Manifesto, на который многие смотрят при организации процесса, но все равно что-то не выходит. Можно взять и построить процесс ради процесса. А можно и наоборот, последовать за http://programming-motherfucker.com/.

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

— Какие приемы помогают сократить время и трудовые затраты на тестирование?

Marc Philipp: «Тестирование» — перегруженный термин. Это может означать что угодно: модульное тестирование, ручное тестирование, тестирование производительности… По моему опыту, ручное тестирование, то есть ручное выполнение плана пошагового прохождения тестовых примеров, действительно дорого и часто не так эффективно, как вы думаете. Более того, автоматизация этих скучных тестов имеет смысл только в определенной степени. Тем не менее, вы должны действительно следовать тестовой пирамиде, а не писать слишком много этих end-to-end/UI тестов. Большинство ваших тестов должны быть реальными unit-тестами: независимые, быстрые тесты, которые вы можете выполнять очень часто. Написание этих тестов относительно дешево, особенно если вы знаете свои инструменты. Они очень надежны, поэтому вы не будете тратить время на их актуализацию. UI и Integration тесты всегда будут более хрупкими из-за огромного количества задействованных компонентов.

Всеволод Брекелов: Есть хороший прием — писать меньше кода.

Главное – это понимание процесса и того, что вы хотите решить (или протестировать).
Всегда нужно адекватно оценивать бюджет и время. Что это значит? Если вы можете себе позволить вливать кучу денег в приближение к 100% coverage — why not? Хозяин – барин.

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

Если не впадать в крайности, то самая частая ошибка — это написание e2e тестов пачками до потери пульса до того, как написаны юнит тесты, компонентные тесты, интеграционные тесты на Backend, Frontend, DB, Performance и тд. Эта тенденция, вероятно, следует от модных BDD подходов (я их не очень люблю). К чему это все приводит?

Первая степень «опьянения» — у вас начинает реально работать автоматизация. Ручные тест кейсы вы заменяете на автоматические. Тестировщики начинают радоваться. Менеджеры начинают думать, что вот-вот сэкономят.

Вторая степень — тестов становится много, почему-то некоторые из них периодически падают. Тестировщики уже не очень рады. Нужно сидеть и разбираться в причинах. А баги все равно пролезают. И, вероятно, даже находятся на QA окружении путем ручного (может, даже monkey) тестирования.

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

Четвертая степень — строить целые суперархитектуры по запуску 500 e2e тестов на 50 агентах, чтобы все летало быстро, аж за 10 минут (я тут утрирую, конечно). И все равно баги есть.

Пятая степень — я назову ее недостижимой. Приходит осознание того, что бОльшая часть e2e тестов не нужна. Нужны другие тесты, которых никто никогда не писал. Например, компонентные тесты на back-end или они же на UI. А может, не они, может, системные тесты? А может, и тесты на верстку? А может, Ваш, {username} вариант?

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

— Как влияет на инструменты и подходы тестировщиков развитие средств разработки и подходов к созданию кода? Что из новшеств облегчает
unit-тестирование (например, представление методов в виде лямбда-функций)?


Marc Philipp: Новые инструменты стараются облегчить жизнь разработчикам, предоставляя им большую гибкость. Однако, в конце концов, я считаю, что не имеет значения, представляете ли вы свои тесты как методы или в виде лямбда-функций. Понять, что тестировать и как тестировать, — это самая сложная часть.

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

Что облегчает тестирование — странный вопрос. Думаю, что технологии не могут сильно облегчить жизнь. Так как, чтобы использовать что-то новое (технология, инструмент), его нужно изучить всей команде, принять какую-ту «полиси», code style. Это в перспективе может, конечно, облегчить жизнь, но на коротких дистанциях не очень полезно, так как трудозатратно, имхо.

Кстати, вариант перехода на Kotlin (если мы говорим про Java тесты) – может и неплохая идея. Я в своей практике пока не пробовал.

Касательно новшеств языка (лямбды и прочие полезности) — это все хорошо, конечно, но мне трудно сказать, насколько они облегчают жизнь, так как нужно это измерить. Я не измерял. Но только не записывайте меня в противники прогресса, я считаю, что практика по изучению/использованию чего-то нового должна присутствовать всегда. Это обычная continuos improvement история.

— Насколько вы покрываете unit-тестами ваши продакшн проекты? Стоит ли тратить время на 100% покрытие?

Marc Philipp:
В зависимости от языка программирования и фреймворков, которые вы используете, в проекте может быть некоторый шаблонный код, который не содержит никакой логики. Но кроме таких кусков, на мой взгляд, вы должны написать unit-тесты для всего вашего кода. Таким образом, я бы посоветовал охват более 90%.

Всеволод Брекелов: В проектах, в которых мне приходилось работать, чаще всего разработчики стараются довести тесты до покрытия в 90%. Стоит ли тратить время – обычно решается менеджерами. Я не менеджер, но по мне юнит тесты – это очень хорошая практика, 100% покрытие хорошо иметь, когда есть на это ресурсы.

Главное, надо помнить, что 100% покрытие, к сожалению, не гарантирует, что у вас нет багов.

Из того, что кажется более полезным, чем гонка с 90% до 100% coverage, — это написание мутационных тестов. Ничего не скажу нового относительно статьи 2012 года. Но на практике не очень часто видел, чтобы применяли этот подход (да и сам я тоже, каюсь). Так может быть пора начинать?

— Как тестовые фреймворки помогают с unit-тестами? Какую часть работ они берут на себя? Чего не стоит ждать при использовании фреймфорков?

Marc Philipp: Хороший фреймворк позволяет очень быстро и легко писать простые unit-тесты и в то же время содержать мощные механизмы для проведения более сложных тестов. Например, он должен помочь вам подготовить тестовые данные и предоставить точки расширения, которые позволят вам повторно использовать одну и ту же логику во многих тестах. Но никакой фреймворк не решит за вас, что и как тестировать. Также он не может волшебным образом улучшить ваш проект, чтобы сделать его хорошо тестируемым.

— Какие элементы кода сложнее всего поддаются unit-тестированию? Как решается эта проблема у вас?

Всеволод Брекелов:
Чем больше зависимостей — тем больше рутины, тем сложнее писать юнит тест. А в целом, не вижу каких-то особенных проблем, если честно. Хотя на тему unit тестов написано большое количество книг, из которых я ни одну не прочитал до конца. Может, поэтому я не обременен проблемами.

Например, сложно написать unit-тест, когда, скажем, конструктор объекта содержит в себе вермишели кода, но тогда можно советовать товарищам прочитать книжки, например
https://www.amazon.com/Effective-Java-2nd-Joshua-Bloch/dp/0321356683 и ввести code review практику.

Что касается JavaScript кода, то там можно встретиться с различными сложностями и внезапностями (да, я очень люблю JavaScript), скорее связанными с используемым фреймворком, например, работа с digest’ом. Я использовал только AngularJS/Angular2/Angular4. Несмотря на старания команды Angular сделать удобно-тестируемый фреймворк, все равно периодически сталкиваешься с проблемами, которые безусловно имеют решения, мы ведь инженеры.



Огромный массив информации о всех аспектах тестирования ждет участников на ближайшем Гейзенбаге, где Mark Phillip прочтет доклад «JUnit 5 — The New Testing Framework for Java and Platform for the JVM».

О том, какие еще знаковые фигуры выступят на конференции и смогут ответить на самые актуальные вопросы в кулуарах, можно узнать на сайте.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329372/


Метки:  

Чип для умных камер ELISE — одно из самых высокотехнологичных изделий России 2017 года. Плата для разработчиков и камера

Среда, 31 Мая 2017 г. 10:11 + в цитатник
У каждой российской микроэлектронной компании есть рассказ, почему она самая хорошая и передовая. По английски это называется «claim to fame» — «заявка на славу». Одни российские компании славятся оригинальной архитектурой CPU, другие — спроектированной в России системой на кристалле, третьи — спроектированными в России блоками, которые были лицензированы западными компаниями.

У российской компании ЭЛВИС (ELVEES), которая исторически специализировалась на космической электронике, DSP и хардверно-поддерживаемом распознавании образов, текущая «заявка на славу» выражена в совместном российско-британско-американско-тайваньском чипе для «умных камер» под названием ELISE. Инженеры в подмосковном Зеленограде спроектировали внутри этого чипа важные блоки для видео-обработки и GNSS, которые потом кросс-лицензировала британско-американская Imagination Technologies.

Блоки от элвисовцев интегрированы с тремя разнородными процессорными ядрами: двухядерным кластером суперскалярных ядер MIPS P5607 (Apache) с частотой 1.2 GHz, на котором работает Linux, процессором с аппаратно-поддерживаемой многопоточностью MIPS interAptiv (1 GHz) и небольшим вспомогательным процессором с аппаратно-поддерживаемой виртуализацией MIPS M5150 (Virtuoso).

На днях мне попали в руки два изделия с чипом ELISE — плата для разработчиков и трехмерная бинокулярная камера. Элвисовцы также дали мне список на 10 страниц, что есть на плате, что есть внутри чипа, и какой для этого поддерживается софтвер. К сожалению, они не разрешили мне выложить эти страницы в интернет, поэтому я кое-что перескажу своими словами, а также добавлю инфо про используемые ядра, после чего вы все остальное можете запросить у элвисовцев сами.

На фотографиях ниже некоторые из инженеров-участников проекта. Девушка слева спроектировала часть load-store unit в MIPS P5607, юноша в зеленой майке написал модели интерфейсов шин, а товарищ в клетчатой рубашке — архитектор софтверной экосистемы:



ЭЛВИС выпустил пресс-релиз о чипе ELISE год назад, в мае 2016:



На чипе стоит много разных блоков, включая графический процессор PowerVR Clyde (GX6250) и тяжелый DSP — 8-ядерный VLIW SIMD ELVEES Velcore2, но я расскажу только про ядра обычных процессоров, которых на чипе стоит три разных класса. Зачем вообще нужны разные классы процессоров, вы можете увидеть в слайдах Чарльза, про которого есть пост на Хабре (Разработка -> Можно скачать материалы семинара Nanometer ASIC (РОСНАНО / МИСиС / Imagination Technologies) — ликбез по всему про чипы). Я приведу оттуда один слайд:



Самый производительный процессор общего назначения (application processor) на чипе ELISE — это ядро MIPS P5607 с кодовым названием «Apache». Оно работает на частоте 1.2 GHz и имеет высокий показатель CoreMark. MIPS P5607 — это суперскалярное ядро с внеочередным выполнением инструкций и векторными операциями:



Два ядра MIPS P5600 «Apache» соединяются на элвисовской СнК в двухядерный кластер с общим кэшем второго уровня и менеджером когерентности, который использует MESI протокол для непротиворечивости состояний кэшей первого уровня в ядрах:



Следущим процессором на чипе ELISE является ядро MIPS interAptiv, которое синтезировано на частоте 1 GHz. Это ядро оптимизировано под эффективность (производительность/милливатт). Элвисовцы используют данное ядро для обработки звука. Помимо элвисовцев, похожие ядра любит компания MediaTek, которая использует предыдущую версию той же микроархитектуры в чипе MT7688 для интернета вещей.

У MIPS interAptiv есть интересная черта — аппаратная поддержка многопоточности, которая возникла в предшественника MIPS interAptiv — ядре MIPS 34K. У меня есть пара слайдов про MIPS 34K и вырезка из журнала The Microprocessor Report, которые иллюстрируют идею:







На элвисовском чипе еще есть ядро MIPS M5150 под кодовым названием «Virtuoso». Оно засинтезировано на частоту 600 MHz. Это простое компактное низкопотребляющее ядро с последовательным пятистадийным конвейером. MIPS M5150 в данном СнК используется как контроллер чего-то нетребовательного (housekeeping, «служанка» то бишь):



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



«Заявка на славу» ядра MIPS M5150 — это единственное в мире малое ядро микроконтроллерного класса, которое реализует аппаратную поддержку виртуализации. Зачем? Как я уже писал, виртуализация на таких ядрах удобна для секьюрити. Даже на небольшом чипе для IoT могут одновременно работать скажем встроенный Линукс и скажем очень защищенный код для работы с финансовыми транзакциями. Теперь если пользователь установит взломанную операционную систему, она не сможет получить доступ к другой ОС, выполняющей критические операции, потому что между двумя ОС стоит гипервайзер. Это становится особенно важно в случае интернета вещей, когда подброшенный в домашнюю сеть утюг или тостер может теоретически обмениваться информацией с главным компьютером хозяина.

Подробнее про виртуализацию см. в посте Разработка -> Придумываем название для нового гипервайзера для архитектуры MIPS с аппаратно-поддерживаемой виртуализацией">



Офис ЭЛВИСа находится в подмосковном Зеленограде, в здании в центре снимка ниже, через дорогу от института МИЭТ, из которого ЭЛВИС черпает кадры (а также из МИФИ, МФТИ и других мест). Вы можете запросить от элвисовцев информацию, когда-нибудь получить у них плату и что-нибудь на ней сделать (чтобы сфотографировать плату с девушкой, мне пришлось на время отобрать плату у другого коллеги, который сейчас портирует на плату Андроид. Вы тоже можете на эту плату что-нибудь спортировать или запрограммировать на ней что-нибудь встроенное, графическое и распознавательное, правда я не знаю, когда элвисовцы будут раздавать эти платы широко).

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329864/


UX-стратегия. Часть 6 — Внедрение

Среда, 31 Мая 2017 г. 10:01 + в цитатник
В первых частях этой серии статей я писал о ключевых составляющих UX-стратегии на практике. Получилась модель, описывающая основные уровни зрелости и ключевые зоны приложения усилий, благодаря которым дизайн превратится из исполнителя в стратегического партнёра:

UX-стратегия. Часть 6 — Внедрение

  1. Уровни зрелости дизайна в компании
  2. Роль продуктового дизайнера
  3. Дизайн-система как способ управления качеством интерфейса продукта и скоростью выхода на рынок
  4. Организация работы дизайнеров и построение дизайн-культуры
  5. Целеполагание через аналитику и исследования

Модель зрелости UX. Стратегический уровень

Но мало сказать «хорошо быть здоровым и богатым». Нужен план действий, рассчитанный на долгую перспективу. В начале пути всегда есть огромный список того, что не так в компании и её продуктах. Он и сам по себе фрустрирует — видишь огромное количество болевых точек, каждая из которых вгоняет в тоску. Хочется исправить всё и сразу, но ресурсы могут быть ограничены, а текущие неэффективные процессы и узкое мировоззрение в плане дизайна не дадут решить многие из бед раз и навсегда. Да и ценность любого изменения на текущем этапе развития компании разная — нет смысла заниматься повышением общей дизайн-культуры, если сами дизайнеры работают абы как.

Статья написана для журнала UXmatters.

Редизайн организации


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

Задача дизайн-лидеров — найти этот путь к светлому будущему и провести компанию по нему. Как выглядит системный подход к решению проблем в общем виде:
  1. Описать текущий интерфейсный и организационный долг, которые мешают создавать качественные продукты.
  2. Показать видение будущего — каким вы видите идеальный дизайн продуктов компании и что должно заработать для этого.
  3. Отметить, чему в продукте мешают текущие проблемы и что именно улучшат изменения. Это покажет их ценность для компании и продуктов.
  4. Оценить сложность изменений — что нужно сделать внутри дизайн-команды и в организации в целом, чтобы светлое будущее наступило.
  5. Определить этапы внедрения изменений — первоочередные, средне- и долгосрочные.
  6. Начать включать изменения в общий план работ и отслеживать их свершение и широко рассказывать о позитивных изменениях.

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

Сложно начать идеально


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

Когда я пришёл в Mail.Ru Group в середине 2011 года, мой коллега Алексей Сергеев уже успел доказать топ-менеджменту важность хорошего дизайна. Его усилиями за пару лет появилась первая в подразделении дизайн-команда, началось юзабилити-тестирование, обновились несколько ключевых продуктов. Моей задачей было масштабирование успеха с новой командой, а Алексей ушёл заниматься продуктовой стратегией.

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

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

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

Сейчас в команде 14 человек, отвечающих за примерно 20 продуктов — productivity (Почта, Облако, Календарь, Mail.Ru для бизнеса), медиа-проекты (Авто, Гороскопы, Дети, Добро, Здоровье, Леди, Кино, Медиатор, Недвижимость, Новости, Ответы, Погода, Спорт, ТВ, Hi-Tech, SEOSan), мобильные продукты (Beepcar, Artisto), главная страница и общепортальные правила для Mail.Ru и My.com. По сравнению с тем, что было шесть лет назад это немало, но если посмотреть на количество задач — нагрузка огромная. Именно поэтому мы топим за любые способы автоматизации процесса — дизайн-системы, алгоритмы, убирание ненужных этапов работ и т.п. Ограничения двигают дизайнерскую мысль и мы отлично научились работать с ними.

Мобильные приложения


Мобильные приложения сейчас: Почта My.com и Mail.Ru, Новости, Облако, Гороскопы, Beepcar и другие. Лидеры по загрузкам и рейтингам.
Сейчас: Почта My.com и Mail.Ru, Новости, Облако, Гороскопы, Beepcar и другие. Лидеры по загрузкам и рейтингам

Мобильные приложения раньше: Единое приложение Агента, Почты и Карт для Symbian.
Раньше: единое приложение Агента, Почты и Карт для Symbian

Медиапроекты


Медиапроекты сейчас: Дизайн-система, объединяющая 12 продуктов (остальные на подходе). Единый подход к интерфейсу, новые сервисы.
Сейчас: дизайн-система, объединяющая 12 продуктов (остальные на подходе). Единый подход к интерфейсу, новые сервисы

Медиапроекты раньше: Каждый сам по себе, в не самом современном виде.
Раньше: каждый сам по себе, в не самом современном виде

Мобильный веб


Мобильный веб сейчас: Дизайн-система, объединяющая 14 продуктов. Единый подход к интерфейсу, гарантирующий качество и скорость.
Сейчас: дизайн-система, объединяющая 14 продуктов. Единый подход к интерфейсу, гарантирующий качество и скорость

Мобильный веб раньше: Несколько сервисов в аскетичном виде.
Раньше: несколько сервисов в аскетичном виде

My.com


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

Конечно, ещё не во всех продуктах всё хорошо, а где-то первый редизайн не решил всех проблем, но огромный рывок за прошедшие годы трудно не заметить. У нас сформировалась дизайн-система, на которой работают медиа-проекты, мобильный веб, частично productivity-сервисы (и постепенно подключаются другие продукты), сформировался стиль пиктограмм и иллюстраций, стандартизируются промо-письма и промо-сайты.

Дизайн-система. Начали в 2012 году, с тех пор экономим уйму времени на запуске новых продуктов и функций.
Дизайн-система — начали в 2012 году, с тех пор экономим уйму времени на запуске новых продуктов и функций

Единые иллюстрации. Сочный и современный стиль под кодовым названием «emotional flat 3D» усиливает бренд.
Единые иллюстрации — сочный и современный стиль под кодовым названием «emotional flat 3D» усиливает бренд

Единые пиктограммы. Несколько сотен векторных пиктограмм в едином стиле. Постепенно выкатывается на продукты.
Единые пиктограммы — несколько сотен векторных пиктограмм в едином стиле (постепенно выкатывается на продукты)

Письма рассылки. Единый подход с разделением на три ветки – промо, дайджест и сервисные.
Письма рассылки — единый подход с разделением на три ветки (промо, дайджест и сервисные)

Промо-сайты. Яркие и сочные, хотя очень хочется добавить в них динамики.
Промо-сайты — яркие и сочные, хотя очень хочется добавить в них динамики

А как насчёт...


Злой твит

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

Хотя хочется расстаться с прошлым одним решительным перезапуском, по факту это не всегда возможно и крайне рисково — полно историй необдуманных резких рывков, когда редизайн губил продукт и отталкивал пользователей. Поэтому лучше сначала превратить ад в адекват; из адеквата — сделать что-то современное и трендовое; а после этого уже можно думать о том, как задавать тренды самому. Тем более, что помимо обновления продуктов требуется невидимая снаружи работа по обновлению орг.структуры и производственного процесса — важно просто научиться выдавать хороший результат регулярно, на потоке, а не раз в несколько лет при следующем редизайне. Да, для начала изменений в дизайне зачастую необходима революция, но после этого он развивается эволюционным путём. Этот опыт перестройки процессов и продуктов лёг в основу серии статей о UX-стратегии.

Паттерны дизайн-менеджмента


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

Я собрал чек-лист улучшений, который поможет начать или ускорить изменения в вашей компании. Он основан на нашем пути и наблюдениях за историями изменений в других компаниях. Улучшения будут спускаться от проблем бизнеса к конкретным рецептам для дизайн-менеджеров: ценность для бизнеса -> способ решения -> паттерн. Паттерны привязаны к уровням зрелости (О — оперативный, Т — тактический, С — стратегический).

0. Осознание ценности дизайна


Ценность для бизнеса: Нулевой этап изменений — как показать бизнесу, что дизайн приносит пользу.

Критерии оценки:
  • Доверяют менеджеры. Они приходят с проблемой, а не готовым решением.
  • Доверяют конечные специалисты. Напрямую обращаются за решением рабочих проблем, минуя менеджеров.
  • Задачи приходят заранее, есть время продумать интерфейс.
  • Уменьшается количество итераций по задачам.


Симптомы проблем


Продукт:
  • Слабые или даже вредные дизайн-решения.
  • Разные экраны одного продукта выглядят и работают по-разному.

Организация:
  • Дизайнеры не имеют влияния на продуктовые решения.
  • Дизайнеры привлекаются к задачам в последний момент, «навести марафет».
  • Менеджеры и разработчики сами принимают дизайн-решения.


Способ решения -> паттерн


Донести основы хорошего дизайна:
  • О: Лидер дизайна (часть 4)
  • О: Навыки аргументации, презентации и фасилитации
  • Т: Кредит доверия (часть 1)
  • Т: Карта лиц, принимающих решения
  • С: Ко-дизайн (часть 4)
  • С: Общая дизайн-грамотность (часть 4)
  • С: Адвокат дизайна среди топ-менеджеров

Наглядно показать проблемы:
  • Т: Юзабилити-тестирование, на которое ходит вся продуктовая команда (часть 5)
  • Т: Аналитика и эксперименты (часть 5)

Показать пользу дизайна на практике:
  • О: Быстрые победы (часть 6)
  • Т: Внутренний маркетинг успехов дизайна
  • С: Метрики дизайна, завязанные на бизнес (часть 5)


1. Качество продукта


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

Критерии оценки:
  • Достойное качество продукта в реализации, не только макетах.
  • Лучше отношение пользователей к продукту, что выражается в росте ключевых метрик.
  • Меньше ресурсов на поддержание приемлемого уровня качества.


Симптомы проблем


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

Организация:
  • Разработчики невнимательно реализуют макеты.
  • Дизайн выпускается раньше времени, до проверки качества реализации.
  • Дизайнеры выдают не до конца продуманные или неполные макеты, так что разработчикам приходится самим додумывать (а они не специалисты).


Способ решения -> паттерн


Контроль качества на уровне макетов:
  • О: Ответственность шире, чем просто создание макетов (часть 2)
  • О: T-образные специалисты (часть 2)
  • О: Карта навыков и их развития (часть 4)
  • О: Дизайн-ревью командой (часть 4)
  • О: Общий инструментарий (часть 4)
  • Т: Креативные методики решения проблем (часть 4, 5)

Контроль качества на уровне реализации:
  • Т: Дизайн-система (часть 3)
  • Т: Чек-листы
  • Т: Экспертная оценка с возможность задержать релиз
  • Т: Юзабилити-тестирование (часть 5)
  • Т: Уменьшение интерфейсного долга (часть 6)
  • С: Влияние на продуктовый план (часть 5)
  • С: Повышение общей дизайн-культуры и внимательности разработчиков (часть 4)

Контроль качества на уровне продукта и компании:
  • С: Долгосрочное планирование (часть 4, 6)
  • С: Клуб дизайн-лидеров (часть 4)
  • С: Метрики дизайна, завязанные на бизнес (часть 5)


2. Скорость выхода на рынок


Ценность для бизнеса: Ускорить вывод новых функций и продуктов на рынок при соблюдении приемлемого уровня качества.

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


Симптомы проблем


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

Организация:
  • Непредсказуемое количество итераций по каждой задаче, что затягивает сроки и снижает вовлечённость.
  • Перекладывание ответственности за проблемы на других участников продуктовой команды.
  • Не хватает дизайнеров или у них нет нужных для продукта навыков.


Способ решения -> паттерн


Уменьшение количества итераций:
  • О: T-образные специалисты (часть 2)
  • О: Карта навыков и их развития (часть 4)
  • О: Доверенные аутсорсеры (часть 4)
  • Т: Кредит доверия (часть 1)

Предсказуемость сроков и качества:
  • О: Планирование (краткосрочное и среднесрочное) (часть 4)
  • О: Общий инструментарий (часть 4)
  • С: Дизайн-система (часть 3)
  • С: Планирование (долгосрочное) (часть 4, 6)


3. Снижение рисков при выходе на рынок


Ценность для бизнеса: Повысить шансы на успех при запуске новых продуктов или функций уже существующих.

Критерии оценки:
  • Пользователи видят ценность нового продукта или функции для себя.
  • Пользователи понимают и успешно используют продукт.


Симптомы проблем


Продукт:
  • Продукт плохо принимается пользователями, активность в его использовании меньше ожидаемой.

Организация:
  • Принятие решений о том, каким должен быть продукт, происходит несистемно (слепое копирование конкурентов, паническая реакция на отклонение от ожидаемых значений метрик).
  • Менеджер продукта и команда не знают, насколько хорошо сработали решения.
  • Дизайнеры не имеют влияния на продуктовые решения.


Способ решения -> паттерн


Поиск продуктовых решений с учётом разносторонних требований:
  • Т: Поиск альтернативных решений проблемы (часть 5)
  • С: Ко-дизайн (часть 4)
  • С: Общая дизайн-грамотность (часть 4)

Возможность проверить продуктовую гипотезу на раннем этапе:
  • Т: Ранние прототипы и методы их проверки (часть 5)
  • С: Разведочные пользовательские исследования (часть 5)

Сделать продукт более ценным и понятным:
  • Т: Юзабилити-тестирование (часть 5)
  • Т: Аналитика и эксперименты (часть 5)
  • С: Карта взаимодействия (Customer Journey Map) и оптимизация всех каналов (часть 5)
  • С: Метрики дизайна, завязанные на бизнес (часть 5)


4. Увеличение аудитории и прибыли продукта


Ценность для бизнеса: Повысить ценность продукта для существующих пользователей и привлечь новых.

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


Симптомы проблем


Продукт:
  • Продукт не приносит прибыли или другой пользы компании.
  • Аудитория продукта стагнирует или падает.
  • Использование «тёмных паттернов» для увеличения прибыли.
  • Неудачные интерфейсные решения снижают эффективность работы пользователей.

Организация:
  • Принятие решений о том, каким должен быть продукт, происходит несистемно (слепое копирование конкурентов, паническая реакция на отклонение от ожидаемых значений метрик).
  • Менеджер продукта и команда не знают, насколько хорошо сработали решения.
  • Дизайнеры не имеют влияния на продуктовые решения.


Способ решения -> паттерн


Продуктовые инсайты, исходящие от дизайнеров:
  • Т: Креативные методики решения проблем (часть 4, 5)
  • С: Метрики дизайна, завязанные на бизнес (часть 5)
  • С: Разведочные пользовательские исследования для поиска проблем и «окон возможностей» (часть 5)
  • С: Сегментация и другие способы оценки важности проблем для пользователей (часть 5)
  • С: База знаний об интерфейсе и пользователях (часть 5)

Кросс-функциональное взаимодействие:
  • Т: Уменьшение интерфейсного долга (часть 6)
  • С: Ко-дизайн (часть 4)
  • С: Карта взаимодействия (Customer Journey Map) и оптимизация всех каналов (часть 5)

Предсказуемость:
  • С: Планирование (долгосрочное) (часть 4, 6)


5. Усиление бренда


Ценность для бизнеса: Повысить лояльность существующей аудитории и привлечь новую.

Критерии оценки:
  • Интерфейс продукта усиливает лояльность пользователей к бренду.
  • Стоимость компании и привлекательность продукта повышается за счёт качественного дизайна.


Симптомы проблем


Продукт:
  • Интерфейс продукта слабо связан с брендом.
  • Разные продукты или даже разные экраны одного продукта выглядят и работают по-разному.

Организация:
  • Нет ответственного за развитие бренда.
  • Разные подразделения и продукты компании не взаимодействуют друг с другом.


Способ решения -> паттерн


Единство бренда:
  • Т: Дизайн-система (часть 3)
  • С: Принципы дизайна, идущие от бренда (часть 3)

Кросс-функциональные команды:
  • С: Клуб дизайн-лидеров (часть 4)
  • С: Общая дизайн-грамотность (часть 4)


6. Найм и развитие дизайнеров


Ценность для бизнеса: Привлечь и удержать достаточное количество специалистов по дизайну нужной квалификации.

Критерии оценки:
  • Нужный специалист по дизайну уже есть или может подключиться к команде в приемлемые сроки.
  • Навыки дизайнеров соответствуют задачам компании в текущей и среднесрочной перспективе.
  • Дизайн стоит для компании адекватных денег.


Симптомы проблем


Продукт:
  • Слабые или даже вредные дизайн-решения.
  • Проблемы в интерфейсе не исправляются.

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


Способ решения -> паттерн


Закрытие текущих и будущих потребностей компании:
  • О: Лидер дизайна (часть 4)
  • О: Карта навыков и их развития (часть 4)

Привлечение более сильных дизайнеров:
  • С: HR-бренд


Планирование и отслеживание изменений


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

0. Портрет компании


В первой части серии я описал «портрет» компании, который важно понимать дизайн-менеджеру. Ресурсы, процессы и приоритеты — три ключевых составляющих, влияющих на текущее состояние организации и её будущее. Это та среда, в которой будет развиваться UX и её особенности крайне важны для успешности реализации UX-стратегии. Для того чтобы внедрить её, нужно глубоко понимать бизнес компании. У большинства организаций есть свои особенности, так что хотя цели внедрения UX у большинства похожи или одинаковы, реализация стратегии почти всегда уникальна в деталях.

Ресурсы:
  • Деньги: Как устроено бюджетирование (сколько дизайнеров можно нанять, есть ли бюджет на пользовательские исследования, бюджет на аутсорс).
  • Люди: Соотношение дизайнеров и разработчиков (оптимальные цифры, к которым нужно стремиться).
  • Время: В какой момент процесса работы над продуктом привлекаются дизайнеры.
  • Кредит доверия: Кому уже продали идею хорошего дизайна (топ-менеджмент, менеджеры продуктов, конечные специалисты (разработчики/тестировщики/маркетологи)).

Процессы:
  • Инициация продуктов и их новых возможностей: Какие уровни руководства, на базе какой информации (аналитика/исследования), как требования попадают к дизайнерам, как определяется успешность.
  • Дизайн и разработка: Структура команд, процесс, менеджмент.
  • Обеспечение качества: Методы, каков приемлемый уровень.
  • Дистрибьюция продукта: Каналы, их эффективность и стоимость на пользователя.
  • Поддержка пользователей: Каналы, удовлетворённость и CES (Customer Effort Score).

Приоритеты:
  • Тип продукта: Рынок (B2B, B2C или другой), платформа (сайт, приложение или другая).
  • Бизнес-модель: Ключевые метрики и как их оптимизировать.
  • Стадия жизненного цикла компании и продукта:
    1. Поиск подходящего рынка, продуктового решения и бизнес-модели для его монетизации.
    2. Рост пользовательской базы и/или прибыли.
    3. Удержание пользователей.
    4. Эффективность ведения бизнеса.
    5. Вывод продукта из кризиса, когда падают пользовательская база, прибыль или рыночная доля — всё сразу или что-то из них.



1. Ценность дизайна для бизнеса


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

Например:
Ценность сейчас через год
Качество продукта терпимо критично
Скорость выхода на рынок критично терпимо
Снижение рисков при выходе на рынок терпимо терпимо
Увеличение аудитории и прибыли продукта критично терпимо
Усиление бренда не важно терпимо
Найм и развитие дизайнеров терпимо терпимо
Осознание ценности дизайна терпимо терпимо


2. Интерфейсный и организационный долг


Теперь нужно описать интерфейсный и организационный долг. Первый покажет проблемы в продукте, второй — в организации, которая создаёт этот продукт. Для этого хорошо работают чек-листы и эвристики. Для оценки интерфейсного долга подойдёт шикарный шаблон от Kimberly Dunwoody и Susan Teague Rector или готовые чек-листы вроде 10 эвристик Якоба Нильсена. Для оценки организационного — описанные выше паттерны дизайн-менеджмента. Кстати, в моей концепции интерфейсный долг — сам по себе организационный паттерн.

Организационный долг:
Например:
Проблема или идея
Общая дизайн-грамотность: Тренинг для менеджеров и разработчиков
Медиа-кит по рекламным форматам
Описать интерфейсный долг
База знаний по трендам
Участие дизайнеров в продуктовых планёрках
Формат хакатонов
Именование файлов
Генератор иконок в SVG
Бенчмарки: Наши продукты и конкуренты

Интерфейсный долг:
Проблема или идея
Переделать предупреждение про регион
Перенести шаринг из левой колонки
Заменить пояс новостей на более ёмкий и простой
Оптимизировать врез киноафиши на главной
Убрать новости из истории просмотра
Улучшение интерфейсных текстов
Обменный пояс не на своём месте
Тянуть блок фильма до конца
Убрать ALL CAPS

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

3. Видение будущего дизайна


Мы уже разобрались, какие задачи стоят перед компанией сейчас и в ближайшем будущем, а из чек-листа ясны белые пятна — что именно нужно подтянуть. Теперь нужно наглядно показать видение будущего дизайна в компании — какими могут стать продукты и организация через несколько лет, когда оба долга будут значительно уменьшены. Здесь хорошо работают:
  • Концепты будущего дизайна продуктов.
  • Обновлённый бренд и визуальный язык.
  • Принципы дизайна для продукта, компании или дизайн-команды.

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

4. План внедрения


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

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

Организационный долг:
Проблема или идея Ценность Уровень Сложность
Общая дизайн-грамотность: Тренинг для менеджеров и разработчиков качество
риски
бренд
С квартал
Медиа-кит по рекламным форматам качество
скорость
рост
Т месяц
Описать интерфейсный долг качество
риски
рост
Т месяц
База знаний по трендам риски
рост
С месяц
Участие дизайнеров в продуктовых планёрках скорость
риски
рост
Т месяц
Формат хакатонов скорость
рост
бренд
Т неделя
Именование файлов качество
скорость
О неделя
Генератор иконок в SVG качество
скорость
О квартал
Бенчмарки: Наши продукты и конкуренты качество
рост
С квартал

Интерфейсный долг:
Проблема или идея Метрики Пользователей затронуто, тыс. % Сложность
Переделать предупреждение про регион отношение 4 000 20% неделя
Перенести шаринг из левой колонки качество 20 000 100% месяц
Заменить пояс новостей на более ёмкий и простой деньги
качество
4 000 20% неделя
Оптимизировать врез киноафиши на главной деньги
качество
2 000 10% неделя
Убрать новости из истории просмотра деньги
качество
1 000 5% неделя
Улучшение интерфейсных текстов качество 20 000 100% неделя
Обменный пояс не на своём месте деньги 4 000 20% день
Тянуть блок фильма до конца качество месяц
Убрать ALL CAPS качество день

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

5. Реализация плана


Реализация плана изменений не так однозначна, как кажется из получившегося roadmap. Зачастую это непродуктовая работа, которая отвлекает время дизайнеров от основных задач, а не все менеджеры продуктов готовы на это. Кроме того, многие организационные изменения имеют отложенный эффект, так что время вы потратили сегодня, а ваше руководство увидит выхлоп сильно позже. Помогут две техники:
  • Чередовать «низковисящие фрукты» с долгосрочными инициативами. Первые будут показывать мгновенный эффект и помогут выиграть время на более сложные изменения, повышая кредит доверия.
  • Привязка процессных задач к продуктовым. Изменение лучше упаковывать вместе с реальной задачей по продукту — и проблема выделения времени решится, и на практике проверится.

Многие организационные изменения многогранны и требуют решения сразу нескольких разнородных задач, чтобы дать нужный эффект. Чтобы декомпозировать их и получить целостный, а не половинчатый эффект, их нужно решать в связке. В этом может быть полезен метод планирования по OKR (Objective Key Results). Мы выбираем три крупные темы на квартал (читай — комплексные изменения), каждую из них описываем в виде цели, решающей проблему, и метрик, показывающих успешность внедрения. Дальше делаем план из конкретных действий и идём по нему в ходе квартала. Это хороший способ сфокусировать и мобилизовать команду, чтобы интерфейсные и организационные изменения дали заметный выхлоп, а не просто по мелочи улучшили самочувствие.

Пример OKR:
Предсказуемо высокое качество дизайна на живых продуктах.

Цель: Запустить механизмы обеспечения качества.

Метрики:
  • Все баги и идеи по дизайну зафиксированы в Jira
  • Исправлен как минимум 1 баг на каждом из продуктов

Ключевые результаты:
  • На уровне макетов:
    • Чек-листы для проверки дизайна
    • «Свежий взгляд»: Проверка макетов одного дизайнера другим
    • Design Review всей командой

  • Перед выкаткой:
    • Design Review в Jira: Мобильные приложения
    • Design Review в Jira: Маркетинг

  • После выкатки:
    • Дизайнеры включены в рассылки о всех выкатках
    • Перевести все баги в Jira
    • Повторный Design Review продуктов каждый квартал
    • Задачи из Design Review попадают в продуктовый план
    • Инструкция о том, как описывать проблемы в ходе Design Review
    • Design Review после выкаток


Ну а в конце каждого квартала мы возвращаемся к первому пункту и актуализируем понимание компании и её проблем в дизайне. После этого определяем очередные OKR и берёмся за их внедрение. Каждое свершение или успех команды и продукта — это выходной, в лучшем случае — отпуск. Но никак не «золотой парашют» или выход на пенсию. Как говорил Энди Гроув, «выживают только параноики» — те, кто постоянно начеку.

Среднесрочные и долгосрочные планы полезно делать публичными. Это поможет сделать понимание проблем общим, заранее посвятить в них команду и менеджмент, а в идеале — зарядить их энтузиазмом по поводу того, каким может быть дизайн в компании. Мы используем два инструмента:
  • Стена будущего. Она показывает беклог интерфейсного и организационного долга, а также OKR в виде канбана.
  • Письма команде. Рассказ о текущих проблемах и планах по их решению.

Стена будущего
Стена будущего

У многих компаний на ранних стадиях зрелости явных проблем будет выше крыши, так что можно просто брать первые попавшиеся и разбираться с ними. Но более осмысленный подход, когда у вас есть полная картина, позволит вам двигаться быстрее и лучше понимать долгосрочную UX-стратегию. План — хорошее начало для системной работы. Пускай даже его объём фрустрирует на первый взгляд — по мере продвижения по нему скорость внедрения изменений будет увеличиваться и вы сами удивитесь, сколько сил и мотивации прибавляется команде по ходу.

Как меняется дизайн в известных компаниях


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

Критерии современной компании, ценящей дизайн


За последние годы появилось несколько интересных исследований, анализирующих успешные в плане дизайна компании на рынке. Хотя зачастую они отражают рынок США, цифровые продукты отличаются от страны к стране меньше, чем другие отрасли.

Исследования Leah Buley


Leah Buley провела в 2015 году для Forrester Research очень интересное исследование рынка. Она опросила 23 компании, чтобы узнать, как устроены их дизайн-команды. В результате у неё получилось выделить набор характеристик внутренней организации и вовлечённости в продуктовую работу, которые присущи наиболее сильным с точки зрения дизайна компаниям. Она подробно рассказывала о выводах на Interaction15, а в 2016 году провела повторный опрос (уже после ухода из Forrester). Вот некоторые из характеристик зрелых компаний:
  • Единый подход к дизайну по всей карте взаимодействия, не только цифровой части продукта (поддержка пользователей, офлайновые магазины и мероприятия, упаковка, «железо»).
  • Корпоративная, бренд- и UX-стратегия связаны.
  • Участие в определении продуктового плана.
  • Влияние на широкий спектр метрик с чётким пониманием отдачи от добротных дизайн-решений в деньгах.
  • Среднесрочное (как выпустить текущую версию) и долгосрочное видение продукта (его идеальное состояние).
  • Соотношение дизайнеров и разработчиков. Само по себе количество голов ни о чем не говорит, но такие цифры могут быть ещё одним индикатором зрелости. У лучших компаний отмечается 1:4, а абсолютный минимум для гармоничного развития — 1:12.
  • «Часы налёта» наблюдения за пользователями для всех участников продуктовой команды.






Nielsen/Norman Group


Похожий опрос среди 360 компаний провели Nielsen/Norman Group. Его результаты показывают, с какими проблемами внедрения зрелых практик дизайна на уровне компании сталкиваются дизайн-команды. Здесь также много полезных инсайтов. Например, дизайнеры чувствуют отдачу от своей работы в компаниях малого размера и там, где они в том или ином виде входят в дизайн-команду.

John Maeda


В 2015 году, будучи в KPCB, John Maeda выпустил свой первый отчёт о состоянии дизайна на рынке цифровых продуктов. В 2016 он ушёл из консалтинговой компании и теперь публикует отчёты от своего имени. В них много интереснейших цифр и фактов о том, какие инвестиции в дизайн и зачем делает бизнес, постепенно меняя отрасль.













Другие модели изменений


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

«Адаптивный дизайн»


Дизайн-мышление считается хорошей методологией для того, чтобы придумать будущее, но дальше все зачастую печально — оно так и остается красивым визионерством. А вот в связке с адаптивным лидерством, современным подходом к менеджменту, можно реализовать задуманное. Maya Bernstein и Marty Linsky предлагают методологию «адаптивного дизайна» на стыке дизайн-мышления и адаптивного лидерства, которая позволяет внедрять смелые идеи и изменения. Название, правда, не очень удачное, потому что занято responsive и adaptive-техниками работы с вереницей устройств и экранов.

Модель адаптивного дизайна от Maya Bernstein и Marty Linsky
Модель адаптивного дизайна от Maya Bernstein и Marty Linsky

DesignX


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

Intuit


Интересный подход связки бизнес- и UX-стратегии использует Intuit. Она работает на трёх уровнях — миссия (дизайн как агент социальных изменений), компания (дизайн как подразделение и профессиональный навык) и продукт (дизайн добротных experiences).

Связка бизнес- и UX-стратегии в Intuit
Связка бизнес- и UX-стратегии в Intuit

Подход «миссий» позволяет достичь долгосрочных целей, каждая из которых описывается на нескольких уровнях (ценности, цели, стратегия, приоритеты, метрики) и в идеале должна определять каждое продуктовое решение.

Структура "миссии" в Intuit

Подход "миссий" для реализации долгосрочных целей в Intuit
Подход «миссий» для реализации долгосрочных целей в Intuit

Jeffrey Onken


В своём выступлении на UX STRAT USA 2016 Jeffrey Onken предлагает рассматривать этапы модели зрелости UX как обычную customer journey map. В таком виде гораздо проще обнаруживать и исправлять проблемы, мешающие созданию хорошего дизайна.





Justinmind


В своей книге «How to Make an Enterprise UX Friendly: A Quick Guide» компания Justinmind предлагает шаблон для описания UX-стратегии:

Шаблон для описания корпоративной UX-стратегии  Justinmind
Шаблон Justinmind для описания корпоративной UX-стратегии

Kotter International


Теорий и моделей процесса изменений в классической теории менеджмента предостаточно. Например, 8-шаговый подход John Kotter.

Модель изменений Kotter International
Модель изменений Kotter International

Leah Buley


Leah Buley толково описывает разницу между бизнес-стратегией и UX-стратегией, указывая на слабые места последней. Она имеет две трактовки:
  • упрощённую, когда ярлык «стратегия» навешивается достаточно прозаичное планирование будущего продукта;
  • полноценную, когда речь идёт о принесении пользы бизнесу через дизайн в широкой сфере приложений и организационных изменениях.

В мастер-классе для UX STRAT USA 2016 она описывает свой подход к изменению дизайна в компаниях.

Leah Buley: Разница между бизнес- и UX-стратегией
Leah Buley: Разница между бизнес- и UX-стратегией

OPPOSITE


Brian Solis использует методологию OPPOSITE для пошаговой цифровой трансформации компании:
  • Ориентация (Orientation) — Определить видение будущего, несущего осмысленные изменения.
  • Люди (People) — Понимание ценности для пользователей, их ожиданий и поведения.
  • Процессы (Processes) — Оценить оперативную инфраструктуру и обновить технологии, процессы и внутренние правила для поддержки изменений.
  • Цели (Objectives) — Определить цели цифровой трансформации, объединив всех принимающих решения вокруг нового видения и его плана внедрения.
  • Структура (Structure) — Сформировать выделенную команду с ясно очерченными ролями, ответственностью, целями и способами оценки.
  • Инсайты и намерения (Insights & Intent) — Собрать данные и использовать инсайты для уточнения стратегии эволюции.
  • Технологии (Technology) — Перестроить фронт- и бек-энд для обеспечения единого интегрированного UX.
  • Внедрение (Execution) — Внедрять, получать обратную связь и корректировать направление трансформации.


Rosa Wu и Jess McMullin


В этой публикации интересно всё — и то, что она делает акцент на понимании бизнеса правильными словами, и то что она выпущена аж в 2006 году. Rosa Wu и Jess McMullin описывают свой подход к изменениям, состоящий из трёх этапов:
  1. Найти партнёров среди топ-менеджмента, а после этого показать им ценность дизайна. Они станут спонсорами и евангелистами дизайна в компании.
  2. Запустить пилотный проект, который даст быстрые победы и покажет ценность дизайна на практике с минимальными рисками.
  3. Широко рассказать об успехе, чтобы все продукты и подразделения компании также увидели ценность дизайна на практике.

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

Salesforce V2MOM


Руководитель Salesforce Marc Benioff создал в компании методологию V2MOM для определения планов на будущее. Их пишет каждое подразделение и сотрудник, так что в итоге получается целостная цепочка управления от основных целей бизнеса к конкретным действиям, связывая все части стратегии вместе:
  • Видение (Vision) — Чего хочется достичь?
  • Ценности (Values) — Что важного в этой цели?
  • Методы (Methods) — Как достичь её?
  • Препятствия (Obstacles) — Что может помешать?
  • Метрики (Measures) — Как определить, что цель достигнута?

Общая идея очень похожа на OKR в её цельном виде.

Toyota Kata и Kaizen


Японские управленческие практики широко востребованы в последние десятилетия благодаря смеси простоты и методичности. Toyota использует 4-этапный подход «Kata» для перехода от текущей ситуации к будущему:
  1. Понимая видение будущего или общее направление изменений...
  2. Оценить текущую ситуацию.
  3. Определить следующую целевую ситуацию.
  4. Итеративно двигаться в сторону нового состояния, что позволяет постепенно находить и решать заранее неизвестные препятствия.

Darren Hood из Bosch рассказал на UX Strategies Summit 2015 о том, как использовать «Kaizen» для изменений в дизайне компании. Это, опять же, множество непрерывных небольших улучшений, каждое из которых увеличивает ценность для пользователей или снижает затраты компании. Причём по всем фронтам, не только в рамках самого продукта — обучение и мотивация сотрудников, отношения с пользователями и т.п.

Кейсы


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

Accenture и Fjord


В 2013 году крупная консалтинговая компания Accenture купила известное дизайн-агентство Fjord. Celia Romaniuk, глава лондонского офиса студии, рассказывает, что CEO Accenture был протагонистом студии и дизайна в целом, так что он дал место у стола принятия решений и всячески поддерживал, хотя и не понимал до конца самих дизайнеров. При этом руководитель Celia в Accenture сказала ей, что в компании полно хороших и плохих людей, так что надо держаться первых и не думать о вторых, тогда получится всё. В итоге Fjord стал катализатором изменений в компании, потому что наглядно показал, что можно делать, так что постепенно начали проникаться и другие подразделения. При этом они избирательно внедряют общие для Accenture вещи, чтобы сохранить исходную культуру Fjord — не используют систему грейдов, имеют отдельный маркетинг и другие активности, хотя и стараются интегрироваться по-максимуму. Важно уделять внимание менеджменту дизайна и ценности, которую он приносит. В результате люди становятся более образованными в дизайне и дизайн в целом сильно помогает в организационных изменениях.

Правило масштабирования дизайна Fjord
Правило масштабирования дизайна Fjord

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

Citrix


Компания создала роль вице-президента по продуктовому дизайну и начала изменения с пилотных проектов. Вместо того, чтобы навязывать необходимость редизайна всем подразделениям сразу (не все понимали ценность дизайна), они работали поочерёдно со всеми, кто был готов сам. Результаты первого пилота были настолько успешными, что остальные продукты тоже захотели поработать с толковыми дизайнерами. Они получили кредит доверия с помощью этого примера и с тех пор плотно работают с кросс-функциональными командами, чтобы добиться критических бизнес-целей. Как говорит Julie Baher, ваша задача — изменить операционную систему компании.

Coca-Cola


David Butler из Coca-Cola изучал принципы других компаний, которые научились использовать дизайн для решения стратегических задач. Он начал работать в команде брендинга и коммуникаций, затем перешёл в упаковку и оборудование, после этого в розничные продажи, а в конце — бизнес-операции, включающие дистрибьюцию и поставки. Хотя он тратит много времени на профессиональное дизайнерское развитие, он не использует слова вроде «дизайн-мышление» при общении с бизнесом, а старается говорить на их языке — все инициативы должны повышать продажи.

Eventbrite


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

Ford


Толковый рассказ Parrish Hanna, руководителя эргономики и пользовательского взаимодействия Ford, о том, как компания меняет себя. Одним из ключевых моментов была привязка улучшения UX к миссии компании — «делать жизнь людей лучше».

Google


Первая попытка привести в порядок линейку продуктов в 2007 провалилась, но когда главой компании в 2011 году стал основатель Larry Page, он сделал качественный UX одной из ключевых задач. Лидером изменений со стороны самого дизайна стал Matias Duarte, глава дизайна Android. Он здраво посчитал, что централизация дизайна в компании с таким количеством продуктов невозможна и собрал небольшую рабочую группу UXA. После того как они нашли сильную визуально-интерфейсную концепцию, эта команда работала с дизайнерами из конкретных продуктов для ее внедрения. Сейчас связь между командой визуального языка и продуктами работает в обе стороны — дизайнеры на полях привносят в общий котёл свежие паттерны и решения. А Matias выступает как евангелист объединения усилий разных команд под единым видением дизайна — во многом этому помогло его тесное общение с Larry Page и способность донести идеи до топ-менеджмента.

IBM


Глава IBM Virginia Rometty видела, что рынок корпоративного ПО меняется — вместо сложных внедрений на всю компанию, где решение часто принимает отдел ИТ-закупок, всё чаще конкретные функциональные подразделения оплачивают подписку на подходящий сервис, а они более требовательны к качеству продукта (включающем юзабилити). Главе недавно купленного стартапа Phil Gilbert, который был евангелистом хорошего дизайна, предложили масштабировать его лучшие практики на всю компанию. Он объявил достаточно амбициозную цель — нанять и обучить 1000 дизайнеров — но не ожидал, что это реально. Но он получил не только добро, но и неожиданный вопрос: как быстро можно осуществить этот план?

Всего в компании 400 000 сотрудников и централизация экспертизы невозможна на практике. Была сделана ставка на лабораторию-инкубатор в Остине (Техас), которая занимается проработкой типовых процессов, визуальным языком, обучением. В итоге основная цель — повышение общей дизайн-культуры в компании, «продажа» ценности дизайна менеджменту разных уровней, проведение рабочих сессий и мастер-классов для передачи знаний и опыта. Один из инструментов для этого — менторство.

Intuit


Серьёзное внимание пользователям в компании начали уделять в 2004 году с внедрением NPS. Но к 2007 году рост показателя замедлился — количество критиков уменьшить удалось, а вот евангелисты не появлялись. Основатель Intuit Scott Cook устроил 5-часовую лекцию о пользе дизайна для менеджеров компании, но не особо тронул их. Зато выступавший следом за ним Alex Kazaks провёл небол

Метки:  

Играем с эмоциями: Microsoft Cognitive Services + Unity

Среда, 31 Мая 2017 г. 09:59 + в цитатник
Друзья!

Наверняка многие из вас уже слышали про когнитивные сервисы, которые позволяют одним вызовом REST API решать сложные задачи — определять эмоции и возраст человека по фотографии, делать машинный перевод текста и т.д. Часто когнитивные сервисы внедряют в приложения или веб-бекенд. Сегодня наш большой друг, сотрудник компании VRTech и Game-разработчик Григорий Дядиченко расскажет нам, как внедрять когнитивные сервисы в игры на Unity, а также пригласит вас на митап Unity-разработчиков, где можно будет обсудить это подробнее.




В этой статье мне бы хотелось рассказать про интеграцию Microsoft Cognitive Services в Unity; про то, как делать HTTP запросы к сервисам через класс WWW (если вдруг кто-то ещё не сталкивался с этим и не знает) и рассказать, с какими неожиданными для меня проблемами я столкнулся, разрабатывая приложение с использованием этих сервисов для Google Play.
 



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

Когда-то я уже писал статью про когнитивные сервисы, и даже конкретно про Emotions API. В ней использовалась библиотека для UWP, которую нельзя использовать в Unity проекте. Поэтому недавно мне пришла в голову идея, что неплохо было бы написать обёртку для этих сервисов для Unity. И я взялся за дело.

Эти сервисы являются интересным и недорогим инструментом для создания “вау эффекта” на выставках, сбора контактов и подобных задач. Работать с ними в принципе в разы проще, нежели с тем же OpenCV. В контексте разработки игр можно сделать прикольную плюшку для игрока, которая позволяет генерировать аватарку игроку по его фотографии.

Перейдём к описанию самой обёртки. На данный момент в ней частично покрыты Emotions API и Face API.
 


Взаимодействие с решением построено очень просто. Вы создаёте нужный вам сервис, указывая в конструкторе SubscriptionKey (для удобства в демо сценах для их хранения создан ScriptableObject), а дальше создаёте корутину, в которой забираете необходимые вам данные.
 
Пример
private IEnumerator CheckEmotions()
{
    EmotionService emoServ = new EmotionService(SubscriptionKeys.Instance.EmotionsApiKey);
    while (true)
    {
         yield return new WaitForEndOfFrame();
         yield return emoServ.GetEmoInfoCoroutine(_WebCam.Screenshot);
         var emotions = emoServ.LastEmotions;
         if (emotions != null)
         {
              _MaxEmotionValue.text = GetMaxEmotionOnScreenshot(emotions);
         }
         yield return new WaitForSeconds(DELAY);
     }
}


Бесплатную пробную версию subscription key можно получить на сайте когнитивных сервисов Microsoft
 
Итак, зачем тут корутины? Дело в том, что самый удобный способ обращаться к сервисам — это Rest API. Проще всего в Unity это делается с помощью класса WWW, в котором запрос работает асинхронно. Есть множество способов дождаться его выполнения.

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

А можно сделать корутинами, что и реализовано в данной версии обёртки.
 
Пример
private IEnumerator CreateRecognizeRequestAndSaveResponseCoroutine(
           string contentHeader, 
           byte[] data)
{
    Dictionary headers = new Dictionary();
    headers.Add(Constants.SUB_KEY_HEADER, _SubscriptionKey);
    headers.Add(Constants.CONTENT_TYPE_HEADER, contentHeader);
    WWW request = new WWW(_RecognizeRequestUrl, data, headers);
    yield return new WaitUntil(() => request.isDone);
    ParseEmotionsFromJson(request.text);
}


Данный способ работает неплохо, и устраивал меня, когда я писал своё приложение под андроид. Так как анализ фотографий занимает некоторое время, чтобы пользователь не сидел без дела, я решил интегрировать рекламу. Но в ходе интеграции рекламы появились неожиданные проблемы. Пользователь смотрит рекламу, профиль анализируется — профит, но не тут-то было. Тут меня ждала особенность, про которую я не знал относительно Unity Ads на андроиде. Дело в том, что во время показа рекламы блокируется главный поток, поэтому для анализа профиля было решено вынести всё в отдельный поток.
 
Там меня ждало новое, но вполне логичное открытие. Оказывается, класс WWW может работать только в главном потоке. Поэтому пришлось всё писать на System.Net (версии 2.0, так как в Unity именно она). И я бы выложил это решение в репозиторий, но там потребовалось подписывать SSL-сертификат, что неочевидно, и может приводить к непредвиденным последствиям у пользователя обёртки. Если вдруг кому-то будет интересно, то я могу её выложить отдельным проектом на гитхабе, но с точки зрения реализации там нет ничего сложного.
 
(Не самый красивый пример сделанный на скорую руку)
Пример в отдельном потоке
private void CreateRecognizeRequest()
{
    Clear();
    _Thread = new Thread(Run);
    _Thread.Start(); 
}
private void Run()
{
    WebHeaderCollection headers = new WebHeaderCollection();
    headers.Add(Constants.SUB_KEY_HEADER, _SubscriptionKey);
    var request = HttpWebRequest.Create(_RecognizeRequestUrl);
    request.ContentType = _ContentHeader;
    request.Headers = headers;
    request.ContentLength = _Data.Length;
    request.Method = WebRequestMethods.Http.Post;
    var dataStream = request.GetRequestStream();
    dataStream.Write(_Data, 0, _Data.Length);
    dataStream.Close();
    var response = request.GetResponse();
    dataStream = response.GetResponseStream();
    StreamReader reader = new StreamReader(dataStream);
    string responseString = reader.ReadToEnd();

    reader.Close();
    dataStream.Close();
    response.Close();
    Debug.Log(responseString);
    if (!TryParseEmotionsFromJson(responseString))
    {
        Run();
    }
    else
    {
        _IsDataReady = true;
    }
}


Ещё одно забавное открытие было обнаружено при тестировании Face API. Хотелось сделать такой эффект идеальной улыбки.
 




Face API может возвращать тот же набор эмоций, что и Emotions API. Но в ходе тестов я обнаружил, что результаты разнятся, при этом Emotions API работает чуть более стабильно и точно. Поэтому для данного эффекта, лендмарки лица (чтобы правильно поставить звёздочку) забирались из Face API, а эмоции — из Emotions API.

В ближайшее время я планирую вернуться к реализации этой обёртки и к поиску новых приколов, связанных с использованием Microsoft Cognitive Services. А пока в проекте есть Demo сцены, в которых показано простейшее взаимодействие EmotionService с веб камерой. Кроме того, некоторые полезные утилиты для скриншотов (скрипт, который делает скриншот определённого RectTransform к примеру)

Возвращаясь к обёртке, скачать и следить за её развитием можно в Github репозитории. (Возможно после митапа дойдут руки написать документацию)
 

Unity Moscow Meetup #3


7 июня в ВШБИ пройдёт третий митап Unity разработчиков в Москве. Если вы занимаетесь разработкой на Unity или она вам интересна — приходите! Мероприятие бесплатное, регистрация обязательна, зарегистрироваться и узнать более подробную информацию можно тут

А так же, чтобы сделить за последующими мероприятиями и посмотреть материалы с прошлых встреч, можете вступить в группы:
VK: vk.com/unimosmeet
FB: www.facebook.com/groups/unimosmeet
 

Об авторе


Дядиченко Григорий — ведущий Unity разработчик в VRTech. Организатор Unity Moscow Meetup. Увлекается алгоритмами на графах, разработкой игр и всем, что связано с компьютерной графикой.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329866/


Метки:  

Удаленное подключение к защищаемым компьютерам из корпоративного антивируса

Среда, 31 Мая 2017 г. 08:35 + в цитатник


Интеграция корпоративного антивируса со средствами удаленного управления – вещь вполне удобная и полезная, особенно для тех компаний, которые не имеют полноценных комплексных RMM-решений, а бесплатных индивидуальных утилит по каким-то причинам недостаточно. Рассмотрим на примере нового Panda Remote Control.

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

В данном случае есть различные варианты решения с помощью специальных утилит удаленного доступа: от бесплатных индивидуальных инструментов типа TeamViewer до комплексных RMM-решений как Panda Systems Management, о котором мы публиковали серию статей. Однако бесплатных решений для кого-то может быть недостаточно, а комплексные решения стоят недешево. В этом случае можно сэкономить, если ваш корпоративный антивирус интегрирован со средствами удаленного управления.
В качестве примера такого решения мы можем привести модуль удаленного управления Panda Remote Control для корпоративных антивирусных решений Panda Endpoint Protection [Plus] и Panda Adaptive Defense 360. Несмотря на то, что решения Panda уже много лет интегрированы со средствами удаленного доступа (TeamViewer, LogMe In, VNC), тем не менее, новый модуль позволяет осуществлять удаленное подключение к защищаемым компьютерам непосредственно в консоли управления корпоративным антивирусом без использования стороннего ПО.

Что такое Panda Remote Control


Panda Remote Control — это инструмент удаленного доступа, разработанный компанией Panda Security и интегрированный в веб-консоль управления корпоративными антивирусными решениями Endpoint Protection, Endpoint Protection Plus и Adaptive Defense 360.

Panda Remote Control позволяет администраторам:

• Удаленно предпринимать требуемые действия для решения инцидентов безопасности
• Предоставлять инструмент удаленной поддержки для устранения инцидентов на компьютерах.

Первая версия данного модуля поддерживает пока только системы Windows:

• Windows XP SP3 и выше (Vista, 7, 8, 8.1, 10)
• Windows XP (64-бит) SP2 и выше
• Windows Server 2003 SP2 и выше
• Windows 2003 (64-bit) SP2 и выше

Panda Remote Control содержит следующие функции:

• Удаленный рабочий стол
• Удаленная командная строка
• Монитор процессов: удаленное управление активными процессами
• Монитор служб: удаленное управление запущенными службами
• Двунаправленная передача файлов

Все эти функции доступны из веб-консоли управления корпоративными антивирусными решениями Panda.
В настоящий момент Panda Remote Control пока доступен только на английском языке.

Установка модуля и его обновления

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

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

Настройки модуля

Модуль Panda Remote Control имеет собственные настройки управления среди настроек профилей безопасности в веб-консоли управления.



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

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

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

Доступны следующие опции конфиденциальности:

Удаленный рабочий стол:

• Всегда спрашивать разрешение
• Только уведомить
• Разрешить доступ без уведомления

Действия по устранению неполадок:

• Всегда спрашивать разрешение
• Только уведомить
• Разрешить доступ без уведомления

Опция Действия по устранению неполадок подразумевает настройку опций конфиденциальности для следующих функций:

• Удаленная командная строка
• Монитор процессов: удаленное управление активными процессами
• Монитор служб: удаленное управление запущенными службами
• Передача файлов

Доступ к функциям удаленного управления из веб-консоли управления

Модуль удаленного управления может быть доступен с двух страниц в веб-консоле централизованного управления корпоративных антивирусных решений Panda:
• Раздел Компьютеры
• Страница Сведения о компьютере

Из раздела Компьютеры

Ранее, до появления модуля Panda Remote Control, в разделе Компьютеры показывалась зеленая галочка у тех компьютеров, на которых были установлены сторонние утилиты удаленного доступа (LogMeIn,TeamViewer или VNC), т.к. решения Panda допускают интеграцию с этими утилитами.



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



Эта иконка может выглядеть следующим образом:

— модуль включен

— модуль выключен

При нажатии на эту иконку можно выбрать соответствующее действие.

Со страницы Сведения о компьютере

Аналогично, страница Сведения о компьютере теперь содержит иконку для доступа к Panda Remote Control.



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


Если Panda Remote Control отключен, то данная кнопка будет не активна (серый цвет).


Удаленный рабочий стол

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



Здесь можно перейти к диспетчеру задач или выйти на меню, появляющееся при нажатии клавиш Ctrl+Alt+Del, сделать скриншот, переключиться в полноэкранный режим.

Командная строка

При выборе данной опции можно открыть командную строку у данного компьютера.



Монитор процессов

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



Монитор служб

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



Передача файлов

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



Локальная настройка опций конфиденциальности

После того как Panda Remote Control был установлен на компьютер, и если в веб-консоли централизованного управления была включена опция Разрешить пользователю ПК устанавливать уровень конфиденциальности, то иконка Panda на компьютере конечного пользователя предоставит доступ к следующим опциям:

Удаленный рабочий стол:

• Спрашивать разрешение на удаленный доступ
• Уведомлять об удаленном подключении
• Разрешать удаленный доступ без уведомления

Действия по устранению неполадок:

• Спрашивать разрешение на действия
• Уведомлять о действиях
• Разрешать действия без уведомления



Всплывающие окна

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

• Сообщения, в которых запрашиваются права для установления подключения к удаленному рабочему столу:


• Сообщения, информирующие о начале сессии удаленного управления:


Права на использование Panda Remote Control

Только пользователи с правами доступа Полный контроль и Администратор безопасности могут использовать Panda Remote Control. И только пользователи с правами Администратор безопасности смогут подключаться к тем компьютерам, на которые они имеют права. Пользователи с правами Мониторинг не смогут использовать Panda Remote Control.

Права для сервис-провайдера

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



Права для службы поддержки Panda

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



Заключение


Модуль Panda Remote Control полезен в тех случаях, когда необходимо удаленно выполнить какие-либо действия на требуемом компьютере. Это могут быть различные случаи: инциденты безопасности, сбой в работе, установка или настройка ПО, запуск требуемых процессов или служб и т.д. Ну и не надо забывать, что удаленное подключение может использоваться и в целях мониторинга и контроля работы сотрудников, когда можно подключиться к ПК сотрудника и проверить, чем он занимается в рабочее время.

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

Демо-консоль Adaptive Defense 360 + Remote Control

Для знакомства с консолью управления достаточно только обычного браузера (рекомендуется Chrome или Firefox) и немного свободного времени.

Консоль: demologin.pandasecurity.com
логин: DRUSSIAN_FEDERATION_C18@panda.com
пароль: DRUSSIAN#123

Триал-лицензии Adaptive Defense 360

Вы можете зарегистрировать бесплатные полнофункциональные лицензии сроком на 1 месяц:
www.pandasecurity.com/russia/intelligence-platform/solutions.htm
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329862/


Container Networking Interface (CNI) — сетевой интерфейс и стандарт для Linux-контейнеров

Среда, 31 Мая 2017 г. 08:20 + в цитатник


На прошлой неделе фонд CNCF (Cloud Native Computing Foundation) объявил о принятии под своё крыло 10-го Open Source-проекта — CNI (Container Networking Interface). Его задача — обеспечить всё необходимое для стандартизированного управления сетевыми интерфейсами в Linux-контейнерах и гибкого расширения сетевых возможностей. В CNCF объяснили необходимость такого проекта активным распространением контейнеризированных приложений в мире production и утверждают, что «подобно тому, как Kubernetes позволяет разработчикам массово запускать контейнеры на тысячах машинах, этим контейнерам в больших масштабах требуется сетевое управление [и реализующий его фреймворк]».

Как же появился CNI и что он предлагает?

Предыстория CNI


Проект Container Network Interface (CNI) зародился в компании CoreOS, известной по движку для контейнеров rkt (недавно был тоже передан в CNCF, одновременно с containerd), NoSQL-хранилищу etcd, активной работе над Kubernetes и другими Open Source-проектами, связанными с контейнерами и DevOps. Первая подробная демонстрация CNI состоялась ещё в конце 2015 года (см. видео в октябре, презентацию в ноябре). С самого начала проект позиционировался в качестве «предлагаемого стандарта для конфигурации сетевых интерфейсов для Linux-контейнеров», а использовать его первым делом начали, конечно же, в rkt. Первыми «сторонними пользователями» CNI стали Project Calico, Weaveworks, а в скором времени к ним примкнул Kubernetes.

Адаптация CNI в платформе Kubernetes стоит отдельного внимания. Поскольку потребность в стандартизации сетевой конфигурации Linux-контейнеров была очевидной и всё более актуальной на тот момент (~2015 год), CNI оказался не единственным таким проектом. Конкурирующий продукт — Container Network Model (CNM) от Docker, представленный в том же 2015-м, — решал те же задачи и получил свою эталонную реализацию в виде libnetwork — библиотеки, которая выросла из сетевого кода в libcontainer и Docker Engine. И важным этапом в противостоянии CNI и CNM стал выбор, сделанный Kubernetes. В статье «Почему Kubernetes не использует libnetwork?» (январь 2016 года) разработчики подробно описывают все технические и иные причины, объясняющие их решение. Основная же суть (помимо ряда технических моментов) сводится к следующему:

CNI ближе к Kubernetes с философской точки зрения. Он гораздо проще CNM, не требует демонов и его кроссплатформенность по меньшей правдоподобна (исполняемая среда контейнеров CoreOS rkt поддерживает его) [… а Kubernetes стремится поддерживать разные реализации контейнеров — прим. перев.]. Быть кроссплатформенным означает возможность использования сетевых конфигураций, которые будут одинаково работать в разных исполняемых средах (т.е. Docker, Rocket, Hyper). Этот подход следует философии UNIX делать одну вещь хорошо.

По всей видимости, именно это (не только выбор Kubernetes, но и сторонний взгляд технических специалистов на существующие реализации) предопределило будущее CNI и его принятие в CNCF. Для сравнения, другие конкурирующие продукты CoreOS и Docker: среды исполнения контейнеров rkt и conatinerd — были приняты в фонд вместе и одновременно, а вот с CNI/CNM этого не произошло.


Взгляд проекта Calico на сети для контейнеров в марте 2016 года

Дополнительное сравнение CNI и CNM по состоянию на сентябрь 2016 года можно также найти в англоязычной статье на The New Stack.

Устройство CNI


Авторы CNI пошли путём создания минимально возможной спецификации, предназначение которой — стать лёгкой прослойкой между исполняемой средой контейнера и плагинами. Все необходимые сетевые функции реализуются именно в плагинах, взаимодействие с которыми определено схемой в формате JSON.



CNI состоит из трёх частей:

1. Спецификации (см. GitHub), определяющей API между исполняемой средой контейнера и сетевыми плагинами: обязательные поддерживаемые операции (добавление контейнера в сеть и удаление его оттуда), список параметров, формат конфигурации сети и их списков (хранятся в JSON), а также известных структур (IP-адресов, маршрутов, DNS-серверов).

Пример конфигурации сети в CNI:
{
  "cniVersion": "0.3.1",
  "name": "dbnet",
  "type": "bridge",
  "bridge": "cni0",
  "ipam": {
    "type": "host-local",
    "subnet": "10.1.0.0/16",
    "gateway": "10.1.0.1"
  },
  "dns": {
    "nameservers": [ "10.1.0.1" ]
  }
}

2. Официальных плагинов, предоставляющих сетевые конфигурации для разных ситуаций и служащих примером соответствия спецификации CNI. Они доступны в containernetworking/plugins и разбиты на 4 категории: main (loopback, bridge, ptp, vlan, ipvlan, macvlan), ipam (dhcp, host-local), meta (flannel, tuning), sample. Все написаны на Go. (Про сторонние плагины см. в следующем разделе статьи.)

3. Библиотеки (libcni), предлагающей реализацию спецификации CNI (тоже на языке Go) для удобного использования в исполняемых средах контейнеров.

Весь имеющийся код (и спецификация) опубликованы под свободной лицензией Apache License v2.0.

Быстро попробовать CNI


«Потрогать руками» CNI можно и без контейнеров. Для этого достаточно загрузить себе файлы из репозитория проекта (и, по желанию, нужных плагинов), собрать их с ./build.sh (или скачать уже бинарную сборку), после чего — воспользоваться исполняемым файлом плагина (например, ./bin/bridge), передав ему необходимые для функционирования аргументы через переменные окружения CNI_*, а сетевую конфигурацию — прямо JSON-данными через STDIN (так предусмотрено в спецификации CNI).

Подробности о таком эксперименте можно найти в этой статье, автор которой делает приблизительно следующее (на хосте в Ubuntu):
$ cat > mybridge.conf <<"EOF"
{
    "cniVersion": "0.2.0",
    "name": "mybridge",
    "type": "bridge",
    "bridge": "cni_bridge0",
    "isGateway": true,
    "ipMasq": true,
    "ipam": {
        "type": "host-local",
        "subnet": "10.15.20.0/24",
        "routes": [
            { "dst": "0.0.0.0/0" },
            { "dst": "1.1.1.1/32", "gw":"10.15.20.1"}
        ]
    }
}
EOF
$ sudo ip netns add 1234567890
$ sudo CNI_COMMAND=ADD CNI_CONTAINERID=1234567890 \
 CNI_NETNS=/var/run/netns/1234567890 CNI_IFNAME=eth12 \
 CNI_PATH=`pwd` ./bridge 64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:536 (536.0 B)  TX bytes:648 (648.0 B)
…

Дополнительные примеры для быстрого запуска CNI и сетевых плагинов представлены в README проекта (раздел «How do I use CNI?»).

Сторонние плагины для CNI


Одной из главных ценностей CNI, конечно же, являются сторонние плагины, обеспечивающие поддержку различных современных решений для Linux-контейнеров. Среди них:
  • Project Calico (виртуальная сеть L3, интегрированная с инструментами оркестровки и облачными платформами);
  • Weave (простая сеть для multi-host Docker-инсталляций);
  • Contiv Netplugin (политики/ACL/QoS и другие возможности для контейнеров в кластерных установках типа multi-host);
  • Flannel (сетевая фабрика для контейнеров от CoreOS);
  • SR-IOV, Cilium (BPF/XDP), Multus (плагин Multi для Kubernetes от Intel), VMware NSX и другие…

К сожалению, какого-либо каталога или постоянно обновляемого их списка пока нет, но для общего представления о текущем распространении CNI этого должно быть достаточно.

Дополнительным индикатором зрелости проекта является его интеграция в существующие исполняемые среды для контейнеров: rkt и Kurma, — и платформы для работы с контейнерами: Kubernetes, OpenShift, Cloud Foundry, Mesos.

Заключение


Текущий статус CNI позволяет уже сейчас говорить не только о «больших перспективах» проекта, но и ощутимых реалиях его практической применимости. Принятие в CNCF — официальное признание индустрией и гарантия для дальнейшего развития. А всё это означает, что самое время как минимум узнать про CNI, с которым скорее всего рано или поздно придётся встретиться.

Не забывайте также подписываться на хаб нашей компании, чтобы не пропустить новые статьи и рецепты по темам DevOps и системного администрирования GNU/Linux! ;-)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329830/


Postgres и Пустота

Среда, 31 Мая 2017 г. 07:50 + в цитатник

Только что натолкнулся на возможность Postgresql, показавшуюся мне забавной.
Для кого "боян" — респект вам, я несколько лет работаю с Postgres и до сих пор не натыкался на такую штуку.


select; без указания полей, таблицы и условий возвращает одну строку.
Но у этой строки нет полей:


=> select;
--
(1 row)

Для сравнения:


=> select null;
 ?column? 
----------

(1 row)
=> select null where 0=1;
 ?column? 
----------
(0 rows)

А сможем ли мы создать таблицу из такого "пустого" запроса? Таблицу без полей.


Да пожалуйста:


=> create table t as select;
SELECT 1
=> \d+ t
                          Table "t"
 Column | Type | Modifiers | Storage | Stats target | Description 
--------+------+-----------+---------+--------------+-------------
=> select * from t;
--
(1 row)

А можем ли мы в неё вставить?
Легко:


=> insert into t select;
INSERT 0 1
=> insert into t select;
INSERT 0 1
=> select * from t;
--
(3 rows)
=> select count(*) from t;
 count 
-------
     3

ЕЩЕ!


=> insert into t select from generate_series(1,1000000);
INSERT 0 1000000

Интересно, будет ли Postgresql сканировать такую таблицу?


=> explain analyze select * from t;
                                                 QUERY PLAN                                                 
------------------------------------------------------------------------------------------------------------
 Seq Scan on t  (cost=0.00..13438.67 rows=1000167 width=0) (actual time=0.018..96.389 rows=1000003 loops=1)
 Planning time: 0.024 ms
 Execution time: 134.654 ms
(3 rows)

Да, честно сканирует. Больше 100 ms — вполне себе заметное время.
Ну и чтобы убедиться, что всё по честному, посмотрим сколько места занимает наша супер-полезная таблица:


=> select pg_size_pretty(pg_total_relation_size('t'));
 pg_size_pretty 
----------------
 27 MB
(1 row)

То есть таблица есть, занимает место на диске, в блоках хранятся разные служебные данные, ну а то, что в ней нет полей — бывает, дело житейское!


=> select t.xmin, t.ctid from t limit 10;
  xmin   |  ctid  
---------+--------
 1029645 | (0,1)
 1029647 | (0,2)
 1029648 | (0,3)
 1029649 | (0,4)
 1029649 | (0,5)
 1029649 | (0,6)
 1029649 | (0,7)
 1029649 | (0,8)
 1029649 | (0,9)
 1029649 | (0,10)
(10 rows)

Я не придумал, зачем может понадобиться такая таблица. Но возможность есть, и это хорошо!

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329856/


Метки:  

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 3

Среда, 31 Мая 2017 г. 06:55 + в цитатник

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2

Среда, 31 Мая 2017 г. 06:39 + в цитатник

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 2



MIPSfpga микропроцессор MIPS32 microAptiv описаный на языке Verilog для образовательных целей фирмы Imagination, который имеет кэш-память и блок управления памятью. Код процессора доступен пользователю (инструкция по скачиванию) и может использоваться для моделирования и реализации процессора на FPGA плате.

Данная статья является продолжением статьи о том как портировать MIPSfpga-plus на другие платы, и в ней будет описано как интегрировать периферию в систему MIPSfpga:


Так же о том как начать работать с MIPSfpga написано в статье:
habrahabr.ru/post/275215

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

Для начала нужно иметь понятие как будут проходить сигналы по шине AHB-Lite:


Видно, что процесс считывания данных с периферии осуществляется по сигналу HRDATA, передача данных производится по HWRITE с активным высоким уровнем на сигнале разрешения записи, выбор GPIO осуществляется выбором адреса на HADDR.

1. Подключение клавиатуры Digilent Pmod KYPD


Первым датчиком который был подключён это 16 кнопочный pmod KYPD (даташит)


Распиновка и сигналы клавиатуры описаны в таблице:
Пин Сигнал Назначение Пин Сигнал Назначение
1 Col4 4 колонка 7 ROW4 4 ряд
2 Col3 3 колонка 8 ROW3 3 ряд
3 Col2 2 колонка 9 ROW2 2 ряд
4 Col1 1 колонка 10 ROW1 1 ряд
5 GND контакт земли 11 GND контакт земли
6 GND контакт питания 12 VCC контакт питания


схема подключения клавиатуры очень простая:


Следующим шагом для интеграции клавиатуры к шине AHB-lite будет написание модуля на Verilog. На схеме показано что ряды подтянуты к питанию сопротивлениями в R=10к, это значит что активный сигнал на них будет низким, а на каждую колонку с определенной частотой подается тактовый сигнал (низкий уровень). В момент когда активный сигнал на входе совпадёт с колонкой (col) на которой нажата кнопка на выходе рядка появится низкий уровень. Для реализации такого процесса нужно написать дешифратор (пример реализации модуля так же описан в данной статье).

Сам модуль имеет вид:
module kypd_decoder(
                input 		      i_clk,
                input 		      i_rst_n,
                input          [3:0]  i_row,

                output reg     [3:0]  o_col,
                output reg     [3:0]  o_number
              );
	  
                reg            [19:0] counter;
                reg            [3:0]  col;
                reg            [3:0]  row;
                
                        //  row col
parameter   ZERO       = 8'b11100111,
            ONE        = 8'b01110111,
            TWO        = 8'b01111011,
            THREE      = 8'b01111101,
            FOUR       = 8'b10110111,
            FIVE       = 8'b10111011,
            SIX        = 8'b10111101,
            SEVEN      = 8'b11010111,
            EIGHT      = 8'b11011011,
            NINE       = 8'b11011101,
            A          = 8'b01111110,
            B          = 8'b10111110,
            C          = 8'b11011110,
            D          = 8'b11101110,
            E          = 8'b11101101,
            F          = 8'b11101011;


always @(posedge i_clk or negedge i_rst_n)
	if (i_rst_n == 0)
	   counter <= 20'b0;	   
	else
	   counter <= counter + 1'b1;


always @(posedge i_clk or negedge i_rst_n)
	if (i_rst_n == 1'b0) begin
	   
	   o_col <= 4'b1110;
	   col 	 <= 4'b1110;
	   row   <= 4'b1111;
	
	end else if (!counter) begin
    
       o_col <= {o_col [0], o_col [3:1]};
       col   <= o_col;
       row   <= i_row;
	
	end

always @(posedge i_clk or negedge i_rst_n)
	if (i_rst_n == 0)
		o_number <= 4'b0;
	else
		case ({row, col})
	
			ZERO:    o_number <= 4'h0;
			
			ONE:     o_number <= 4'h1;
			
			TWO:     o_number <= 4'h2;
			
			THREE:   o_number <= 4'h3;
			
			FOUR:    o_number <= 4'h4;
			
			FIVE:    o_number <= 4'h5;
			
			SIX:     o_number <= 4'h6;
			
			SEVEN:   o_number <= 4'h7;
			
			EIGHT:	 o_number <= 4'h8;
			
			NINE:	 o_number <= 4'h9;
			
			A:	 o_number <= 4'hA;
			
			B:	 o_number <= 4'hB;
			
			C:	 o_number <= 4'hC;
			
			D:       o_number <= 4'hD;
			
			E:       o_number <= 4'hE;
			
			F:       o_number <= 4'hF;
	
	
		endcase
		
endmodule

Схема модуля в Vivado будет иметь вид:


Если кратко, то добавить модуль дешифратора в проект Vivado нужно так: Add Sources -> Add or create design sources -> Next -> Create File -> (написать имя файла) -> Ok -> Ok -> Yes. Создан пустой Verilog файл, после создания файла, нужно его найти в иерархии системы MIPSfpga-plus, написать код дешифратора и сохранить. Более подробное описание как добавить модуль в проект и просто как работать с Vivado описано в предыдущей моей статье:

Портирование MIPSfpga на другие платы и интеграция периферии в систему. Часть 1

Теперь приступим к подключению входов и выходов к шине AHB-Lite и физическим выходам нашей платы.

Иерархия mipsfpga_ahb имеет вид:


Для начала в директории Verilog Header mfp_ahb_lite_matrix_config.vh пропишем с помощью директивы `define название периферии которую будем подключать. Для этого найдем строку с идентификатором добавления в систему датчика освещённости (подробнее о датчике описано в предыдущей статье):

Строку нужно закомментировать, это позволит выключить все строки которые связаны с кодом подключения датчика освещённости к шине AHB-Lite:
//`define MFP_DEMO_LIGHT_SENSOR

Пропишем и расскоментируем строку для нащей периферии:
`define MFP_PMOD_KYPD

Откроем «mfp_system» найдем строки подключения екземпляра датчика освещенности:
`ifdef MFP_DEMO_LIGHT_SENSOR

И рядом добавим екземпляр своего модуля дешифратора:
`ifdef MFP_PMOD_KYPD
      kypd_decoder kypd_decoder
                      (                  
                          .i_clk    (   SI_ClkIn         ),
                          .i_rst_n  (   KEY_0            ),
                          .o_col    (   KYPD_DATA [3:0]  ),
                          .i_row    (   KYPD_DATA [7:4]  ),   
                          .o_number (   KYPD_OUT         )
                      );
`endif

Сигналы модуля дешифратора нужно подключить к екземпляру шины mfp_ahb_lite_matrix_with_loader (где прописывать нужные строчки можно смотреть по примеру интеграции датчика освещённости с помощью поиска по модулю MFP_DEMO_LIGHT_SENSOR):
`ifdef MFP_PMOD_KYPD
            .KYPD_OUT    (    KYPD_OUT      ),    
`endif

Для соединения экземпляров модуля дешифратора и шины добавим сигнал типа wire:
`ifdef MFP_PMOD_KYPD
            wire [3:0] KYPD_OUT;
`endif

После подключения нашего модуля дешифратора к шине перейдём в «mfp_ahb_lite_matrix_with_loader» который находится по иерархии ниже модуля «mfp_system» и добавим порт ввода/вывода:
`ifdef MFP_PMOD_KYPD
             input [3:0] KYPD_OUT,
`endif

Так же добавим эти сигналы в екземпляр «mfp_ahb_lite_matrix»:
`ifdef MFP_PMOD_KYPD
            .KYPD_OUT    (    KYPD_OUT      ),    
`endif

Те же действия проделаем в «mfp_ahb_lite_matrix» который находится по иерархии ниже модуля «mfp_ahb_lite_matrix_with_loader» и добавим порт ввода/вывода:
`ifdef MFP_PMOD_KYPD
             input [3:0] KYPD_OUT,
`endif

Так же добавим эти сигналы в екземпляр «mfp_ahb_gpio_slave»:
`ifdef MFP_PMOD_KYPD
            .KYPD_OUT    (    KYPD_OUT      ),    
`endif

Перейдем в модуль «mfp_ahb_gpio_slave», это именно тот блок (GPIO) в который мы так рвались, добавим порт ввода/вывода:
`ifdef MFP_PMOD_KYPD
             input [3:0] KYPD_OUT,
`endif

Теперь следует изменить модуль «mfp_ahb_gpio_slave» так, чтобы он обнаруживал адрес ввода/вывода с отображением в память (которые мы ещё определим) и записывал данные (HWDATA) в соответствующий обнаруженному адресу регистр:
`ifdef MFP_PMOD_KYPD
            `MFP_PMOD_KYPD_IONUM  : HRDATA <= { 28'b0,    KYPD_OUT };
`endif

Чтобы указать адрес по которому мы будем обращаться, откроем заголовочный файл «mfp_ahb_lite_matrix_config.vh» и добавим:
`ifdef MFP_PMOD_KYPD
`define MFP_PMOD_KYPD_ADDR          32'h1f800018
`endif

Модуль GPIO использует младшие биты адреса, чтобы определить, с каким периферийным устройством следует осуществлять операцию чтения или записи информации.
`ifdef MFP_PMOD_KYPD            
`define MFP_PMOD_KYPD_IONUM         4'h6
`endif

Вернемся назад по иерархии в модуль «mfp_system» и добавим порты ввода/вывода:
     `ifdef MFP_PMOD_KYPD
     inout [7:0] KYPD_DATA,
     input KEY_0,
    `endif

Стоит заметить что это уже не совсем те порты которые мы подключали к шине. Перейдем в топ модуль оболочку (у меня «cmoda7») и добавим в екземпляр «mfp_system» строчки:
        `ifdef MFP_PMOD_KYPD
    	.KYPD_DATA		  (     JA           ),
	.KEY_0                    (     ~ i_btn1     ),
        `endif

Таким образом мы добавили к JA[7:0] выводам модуль нашего декодера и соединили декодер с процессором по шине AHB-Lite.

В нашем случае порты ввода/вывода JA в модуле оболочке и в файле ограничений (у меня «cmoda7.xdc») добавлять не потребуется так как они уже использовались для датчика освещённости. Но в других случаях такие действия потребуются, потому для понимания я просто покажу эти строки:
module cmoda7
(
...
...
...
   inout  [ 7:0] JA
);


cmoda7.xdc
## Pmod Header JA
set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {JA[0]}]
set_property -dict {PACKAGE_PIN G19 IOSTANDARD LVCMOS33} [get_ports {JA[1]}]
set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports {JA[2]}]
set_property -dict {PACKAGE_PIN L18 IOSTANDARD LVCMOS33} [get_ports {JA[3]}]
set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {JA[4]}]
set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS33} [get_ports {JA[5]}]
set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports {JA[6]}]
set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports {JA[7]}]


И если мы вспомним в «mfp_ahb_lite_matrix_config.vh» мы закомментировали строку:
//`define MFP_DEMO_LIGHT_SENSOR

тем самым при синтезе системы весь код прописаный между
`ifdef MFP_DEMO_LIGHT_SENSOR
...
`endif 

будет игнорироваться, и конфликтов использования портов не будет.

Мы можем посмотреть схему созданой системы MIPSfpga-plus со встроенным дешифратором для нашей клавиатуры, для этого откройте во вкладке RTL Analysys -> Open Elaborated Design -> Schematic. Здесь отображается вся схема системы, чтобы проверить правильность подключёного модуля дешифратора желательно пройтись по RTL Netlist и проверить все контакты.
Теперь можно сгенерировать bitstream файл (.bit) и загрузить в FPGA.

Напишем простую программу для взаимодействия клавиатуры и процессора.
Для загрузки кода в систему нужно перейти в папку скачаного mipsfpga plus ->github->mipsfpga-plus->programs->01_pmod_kypd откроем «mfp_memory_mapped_registers.h»
#define MFP_PMOD_KYPD_ADDR      0xBF800018
и
#define MFP_PMOD_KYPD           (* (volatile unsigned *) MFP_PMOD_KYPD_ADDR     )

далее откроем main.c и напишем пару строк для демонстрации:
#include "mfp_memory_mapped_registers.h"

int main ()
{
    int n = 0;

    for (;;)
    {
        MFP_7_SEGMENT_HEX = MFP_PMOD_KYPD;
    }

    return 0;
}

После в папке находим скрипт который компилирует код:
02_compile_and_link

Генерируем motorola_s_record файл:
08_generate_motorola_s_record_file

Проверяем к какому СОМ порту подключен USB UART преобразователь:
11_check_which_com_port_is_used

Изменяем файл 12_upload_to_the_board_using_uart:
set a=7 
mode com%a% baud=115200 parity=n data=8 stop=1 to=off xon=off odsr=off octs=off dtr=off rts=off idsr=off type program.rec >\.\COM%a%

где а – номер СОМ порта, к которому подключен USB UART преобразователь.
И загружаем программу:
12_upload_to_the_board_using_uart

Результат:




В следующей части расскажу как добавить в MIPSfpga встроеный в cmoda7 АПЦ, и LCD дисплей от Nokia 5100.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329852/


[Перевод] Что нового нас ждет в Swift 4?

Среда, 31 Мая 2017 г. 00:43 + в цитатник

Метки:  

[Перевод] Ruby on Rails соглашение. Часть 3

Вторник, 30 Мая 2017 г. 23:39 + в цитатник


Ни одна парадигма


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

В Rails — это не так. Это не один, идеальный крой ткани. Это одеяло. Совокупность многих разных идей и даже парадигм. Многие из них, как правило, противоречат друг другу, если их сравнивать друг с другом и один за другим. Но это не то что мы пытаемся сделать. Это не одно большое соревнование, в котором должен быть объявлен один победитель.

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

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

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

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

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

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

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

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

Это относится и ко многим подязыкам, а также Rails. Мы не пытаемся оградить вас настолько, чтобы научиться, скажем, JavaScript для представления или SQL для сложных запросов. По крайней мере, чтобы не достичь пика возможностей.

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

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

Культ красоты кода


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

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

Вот простой пример из Active Record:

class Project < ApplicationRecord
  belongs_to :account
  has_many :participants, class_name: 'Person'
  validates_presence_of :name
end

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

Часть красоты данного примера заключается в том, что это соответствует предыдущим принципам, таким как Конвенция над конфигурацией. Когда мы вызываем belongs_to :account, то предполагаем, что внешний ключ называется account_id и что он находится в таблице projects. Когда нам нужно определить class_name Person для ассоциации participants, нам требуется определить только имя класса. Из этого мы вновь получим внешние ключи и другие точки конфигурации.

Вот еще один пример с миграцией базы данных:

class CreateAccounts < ActiveRecord::Migration
  def change
    create_table :accounts do |t|
      t.integer :queenbee_id
      t.timestamps
    end
  end
end


В этом и заключается сила фреймворка. Программист объявляет класс в соответствии с определенным соглашением, например, подкласс ActiveRecord::Migration, который реализует метод #change и фреймворк выполяет все связанные с этим операции и знает, что это метод вызова.

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

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

Эти два условия делают одно и тоже:

if people.include? person
      …
if person.in? people


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

Острые лезвия


В Ruby есть много острых лезвий. Не случайно, а намеренно. Самое известное это monkey-patching: механизм позволяющий изменить существующие методы и классы.

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

Если вы можете изменить что угодно, что остановит вас от переписывания функции String#capitalize и ‘something bold’.capitalize вернет ‘Something Bold’ вместо ‘Something bold’? Это сработает в вашем локальном приложении, но сломает всю логику, которая зависит от оригинальной реализации.

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

Потому что обратная сторона monkey patching это возможность делать такие вещи как 2.days.ago (возвращает дату на два дня назад от текущей). Вы можете подумать что это плохая сделка. То что вы лучше откажетесь от использования 2.days.ago если это будет означать, что программисты не перезаписывают String#capitalize. Если это ваша позиция, то Ruby вероятно не для вас.

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

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

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

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

Множество функций Rails со временем начинают оспариваться “слишком много свободы”. Но один пример, который в настоящее время является самым популярным, является апогеем. Это тонкий слой синтаксического сахара вокруг встроенной в Ruby функции модулей и предназначен для того, чтобы один класс мог инкапсулировать несколько связанных с ним классов, но самостоятельно понять concerns (отсюда и название).

Обвинение заключается в том, что при помощи concerns программисты могут разбить свои объекты на отдельные наборы и превращать очевидную структуру в беспорядок. И это правда. Concerns действительно могут быть использованы именно так.

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

Программисты, которые еще не научились обращаться с острыми лезвиями, пока не собираются делать безе. Важное слово здесь: Еще. Я считаю, что у каждого программиста есть путь, если не право, стать полностью способным программистом Ruby on Rails. И говоря способным я имею в виду осведомленным, чтобы знать, когда и в каком контексте следует использовать острые лезвия из набора инструментов.

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

Ruby on Rails — это среда для шеф-поваров и тех, кто хочет стать шеф-поварами. Вы можете начать с посуды, но вы можете поработать над кухней. Не позволяйте никому говорить вам, что вам нельзя доверять лучший инструмент в рамках этого пути.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329844/


Метки:  

DevOps на сервисах Amazon AWS

Вторник, 30 Мая 2017 г. 23:13 + в цитатник
Эффективность, которую даёт использование облачных сервисов — один из главных трендов для преобразования многих IT-компаний на сегодняшний день. Автоматизация всех процессов по пути от кода на GIT до развёртывания на Development и/или Production, а также последующий мониторинг, реакция на инциденты и т.д. (что также может и должно быть автоматизировано) — всё это, если не отменяет, то существенно меняет многие общепризнанные ITIL-практики. Взгляд на DevOps-процессы с точки зрения Amazon AWS: как они могут быть реализованы на его сервисах в рамках концепции IaaC (Infrastructure as a Code) — всё это будут даны далее в цикле статей, посвящённых Code-сервисам Amazon AWS: CodeCommit, CodeBuild, CodeDeploy, CodePipeline, CodeStar.
Эта статья первая, обзорная.

Цель данной статьи есть не ликбез по DevOps и не банальное дублирование и так имеющихся у первоисточника материалов. Целью есть представление реализации DevOps на сервисах Amazon AWS в её общем виде, из которой каждый волен выбрать нужный вариант. Целевыми читателями являются знакомые как минимум о существовании Amazon AWS, планирующие задействовать его возможности в своей работе, перенести туда свои процессы частично или полностью. Предоставляемые сервисы Amazon AWS плодятся с большой скоростью, их число уже превысило круглую отметку в 100 штук, потому даже имеющим хороший опыт с AWS может быть полезным узнать — что же появилось нового, такого, которое, может быть, они просто пропустили, а это можно успешно задействовать в их работе.

Не (только) кубики


image

Немного общих, но для кого-то важных слов, особенно для тех, кто не имеет достаточного опыта работы с Amazon AWS. Изображённые на логотипе кубики логически правильно передают основную идею: Amazon AWS — это конструктор, который даёт набор сервисов и из которого каждый может собрать себе нужное. Однако как раз этот момент «кубико-центричности» может некоторых отталкивать в случае, если нужный кубик (сервис) не удовлетворяет его запросы. В таком случае нужно помнить, что одну и ту же задачу можно решить с помощью разных сервисов, многие сервисы могут во многом дублируют друг друга, а потому не подошедший к вашим запросам сервис Amazon AWS никак не отменяет его использование, а всего лишь даёт повод найти подходящий. Ведь сервисы Amazon AWS появились как результат эксплуатации в первую очередь для собственных нужд. В Amazon AWS работают тысячи небольших команд (они их называют two pizza team), каждая из которых вольна выбирать свой собственный способ работы (язык, ОС, структура, протоколы и т.п.), а значит и сервисы, имеющиеся на Amazon AWS изначально должны поддерживать всё многообразие такого зоопарка их эксплуатирующих уже просто внутри самой компании Amazon AWS.
Особенно это важно для Code-сервисов Amazon AWS, которые как раз предназначены не для того, чтобы указывать вам, что нужно использовать, а для того, чтобы дать вам, с одной стороны, возможность интегрироваться с уже привычными, имеющимися и отлаженными вашими процессами и инструментами, с другой, предложить свою собственную реализацию, которая обычно наиболее эффективна в рамках задействования функционала Amazon AWS.

DevOps конструктор Amazon AWS


Даже хорошо понимая каждый кубик в отдельности, далеко не всегда понятно, какой дом из них можно построить. Потому попробуем собрать эти сервисы в одной картинке, чтобы получить общее представление, что можно собрать из такого конструктора. Если выделить Code-сервисы и соотнести их с привычными процессами, то получится примерно такая конструкция:
image

Кратко пройдёмся по каждому из Code-сервисов (подробно далее каждому из них будет посвящена отдельная статья):

AWS CodeCommit


как выглядит
image

Наиболее очевидный и понятный сервис — амазоновская реализация GIT, полностью его повторяющая. Отличий от GIT в плане работы и взаимодействия (команды) нет, нужен по сути для непосредственной интеграции в структуру сервисов AWS, в том числе для организации доступа через сервисы IAM. Сам код хранится на S3.

AWS CodeBuild


как выглядит
image

Сборочный сервер — для проектов, требующих сборки перед развёртыванием, например, Java. По умолчанию запускает контейнер на базе Ubuntu, но можно указать и свой собственный.
Specify a Docker image
image

Поддерживает интеграцию с Jenkins через плагин.
Кроме сборки, аналогично могут быть проведены тесты. И хотя это не основное его назначение, он может быть выбран в качестве такового.
AWS CodeBuild as Test provider
image

Потому AWS CodeBuild также присутствует и на этапе «Test».

AWS CodeDeploy


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

AWS CodePipeline


как выглядит
image

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

Позволяет организовывать ветвления процессов, запускать сторонние сервисы (например, для тестирования), делать параллельные ветки, запрашивать подтверждение (Approval Actions) перед запуском следующего этапа. В общем — это центральный инструмент для организации DevOps на Amazon AWS.

AWS CodeStar


как выглядит
image

Сервис, по сути дублирующий CodePipeline, но заточенный под простоту запуска и настройки, что решается с помощью широкого набора готовых шаблонов (под связку приложение-язык) и действительно удобного Dashboard с плагинами, имеющими некоторую интеграцию с сервисом мониторинга (CloudWatch) и плагином для интеграции с Jira.
Шаблоны AWS CodeStar
image


IaaC-сервисы Amazon AWS


Сервисы Amazon AWS, реализующие концепцию «Инфраструктура как код», это:
  • Elastic Beanstalk
  • OpsWorks
  • CloudFormation

Весьма часто возникают вопросы по поводу того, какой из них выбрать и почему три сервиса предназначены для одного и того же (развёртывание инфраструктуры и приложений), располагаясь в главной диаграмме на стадии Deploy. Если кратко, то их использование можно представить как:
image
То есть для того, чтобы сделать что-то быстро (и это не значит, что плохо), это какой-то стандартный функционал (например, простой сайт) — удобно использовать Elastic Beanstalk. Если это сложный проект с многочисленными вложенными элементами и серьёзными требованиям по сетевым настройкам — без использования CloudFormation не обойтись. Как нечто среднее — представляется использование OpsWorks, базирующегося на Chef.
Однако в реальности (и как раз на сложных проектах обычно используется) комбинация из всех трёх (либо комбинации): CloudFormation поднимает основную инфраструктуру (VPC, подсети, репозитории, создаёт нужные роли в IAM для доступа и т.д.), после запускает OpsWorks-стек, который уже может гибко настроить внутреннюю составляющую запущенных виртуалок. А для удобности процесса разработки CloudFormation может поднять и стек для Elastic Beanstalk компонентов, чтобы разработчики с помощью .ebextensions могли сами менять некоторые параметры работающего приложения (количество и тип используемых виртуалок, использование Load Balancer и т.д.) просто изменяя простой файл конфигурации в папке с кодом, когда применение изменений (в т.ч. в инфраструктуру приложения) происходит автоматически после коммита.

AWS Lambda


image
Отдельно стоит сказать про сервис Lambda, реализующего концепцию ServerLess-архитектуры, который, с одной стороны, аналогично Elastic Beanstalk, можно вписать в DevOps-процесс с помощью использования AWS Code-сервисов. А с другой стороны AWS Lambda — отличное (читай — обязательное) средство автоматизации
всего и вся на Amazon AWS. Все процессы, подразумевающие взаимодействие друг с другом — могут быть связаны с помощью Lambda. Она может обработать и отреагировать на результаты мониторинга CloudWatch, например, перезагрузив сервис (виртуалку, кластер) и послав на почту админу сообщение о проблемах. Она же используется в связи DevOps-процессов, например, для запуска своих способов сборки и тестов с последующей передачей на Deploy в общем порядке. И вообще, с помощью AWS Lambda может быть реализована самая сложная логика, которая пока недоступна с помощью текущего набора сервисов Amazon AWS.

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

Не всё может быть передано визуально, т.к. такие глобальные сущности как сервис управления доступом AWS IAM проникает и присутствует практически во всех составляющих. На базе вычислительных мощностей сервиса EC2 работают все другие сервисы. Сервис хранения данных S3 используется для передачи данных между очень многими другими сервисами. А такие высокоуровневые сервисы как AWS Service Catalog могут давать взаимодействие и, в том числе, между разными аккаунтами Amazon AWS.
Далее, по мере более подробного рассмотрения отдельных сервисов, запутанная и непонятная схема будет вырисовываться в понятный набор инструментов, где каждый сможет подобрать себе нужное.

Итого по общей схеме сервисов Amazon AWS, которые могут быть задействованы в DevOps-процессах. Самая популярная связка это что-то типа: CodePipeline/CodeCommit + ElasticBenstalk/OpsWorks в качестве Deploy. А чтобы «быстро просто глянуть» — хорошо подойдёт CodeStar. Правда AWS CodeStar платный, однако фактор стоимости целенаправленно здесь не учитывался, чтобы сначала дать общее представление о выборе, ведь каждую составляющую можно брать по желанию, в том числе задействуя нужное через плагины популярных CI/CD проектов типа Jenkins сотоварищи.

Ссылки:
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329840/


Метки:  

Никита Липский и Дмитрий Чуйко об AOT в Java на jug.msk.ru

Вторник, 30 Мая 2017 г. 22:20 + в цитатник
Очередная встреча московской Java User Group прошла 22 мая 2017 года традиционно в офисе компании КРОК. На ней Никита Липский и Дмитрий Чуйко рассказали о статической (Ahead-of-Time) компиляции в языке программирования Java и её реализации в продуктах компаний Excelsior и Oracle.



О докладчиках


Никита Липский представляет новосибирскую компанию Excelsior, выпускающую уникальный продукт — статический компилятор для языка Java, Excelsior JET. Приложение вполне востребовано и отлично чувствует себя на рынке, этой осенью будет отмечаться уже 20 лет его существования. Никита является одним из инициаторов создания и активным участником разработки приложения.

Блог компании достаточно интересен: кроме анонсов новых версий (с плагинами для Maven и Gradle) встречается описание и прочих полезных вещей вроде Git-плагина для Far Manager и плагина для IntelliJ IDEA (написанных программистами Excelsior). Судя по опросу, скоро можно ожидать что-то ещё.

Доклады Никиты, упорядоченные в хронологическом порядке:

Аудио с Никитой:

Для ознакомления с Excelsior JET наиболее полезны первые два доклада (совместное выступление Никиты с Павлом Павловым на JUG.ru в 2013 году).

Прочие ссылки: Хабрахабр, GitHub, Twitter, SlideShare.

Дмитрий Чуйко работает в компании Oracle, которая тоже с недавнего времени заинтересовалась статической компиляцией. Является активным докладчиком как конференций JUG.ru, так и прочих.

Доклады Дмитрия:
  • «Новинки в java.util.concurrent» (JUG.ru-2013: видео)
  • «Обзор нововведений в java.util.concurrent (JSR166e)» (JEEConf 2013: презентация, видео)
  • «Java Mission Control» (Java 8 Launch 2014: видео)
  • «Быстрая загрузка ваших классов» (JUG.ru-2015: видео)
  • «CompletableFuture. Хочется взять и применить» (JUG.ru-2015: видео)
  • «CompletableFuture уже здесь» (JPoint 2015: видео)
  • «Completable Future уже здесь» (JEEConf 2015: презентация, видео)
  • «Hotspot и AOT» (JBreak 2016: видео)
  • «Hotspot и AOT: Пришло время компилировать» (JPoint 2016: презентация, видео)
  • «Чёрная метка, StampedLock и его друзья. Как не нарушить пиратский кодекс» (JPoint 2016 Student Day: видео)
  • «Hotspot & AOT» (JEEConf 2016: видео)
  • «Ahead-of-Time компиляция для HotSpot JVM» (JUG.ru-2016: презентация, видео)
  • «Compile ahead of time. It’s fine?» (GeeCON 2017, JEEConf 2017: презентация)

Прочие слайды на SlideShare.

О докладах


Для обоих докладчиков встреча jug.msk.ru стала частью тура выступлений на конференциях. Тур Никиты начался участием его в записи выпуска 134 подкаста Разбор полётов (из аэропорта). Далее были Riga DevDays 2017, GeeCON 2017, jug.msk.ru и Oracle Code 2017 Moscow. Тур Дмитрия включал тоже GeeCON 2017 и jug.msk.ru, далее JEEConf 2017.

Встреча и тема, которой была посвящена встреча (AOT), вызвали большой интерес. В качестве зрителей присутствовали, по крайней мере, пять спикеров конференций, проводимых JUG.ru. Т.е. всего (с учётом Дмитрия и Никиты) была редкая возможность увидеться и пообщаться с семерыми спикерами.

Андрей Когунь вместе с Никитой (первый снимок) и дополнительно Дмитрием (второй снимок) начинает встречу.



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



С выпуском JDK 9 «из коробки» появляется возможность статической компиляции, т.е. преобразования в код целевой платформы (т.н. native). Правда, пока только под Linux. O JEP 295, JEP 243 и компиляторе Graal был рассказ Дмитрия. Доклад был логическим продолжением предыдущего его доклада, представленного ранее на встрече JUG.ru.



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



Презентации докладов встречи: AOT для Java: Мифы и Challenges Никиты и Compile ahead of time. It's fine? Дмитрия. Фотографии со встречи: группа в VK, Google+.

К огромному сожалению, по техническими причинам не удалось записать видео (первый и, будем надеяться, последний раз за историю jug.msk.ru). Видео с предыдущих встреч доступно на YouTube.

Подписка на рассылку анонсов следующих встреч jug.msk.ru.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329728/


Метки:  

ИТ-конференция «Продвижение»: суббота с пользой

Вторник, 30 Мая 2017 г. 19:42 + в цитатник


Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 985 984 [983] 982 981 ..
.. 1 Календарь