Русский
Русский
English
Статистика
Реклама

Блог компании яндекс.деньги

Как стать тимлидом фронтендеров и как жить после этого? Cпросите у Ильи Кашлакова

14.06.2020 14:16:56 | Автор: admin


В понедельник, 15 июня в 20:00 руководитель фронтенд-отдела Яндекс.Денег Илья Кашлаков будет отвечать на ваши вопросы в прямом эфире. Эфир пройдет в нашем инстаграм-аккаунте.

Как задать вопрос и в целом о формате


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

Задать новый вопрос можно в комментариях в инстаграме и прямо под этим постом на Хабре.

О чем Илья расскажет, кроме ответов на ваши вопросы:



  • Все о Node.js
  • Архитектура фронтенда: как строят архитектуру в Яндекс.Деньгах, к каким идеалам хочется стремиться.
  • Как и зачем Яндекс.Деньги переходят на NestJS
  • Как стать тимлидом за 5 лет и почему сам Илья выбрал этот путь. Какие есть плюсы и минусы в работе тимлида
  • Процессы управления людьми в команде: как 52 фронтендера находят общий язык друг с другом.
  • Можно ли обмануть Review 360?
  • Все о Logic Review процессе, который помогает перед разработкой понять, что и как именно надо разрабатывать.
  • Как составлялся список главных 7 софт-скиллов, важных для команды Яндекс.Денег. Разберемся, почему софт скиллз главный двигатель карьеры для фронтендера.
  • Куда идти учиться фронтендеру?


Какие эфиры мы уже провели


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


До встречи в прямом эфире!


Напоминаем дату: 15 июня, 20:00. Чтобы не пропустить, вы можете подписаться на уведомления только от одного аккаунта мы принципиально не присылаем спам.

Это делается очень просто


Подробнее..

Архитектура современных корпоративных Node.js-приложений

11.08.2020 14:11:07 | Автор: admin
Ох, не зря в названии намёк на нетленку Фаулера. И когда фронтенд-приложения успели стать настолько сложными, что мы начали рассуждать о высоких материях? Node.js фронтенд погодите, но Нода же на сервере, это бэкенд, а там ребята и так всё знают!



Давайте по порядку. И сразу небольшой дисклеймер: статья написана по мотивам моего выступления на Я.Субботнике Pro для фронтенд-разработчиков. Если вы занимаетесь бэкендом, то, возможно, ничего нового для себя не откроете. Здесь я попробую обобщить свой опыт фронтендера в крупном энтерпрайзе, объяснить, почему и как мы используем Node.js.

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

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

Можно сказать, что концептуально бэкенд нужен фронтенду для получения и сохранения данных. Пример: типичный современный сайт с клиент-серверной архитектурой. Клиент в браузере (назвать его тонким язык уже не повернётся) стучится на сервер, где крутится бэкенд. И, конечно, везде есть исключения. Есть сложные браузерные приложения, которым не нужен сервер (этот случай мы не будем рассматривать), и есть необходимость исполнения фронтенда на сервере то, что называется Server Side Rendering или SSR. Давайте с него и начнём, потому что это самый простой и понятный случай.

SSR


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

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

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

Получается, когда нужна реализация SSR силами бэкенд-разработки:

  1. Смешиваются зоны ответственности. Бэкенд-программисты начинают отвечать за отображение.
  2. Смешиваются языки. Бэкенд-программисты начинают работать с JavaScript.

Выход отделить SSR от бэкенда. В простейшем случае мы берём JavaScript runtime, ставим на него самописное решение или фреймворк (Next, Nuxt и т.д.), работающий с нужным нам JavaScript-шаблонизатором, и пропускаем через него трафик. Привычная схема в современном мире.

Так мы уже немножко пустили фронтенд-разработчиков на сервер. Давайте перейдём к более важной проблеме.

Получение данных


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

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

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

Во-вторых, проблема избыточных/недостаточных данных. Давайте посмотрим, что происходит, когда два разных фронтенда используют один универсальный API.


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



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

В таком случае нам не подойдёт универсальный API, придётся разделить интерфейсы. Значит, потребуется свой API Gateway под каждый фронтенд. Слово каждый здесь обозначает уникальное отображение, работающее со своим набором данных.


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

Такая архитектура называется Backend For Frontend или BFF. Идея проста: на сервере появляется новое приложение, которое слушает запросы клиента, опрашивает бэкенды и возвращает оптимальный ответ. И, конечно же, это приложение контролирует фронтенд-разработчик.



Больше одного сервера в бэкенде? Не проблема!


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

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

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

Можно, конечно, но неинтересно (для фронтендера)

Что же, давайте реализовывать BFF. Конечно, на Node.js. Почему? Нам нужен единый язык на клиенте и сервере для переиспользования опыта фронтенд-разработчиков и JavaScript для работы с шаблонами. А как насчёт других сред исполнения?



GraalVM и прочие экзотические решения проигрывают V8 в производительности и слишком специфичны. Deno пока остаётся экспериментом и не используется в продакшене.

И ещё один момент. Node.js удивительно хорошее решение для реализации API Gateway. Архитектура Ноды позволяет использовать однопоточный интерпретатор JavaScript, объединённый с libuv, библиотекой асинхронного I/O, которая, в свою очередь, использует тред-пул.



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

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

Где хранить бизнес-логику


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


Конечно, архитектор не хочет размазывать бизнес-правила по всем слоям системы, источник правды должен быть один. И этот источник бэкенд. Где ещё хранить высокоуровневые политики, как не в наиболее близкой к данным части системы?



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



Можем ли мы получить идеальную архитектуру, отказавшись от BFF в пользу полноценного бэкенда на Node.js? Кажется, в этом случае не будет протечек.


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


Как бы мы ни старались, бизнес-логика проникнет в API Gateway на Node.js. Зафиксируем этот вывод и перейдём к самому вкусному имплементации!

Big Ball of Mud


Самое популярное решение для Node.js-приложений в последние годы Express. Проверенное, но уж больно низкоуровневое и не предлагающее хороших архитектурных подходов. Основной паттерн middleware. Типичное приложение на Express напоминает большой комок грязи (это не обзывательство, а антипаттерн).

const express = require('express');const app = express();const {createReadStream} = require('fs');const path = require('path');const Joi = require('joi');app.use(express.json());const schema = {id: Joi.number().required() };app.get('/example/:id', (req, res) => {    const result = Joi.validate(req.params, schema);    if (result.error) {        res.status(400).send(result.error.toString()).end();        return;    }    const stream = createReadStream( path.join('..', path.sep, `example${req.params.id}.js`));    stream        .on('open', () => {stream.pipe(res)})        .on('error', (error) => {res.end(error.toString())})});

Все слои перемешаны, в одном файле находится контроллер, где есть всё: инфраструктурная логика, валидация, бизнес-логика. Работать с этим больно, поддерживать такой код не хочется. А можем ли мы писать на Node.js код энтерпрайз-уровня?


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

Архитектура Node.js-приложения (наконец-то)


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

Роберт Дядя Боб Мартин

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

Слои


Как разбить приложение на слои? Есть классический трёхуровневый подход: данные, логика, представление.



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

Более современный подход предполагает, что в приложении выделен доменный слой, который работает с бизнес-логикой и является представлением реальных бизнес-процессов в коде. Однако если мы обратимся к классическому труду Эрика Эванса Domain-Driven Design, то обнаружим там такую схему слоёв приложения:


Что здесь не так? Казалось бы, основой приложения, спроектированного по DDD, должен быть домен высокоуровневые политики, самая важная и ценная логика. Но под этим слоем лежит вся инфраструктура: слой доступа к данным (DAL), логирование, мониторинг, и т. д. То есть политики гораздо более низкого уровня и меньшей важности.

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



Если мы снова обратимся к Роберту Мартину, то обнаружим, что в книге Clean Architecture он постулирует иную иерархию слоёв в приложении, с доменом в центре.



Соответственно, все четыре слоя должны располагаться иначе:



Мы выделили слои и определили их иерархию. Теперь перейдём к связям.

Связи


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


Теперь высокоуровневый UserEntity не зависит от низкоуровневого Logger. Наоборот, он диктует контракт, который нужно реализовать, чтобы включить Logger в систему. Замена логгера в данном случае сводится к подключению новой реализации, соблюдающей тот же контракт. Важный вопрос как её подключать?

import {Logger} from ../core/logger;class UserEntity { private _logger: Logger;constructor() {this._logger = new Logger();}...}...const UserEntity = new UserEntity();

Слои связаны жёстко. Есть завязка и на файловую структуру, и на реализацию. Нам нужна инверсия зависимости (Dependency Inversion), делать которую мы будем с помощью внедрения зависимости (Dependency Injection).

export class UserEntity {constructor(private _logger: ILogger) { }...}...const logger = new Logger();const UserEntity = new UserEntity(logger);

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

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

Как может выглядеть использование контейнера? Например, так:

export class UserEntity {constructor(@Inject(LOGGER) private readonly _logger: ILogger){ }}

Что здесь происходит? Мы воспользовались магией декораторов и написали инструкцию: При создании экземпляра UserEntity внедри в его приватное поле _logger экземпляр той сущности, что лежит в IoC-контейнере под токеном LOGGER. Ожидается, что она соответствует интерфейсу ILogger. А дальше IoC-контейнер сделает всё сам.

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

Фреймворки и архитектура


Вопрос простой: уйдя от Express на современный фреймворк, получим ли мы хорошую архитектуру? Давайте посмотрим на Nest:

  • написан на TypeScript,
  • построен поверх Express/Fastify, есть совместимость на уровне middleware,
  • декларирует модульность логики,
  • предоставляет IoC-контейнер.

Кажется, здесь есть всё, что нам нужно! Ещё и от концепции приложения как цепочки middleware ушли. Но что насчёт хорошей архитектуры?

Dependency Injection в Nest


Давайте попробуем сделать всё по инструкции. Так как в Nest термин Entity применяется обычно к ORM, переименуем UserEntity в UserService. Логгер поставляется фреймворком, поэтому вместо него заинжектируем абстрактный FooService.

import {FooService} from ../services/foo.service;@Injectable()export class UserService {constructor(            private readonly _fooService: FooService   ){ }}

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

Давайте попробуем исправить. Вариант номер один:

@Injectable()export class UserService {constructor(            private _fooService: AbstractFooService   ){ } }

Где-то рядом описываем и экспортируем этот абстрактный сервис:

export {AbstractFooService};

FooService теперь использует AbstractFooService. В таком виде мы регистрируем его вручную в IoC.

{ provide: AbstractFooService, useClass: FooService }

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

@Injectable()export class UserService {constructor(            @Inject(FOO_SERVICE) private readonly _fooService: IFooService   ){ } }

И регистрируем по токену:

{ provide: FOO_SERVICE, useClass: FooService }

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

Исключения


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



Всё ли тут в порядке с точки зрения архитектуры? Снова обратимся к корифеям:

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

Исключения предполагают исключительную ситуацию. При написании бизнес-логики мы должны избегать выбрасывания исключений. Хотя бы по той причине, что ни JavaScript, ни TypeScript не дают гарантий, что исключение будет обработано. Более того, оно запутывает поток исполнения, мы начинаем программировать в GOTO-стиле, а значит, во время исследования поведения кода читателю придётся прыгать по всей программе.



Есть простое правило, помогающее понять, законно ли использование исключений:

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

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

const successResult = Result.ok(false);const failResult = Result.fail(new ConnectionError())

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

Давайте проверим.

Сущности Nest и архитектурные слои


Суровая правда жизни: всё, что мы пишем с помощью Nest, можно уложить в один слой. Это Application Layer.



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



Фреймворк это деталь.
Роберт Дядя Боб Мартин



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



Реально ли реализовать такую архитектуру на Node.js, используя Nest как основу? Вполне. Я сделал урок с примером, если интересно ознакомиться можно по ссылке.

Подведём итоги


  • Node.js это хорошо для BFF. С ней можно жить.
  • Готовых решений нет.
  • Фреймворки не важны.
  • Если ваша архитектура становится слишком сложной, если вы упираетесь в типизацию возможно, выбран не тот инструмент.

Рекомендую эти книги:

Подробнее..

Токенизация карт в E-commerce что это такое и как работает?

03.07.2020 12:17:33 | Автор: admin

Всем привет! Недавно мы в Яндекс.Кассе совместно с платежными системами Visa и Mastercard запустили новую технологию токенизации платежей для E-commerce, или, по-другому, онлайн-коммерции. Кто-то может подумать: что тут такого с токенизацией карт разобрались уже с выходом Apple Pay, Google Pay и других *Pay. Но нет, тут что-то новенькое, а мы еще и первыми эту технологию запустили в России этой весной для магазинов-партнеров, так что почему бы не поделиться.


В США и Европе эта технология появилась несколько раньше, и пользователи таких сервисов, как Netflix и Amazon, уже платят E-commerce токенами, хотя, возможно, даже не знают об этом. А я сейчас расскажу, как это устроено не только снаружи (для партнеров и держателей карт), но и изнутри, с точки зрения разработчика и тимлида этого проекта. Если интересно велкам под кат.



Что общего с Apple Pay и Google Pay

Те читатели, которые представляют, как работают Apple Pay и Google Pay (а кто не знает вот наша статья про запуск *Pay), увидят тут знакомые слова.

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

Пока запомним эти особенности токенизации карт на устройствах пользователей:

  • платить токеном может только тот, кто этот токен создал,
  • управлять токеном можно отдельно и независимо от управления банковской картой.

Запомнили? А теперь перейдем к токенизации карт для E-commerce, иначе говоря, для онлайн-платежей в интернет-магазинах.

Итак, что такое токенизация в E-commerce

Вообще, токенизация карты это обмен конфиденциальных данных банковской карты на специальный токен, который позволяет оплачивать покупки с помощью этой карты.
Конфиденциальные данные карты это ее номер (PAN Primary Account Number) и срок действия.

Если для подключения карты в *Pay инициатором является сам держатель карты, то токенизацию для E-commerce инициирует интернет-магазин. Но зачем (и с какой стати)?

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

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

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

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

Давайте обо всем по порядку. При токенизации мы обмениваем данные банковской карты на некий токен, но что это такое? Токен предоставляется платежной системой карты Mastercard или Visa. Он представляет собой уникальный идентификатор, аналогичный номеру учетной записи устройства в Apple Pay или номеру виртуального счета в Google Pay, которые можно найти в приложении на смартфоне (Wallet на устройствах Apple и Google Pay на Android).

В отличие от *Pay, в E-commerce токенизации создание токена инициирует интернет-магазин или его платежное решение, а сами токены хранятся на серверах платежных систем.

Разумеется, кто угодно не может прийти к платежной системе и получить токен чьей-либо карты для оплаты покупок. Во-первых, токенизировать карты могут только те платежные решения, которые пройдут сертификацию и получат одобрение платежных систем. Такое платежное решение называется On-Behalf Token Requestor или Token Service Provider, но для простоты будем впредь оперировать термином Token Requestor. И только Token Requestor может инициировать платежи токеном. Во-вторых, токен всегда выпускается для конкретного магазина, и с помощью токена можно платить только в этом магазине. Очень похоже на то, как токен *Pay связан с устройством, на котором он был создан.

За счет чего это достигается? Просто перед проведением каждого платежа по токену Token Requestor должен получить одобрение у платежной системы на этот платеж. Факт такого одобрения надо будет предъявить во время фактического проведения платежа, поэтому одобрение это имеет форму одноразовой криптограммы, которую формирует платежная система карты. При проведении платежа эта криптограмма добавляется к параметрам запроса в банк-эквайер и затем передается платежной системе, которая проверяет подлинность этой криптограммы, которую сама ранее выдавала.

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

Подведем некоторый итог. Что токенизация дает держателю карты?

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

Что это дает интернет-магазинам?

  1. То, что хорошо для покупателя, хорошо и для магазина, поэтому использование токенизированных карт может повысить лояльность клиентов.
  2. Возможность перевыпуска банковской карты с сохранением токена важна для магазинов, использующих сценарии платежей по подписке. Магазину больше не нужно будет отключать подписку, если пользователь забыл обновить данные карты, и не придется всячески напоминать ему об этом. Стоит отметить, что у держателя карты все равно остается полный контроль и в любой момент он сможет отключить саму подписку.
  3. Повышение конверсии платежей. Мы исследовали, как использование токенов влияет на конверсию платежей в сравнении с использованием сохраненных данных карт. Выяснилось, что доля успешных платежей без использования токенов была 88,53%, а после включения токенизации выросла до 97,89%*. Получившаяся разница объясняется тем, что если банк-эмитент уже одобрил создание токена, то в дальнейшем платежи этим токеном будут вызывать большее доверие у антифрод-системы банка. На конверсию влияет также возможность оплаты перевыпущенными картами. Если человек не обновит данные карты, которую он привязал к интернет-магазину, то оплата не пройдет, а с токеном такой проблемы не возникнет.

*Мы сравнивали платежи за этот апрель в крупном онлайн-кинотеатре (MCC 4899) привязанными картами без 3DS, без учета неуспешных платежей из-за нехватки денег на карте.

Технические аспекты

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

Интеграция с платежными системами

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

Интеграция подразумевает реализацию следующего API (условно) между платежной системой и нами в качестве Token Requestor:

  1. Создание токена.
    Мы передаем платежной системе данные банковской карты и идентификатор интернет-магазина, для которого создается токен. Дополнительно мы проводим скоринг для оценки рисков (risk scoring) токенизации конкретной карты для конкретного магазина и также передаем результат скоринга в запросе. В ответ мы получаем решение, одобрена токенизация карты ее эмитентом или нет, и если одобрена, получаем уникальный идентификатор созданного токена. После этого токен активен, можно проводить платежи с его использованием.
  2. Получение одноразовой криптограммы для платежа токеном.
    Мало обладать токеном, чтобы им платить: для каждого платежа нужно еще получить одобрение от платежной системы криптограмма, помните? Так вот, чтобы получить эту криптограмму, мы передаем в запросе платежной системе идентификатор токена и некоторые детали платежа. Если токен активен, мы в ответе получаем эту одноразовую криптограмму, которую затем надо будет передать эквайеру при проведении платежа по карте.
  3. Уведомление от платежной системы об изменении состояния токена.
    Это может быть приостановка/возобновление действия токена по инициативе держателя карты, удаление этого токена навсегда, а также обновление данных банковской карты, для которой был выпущен этот токен, в случае ее перевыпуска. Нам нужно уметь обрабатывать определенные запросы от платежных систем и обновлять у себя информацию о токене, проще простого.

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

Токенизация в Яндекс.Кассе

Яндекс.Касса представляет из себя большую систему по приему платежей для интернет-магазинов. Она состоит из многих десятков различных сервисов: backend-, frontend-приложения, BI-сервисы. Они обеспечивают прием платежа пользователя различными способами, перевод денежных средств магазину, управление платежами через личный кабинет магазина, аналитические сервисы и тому подобное. И как именно сюда встроилась токенизация карт?

Главный вопрос: в какой момент создавать токен для банковской карты?
В API Яндекс.Кассы есть возможность сохранять выбранный способ оплаты для последующих платежей в будущем, мы это называем автоплатежи.

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

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

Что же сами платежные системы делают в момент токенизации карты?
Они обращаются в банк-эмитент, с запросом на создание токена (как это происходит и при создании токенов *Pay), и банк выпускает токен для данного магазина. Банк также может уведомить об этом держателя карты и отобразить созданный токен в его личном кабинете.

Как происходит платеж токеном?

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



Итак, при платеже ранее сохраненным способом магазин передает только его идентификатор payment_method_id. По этому идентификатору сервис платежей картами находит данные (PAN и срок действия) карты и передает их одному из банков-эквайеров, который далее общается с платежной системой карты.

С токенами в этом сценарии добавляется еще один шаг:



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

А что происходит в сценарии, когда пользователь перевыпускает карту в своем банке?
Если к карте ранее были выпущены токены, то банк-эмитент сообщает в платежную систему Mastercard/Visa, что карта перевыпущена. В свою очередь, каждый Token Requestor, который выпускал токены к этой карте, получит уведомление от платежной системы. Оно содержит обновленную информацию о карте: последние 4 цифры номера и новый срок действия. Токен при этом остается прежним.

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

Вместо заключения

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

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

Я всё, будьте здоровы и не болейте!
Подробнее..

Конфигурация многомодульных проектов

26.08.2020 14:06:49 | Автор: admin

Предыстория


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

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

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



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


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

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

Скорее всего, вы уже видели такой код в проекте. В нем нет никакой магии, это просто одно из расширений Gradle под названием ExtraPropertiesExtension. Если кратко, то это просто Map<String, Object>, доступный по имени ext в объектe project, а все остальное работа как будто с объектом, блоки конфигурации и прочее магия Gradle. Примеры:
.gradle .gradle.kts
// creationext {  dagger = '2.25.3'  fabric = '1.25.4'  mindk = 17}// usageprintln(dagger)println(fabric)println(mindk)

// creationval dagger by extra { "2.25.3" }val fabric by extra { "1.25.4" }val minSdk by extra { 17 }// usageval dagger: String by extra.propertiesval fabric: String by extra.propertiesval minSdk: Int by extra.properties


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

Кстати, подобного эффекта можно добиться, используя gradle.properties вместо ExtraPropertiesExtension, только будьте осторожны: ваши версии можно будет переопределить при сборке с помощью -P флагов, а если вы обращаетесь к переменной просто по имени в groovy-cкриптах, то gradle.properties заменят и их. Пример с gradle.properties и переопределением:

// grdle.propertiesoverriden=2// build.gradleext.dagger = 1ext.overriden = 1// module/build.gradleprintln(rootProject.ext.dagger)   // 1println(dagger)                   // 1println(rootProject.ext.overriden)// 1println(overriden)                // 2

Вторая итерация project.subprojects


Моя любознательность, помноноженная на нежелание копировать код и разбираться с настройкой каждого модуля, привела меня к следующему шагу: я вспомнил, что в корневом build.gradle есть блок, который генерируется по умолчанию allprojects.

allprojects {    repositories {        google()        jcenter()    }}

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

Пример конфигурации модулей через project.subprojects
subprojects { project ->    afterEvaluate {        final boolean isAndroidProject =            (project.pluginManager.hasPlugin('com.android.application') ||                project.pluginManager.hasPlugin('com.android.library'))        if (isAndroidProject) {            apply plugin: 'kotlin-android'            apply plugin: 'kotlin-android-extensions'            apply plugin: 'kotlin-kapt'                        android {                compileSdkVersion rootProject.ext.compileSdkVersion                                defaultConfig {                    minSdkVersion rootProject.ext.minSdkVersion                    targetSdkVersion rootProject.ext.targetSdkVersion                                        vectorDrawables.useSupportLibrary = true                }                compileOptions {                    encoding 'UTF-8'                    sourceCompatibility JavaVersion.VERSION_1_8                    targetCompatibility JavaVersion.VERSION_1_8                }                androidExtensions {                    experimental = true                }            }        }        dependencies {            if (isAndroidProject) {                // android dependencies here            }                        // all subprojects dependencies here        }        project.tasks            .withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile)            .all {                kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString()            }    }}


Теперь для любого модуля с подключенным плагином com.android.application или com.android.library мы можем настраивать что угодно: подключаемые плагины, конфигурации плагинов, зависимости.

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

Третья итерация buildSrc и plugin


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

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

Код плагина
import org.gradle.api.JavaVersionimport org.gradle.api.Pluginimport org.gradle.api.Projectclass ModulePlugin implements Plugin<Project> {    @Override    void apply(Project target) {        target.pluginManager.apply("com.android.library")        target.pluginManager.apply("kotlin-android")        target.pluginManager.apply("kotlin-android-extensions")        target.pluginManager.apply("kotlin-kapt")        target.android {            compileSdkVersion Versions.sdk.compile            defaultConfig {                minSdkVersion Versions.sdk.min                targetSdkVersion Versions.sdk.target                javaCompileOptions {                    annotationProcessorOptions {                        arguments << ["dagger.gradle.incremental": "true"]                    }                }            }            // resources prefix: modulename_            resourcePrefix "${target.name.replace("-", "_")}_"            lintOptions {                baseline "lint-baseline.xml"            }            compileOptions {                encoding 'UTF-8'                sourceCompatibility JavaVersion.VERSION_1_8                targetCompatibility JavaVersion.VERSION_1_8            }            testOptions {                unitTests {                    returnDefaultValues true                    includeAndroidResources true                }            }        }        target.repositories {            google()            mavenCentral()            jcenter()                        // add other repositories here        }        target.dependencies {            implementation Dependencies.dagger.dagger            implementation Dependencies.dagger.android            kapt Dependencies.dagger.compiler            kapt Dependencies.dagger.androidProcessor            testImplementation Dependencies.test.junit                        // add other dependencies here        }    }}


Теперь конфигурация нового проекта выглядит как applyplugin:ru.yandex.money.module и все. Можно вносить свои дополнения в блок android или dependencies, можно добавлять плагины или настраивать их, но главное, что новый модуль конфигурируется одной строкой, а его конфигурация всегда актуальна и продуктовому разработчику больше не надо думать про настройку.

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

Важный момент: если вы используете android gradle plugin ниже 4.0, то некоторые вещи очень сложно сделать в kotlin-скриптах по крайней мере, блок android проще конфигурировать в groovy-скриптах. Там есть проблема с тем, что некоторые типы недоступны при компиляции, а groovy динамически типизированный, и ему это не важно =)

Дальше standalone plugin или монорепо


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

Первый вариант standalone plugin для gradle. После третьего шага это уже не так сложно: надо создать отдельный проект, перенести туда код и настроить публикацию.

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

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

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

Итого


В новом проекте делай сразу третий шаг buildSrc и plugin проще будет всем, тем более, что код я приложил. А второй шаг project.subprojects используй для того, чтобы подключать общие модули между собой.

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

Recovery mode Сила дашбордов

30.09.2020 18:23:32 | Автор: admin

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

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

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

Слева - дашборд автомобиля, справа - информационный дашборд в ITСлева - дашборд автомобиля, справа - информационный дашборд в IT

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

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

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

Определение дашборда

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

Еще важно разделять дашборды по типам. Я предлагаю учитывать только два:

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

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

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

Наш первый дашборд

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

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

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

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

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

После того, как Autorun берет в работу тикет в Jira, ему нужно выделить отдельный стенд для запуска. Это позволит не прогонять на одном стенде одновременно несколько тестов и заблокировать другой стенд, на котором уже проводятся работы. Для этого у нас есть инструмент под названием Locker.

Autorun обращается к этому инструменту, чтобы получить схему. У Locker тоже есть UI. То есть стенд может быть заблокирован или доступен, и с каким-то комментарием. Если есть комментарий, стенд блокируется.

После того, как Autorun сходит к Locker, он обращается к еще одному инструменту Pinger, чтобы понять, насколько схема живая. С точки зрения UI-интерфейса, Pinger это тоже мини-дашборд, на котором представлены все наши сервисы и их статусы: зеленые, если всё в порядке, или красные, если что-то не так. Autorun через API запрашивает у сервиса информацию. Если стенд не в порядке, он сообщает нам об этом и не запускает на нем тесты.

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

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

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

Что представляла из себя самая важная информация? Из Jira мы брали только количество задач в каждом из статусов, из Pinger только красные компоненты, из Locker статусы схем и пояснение причины лока. То есть фактически мы ничего нового не изобрели, просто сделали общий UI и назвали его дашборд дежурного, а пользу он принес большую. Скорость понимания того, что происходит, увеличилась в разы. Мы вывели этот дашборд на телевизор в кабинете, и теперь на вопрос, что сейчас происходит, может ответить даже человек, который случайно зашел в кабинет. И для этого ему не надо проводить никаких манипуляций с остальными инструментами.

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

Он значит, что со всеми стендами все отлично, новых задач нет и можно идти на обед

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

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

На самом деле, для построения дашбордов есть множество решений, но некоторые из них входят в целые BI-платформы наподобие ClickView, а некоторые облачные решения, например Google Data Studio, нам не подходят. А Grafana у нас уже была и использовалась в команде мониторинга.

На всякий случай повторю, что такое Grafana.

Это инструмент для построения дашбордов на основе различных источников от PostgreSQL до Google Sheets. В нашем случае источником был Graphite. Чем он нам был удобен? У нас не было готового хранилища знаний, где лежали бы все нужные данные. Мы сами пушим данные. Соответственно, Graphite удобное хранилище для таких временных метрик.

Как происходит отсылка этих метрик? В формате StatsD мы отправляем их в Telegraf. Формат такой: название метрики, ее тип и значение. Telegraf за 30 секунд агрегирует метрики в зависимости от типа, который мы передали, и потом отсылает их в хранилище Graphite.

На самом деле, мы даже не особо переживаем и отправляем метрики по UDP, потому что на каждом нашем хосте есть инстанс Telegraf и до него 100% дойдет. Плюс у нас не настолько критичные технические метрики, которые мы отображаем в дашбордах, чтобы переживать, если они не дойдут.

Метрики StatsD бывают четырех типов, которые покрывают полную потребность:

  • g (Gauge) в течение 30 секунд Telegraf отправляет только значение последней метрики, которую получил;

  • с (Count) все полученные за интервал данные будут сложены, то есть Telegraf суммирует все, что к нему пришло;

  • s (Set) отправляет уникальные значения, пришедшие за это время;

  • ms (Timer) отправляет множество разных метрик по таймеру (среднее время выполнения, count, max, min и т.д.).

Сами метрики отсылаются так же просто. Если у вас Java, Java StatsD Client в нем создаем сам клиент и через него отправляем метрики. Всё. Отправку из Java мы используем как раз в наших инструментах, содержащих данные, которые надо отослать. То есть Autorun может отправить данные о количестве пришедших задач. Состояние схем может отправлять Pinger.

import com.timgroup.statsd.StatsDClient;import com.timgroup.statsd.NonBlockingStatsDClient;public class Foo {private static final StatsDClient statsd =         new NonBlockingStatsDClient("my.prefix", "statsd-host", 8125);    public static final void main(String[] args) {    statsd.incrementCounter("bar");    statsd.recordGaugeValue("baz", 100);    statsd.recordExecutionTime("bag", 25);    }    }

https://github.com/tim-group/java-statsd-client

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

echo "my.prefix.bar:1|c" | nc -w 0 -u statsd-host 8125echo "my.prefix.baz:25|g" | nc -w 0 -u statsd-host 8125

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

Дашборд визуализатор метрик

Самым первым у нас был дашборд по метрикам нашей команды. Так как основной процесс у нас это интеграционное тестирование, мы взяли метрики, относящиеся к этому процессу:

  • количество релизов;

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

  • поломанные релизы, в которых была найдена ошибка;

  • пропущенные релизы, для которых была проверена только корректность развертывания сборки в тестовой среде (тестов нет).

Мы решили посмотреть, что будет, если построить такой дашборд и смотреть на него каждый день. Какие плюсы мы от этого получили?

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

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

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

Дашборд мотиватор

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

Мы проверили, насколько дашборд может быть реальным инструментом для мотивации. И нашли проблему, где нам не хватает мотивации в проведении code review. Самописный бот назначает ревьюеров, коллег из моей команды, и мы проводим ревью тестов и наших инструментов для автоматизации. При этом ревьюер не один, иногда даже не два, а одного approve обычно достаточно. То есть если один человек поставил approve, значит, все хорошо. Тут может получиться так, что кто-то вообще никогда не ревьюит и надеется, что это сделают другие. Чтобы это понять, мы построили дашборд и посмотрели, что изменилось.

Дашборд по активностям на ревьюДашборд по активностям на ревью

Новый дашборд показывал активности ревьюеров: comments, approve, needs work. Такая визуализация меня сильно замотивировала. Я желтенький. По рисунку видно, что я более-менее часто ставлю approve, но, например, комментирую не так много. После этого я старался ревьюить активнее.

Если раньше у нас б в pull request чаще всего стоял один approve, то сейчас более чем в 90% случаях он стоит как минимум от двух человек. И это не случайные approve раз один поставил, то и я тоже, а осознанные.

Дашборд для анализа

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

Лично я больше всего люблю анализировать время выполнения тестов. Иногда кажется: Ага, у нас тесты что-то очень долго выполняются Но как понять на самом деле, долго они выполняются или нет, если ты не знаешь, как они выполнялись вчера, позавчера или в течение года и как это соотносится с количеством тестов? На этот вопрос также сложно ответить без визуализации.

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

Анализ времени выполнения тестовАнализ времени выполнения тестов

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

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

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

Дашборд для экономии времени

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

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

Либо увидеть, что все плохо, сильно расстроиться и идти разбираться, почему так случилось.

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

Небольшое резюме

При внедрении дашборда мы получаем:

  • инструмент для объективной оценки происходящего,

  • экономию времени при анализе,

  • дополнительную мотивацию,

  • новую информацию, которая раньше была незаметна,

  • множество данных для анализа в будущем.

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

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

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

Подробнее..

В чём сила дашбордов, как тестировать JS-библиотеки и чего стоит выпустить собственный фреймворк в open source

04.07.2020 12:05:52 | Автор: admin
Пост посвящается всем, кто виртуально не добрался до нашего онлайн-митапа, который мы посвятили инструментам автоматического тестирования. Без лишних слов публикуем видео с BugsBusters 2020 смотрите прямо сейчас, будет хорошее начало выходных.



Сила дашбордов

Егор Иванов, специалист по автоматизации тестирования (Яндекс.Деньги)

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


Таймкоды
0:55 Каким специалистам будет полезен доклад
1:10 Что такое дашборд? Примеры из жизни. Определение термина, основные типы.
4:05 Знакомство с командой интеграционного тестирования. Схема взаимодействия инструментов: Jira, Autorun, Locker, Pinger, Jenkins
7:32 Что делать, когда что-то идет не так роль дежурного
8:15 Дашборд дежурного: мастштабирование задач, использование Grafana
11:26 Как происходит отсылка метрик. Типы метрик.
13:09 Процесс отправки метрик из Java и sh
14:10 Как построить дашборд? Как можно использовать дашборды?
15:00 Пример 1 дашборд как визуализатор метрик
18:20 Пример 2 дашборд как мотиватор
22:18 Пример 3 дашборд для анализа
24:45 Пример 4 дашборд для экономии времени
27:00 Подведение итогов: что мы получили от внедрения дашбордов



Святой Грааль автоматизации: не можешь найти создай сам

Андрей Ганин, QA Head (Альфа-Банк)

Кажется, выбор инструментов для автоматизации огромный ровно до тех пор, пока вам не понадобятся E2E-тесты на C#. Я расскажу о том, как мы создавали собственный фреймворк: о трудностях, несбывшихся надеждах и тонкостях выпуска внутреннего продукта в open source.


Таймкоды
1:30 О чем пойдет речь в докладе?
2:20 Предыстория: как Альфа-банк задумался о сокращении времени на проверку внутренних продуктов.
3:32 Выявление основной проблемы отсутствии документации.
4:21 Итоги первой реализации фреймворка
5:28 Описание второй итерации. SpecFlow. Итоги второй реализации
8:32 What if?.. Создание инструмента, который мог бы безошибочно и без установки дополнительного ПО создавать автотесты.
9:20 Схема взаимодействия внутренний инструментов AFT Desk
10:58 А зачем это всё?
13:35 Разделение тестов с фреймворком. Как это происходит внутри?
16:31 Глобальное изменение: прекращение Microsoft развития фреймворка Net Framework. Переход на Net Standard
18:20 Как изменился процесс после перехода. Плюсы и минусы
20:57 Применимость фреймворка. Примеры. Паттерны Page Object
23:11 Как использовать технологии?
24:17 Как выглядит релиз новой версии в Open Source. Различия с внутренним решением
26:44 Выводы: зачем использовать фреймворк и кому это может пригодится? Планы развития



Как мы тестируем виджет Яндекс.Кассы

Дмитрий Сергиенко, старший тестировщик (Яндекс.Деньги)
Виджет Яндекс.Кассы это JS-библиотека, которая работает через iframe. Расскажу о своём опыте тестирования и о нашем инструменте WidgetRunner.


Таймкоды:
0:32 Как тестировать JS-библиотеку?
0:54 Виджет Яндекс.Кассы: что это такое.
2:45 Почему мы решили использовать iframe
3:04 Как же это все тестировать? Первый вариант (статичный html-файл), его минусы.
3:45 О платежном токене: что это и как его получить.
5:01 Почему 1 подход не сработал? Следующие подходы
6:09 Почему плохо тестировать только форму оплаты?
7:48 Требования к инструменту тестирования
8:40 WidgetRunner как работает инструмент и его функциональность
11:52 Выводы: что получили с внедрением инструмента WidgetRunner



Наш первый митап в онлайне прошел круто и драйвово: чуть больше 200 слушаталей в прямом эфире! А под конец мы еще и подарочные сертификаты разыграли в викторине участники остались довольными.

P.S. Скоро откроем регистрацию на Android-митап, на котором затронем темы мобильного тестирования. Следите за новостями!
Подробнее..

Дата-инженеры в бизнесе кто они и чем занимаются?

15.07.2020 16:21:33 | Автор: admin
Данные один из активов организации. Поэтому вполне вероятно, что перед вашей командой в какой-то момент могут возникнуть задачи, которые можно будет решить, используя эти данные разными способами, начиная с простых исследований и вплоть до применения алгоритмов машинного обучения.

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

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



Какие роли есть в Data Science-проекте?

Существуют разные подходы к делению сфер ответственности в команде, которая занимается DS-проектами.
К сожалению, не для всех названий ролей есть аналоги в русском языке. Если у вас в компании есть устоявшееся русское название, например, для Data Ingest, то поделитесь им в комментариях.
Например, можно выделить следующие роли:

  • Data Scientist тот человек, который непосредственно делает модели машинного обучения,
  • Data Ingest отвечает за загрузку данных, разрабатывает ETL-пакеты,
  • Data Steward тот, кто следит за качеством этих данных,
  • Data DevOps примерно как девопс, но с упором на процессы, связанные с загрузкой и обработкой данных,
  • Специалист в Information Security отвечает за безопасность исследуемых данных, доступы, и т.д.
  • и др.

Задачи, которыми занимается дата-инженеры, примерно относятся к Data DevOps, Steward и Ingest.

Что такое Data Science-проект?

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

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



Сам график с количеством не требует дата-сайенса, но уже требует дата-инженерии.

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

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

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

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

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

Порядок действий в DS-проекте

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

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

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


В проектах, которыми мы занимались, один такой круг занимал по времени около 1,5-2 недель.

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

Теперь рассмотрим этот процесс подробнее.

Сбор датасета

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

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

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

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

  1. авторизация в личном кабинете,
  2. сбор реквизитов,
  3. авторизация карты,
  4. зачисление денег в систему,
  5. перевод на счет получателя,
  6. уведомление получателя,
  7. клиринг и т.д.

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

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

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

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

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

Составление корректного датасета состоит из следующих этапов:

  • интеграция,
  • очистка,
  • разметка,
  • расчет фич,
  • актуализация.

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

  1. Нужно прочитать все данные топики, в которых содержится то, из чего мы будем составлять датасет. В зависимости от архитектуры приложений одно и то же событие может записываться в брокер событий по-разному: at-least-once, exactly-once (at-most-once не рассматриваем, так как строить аналитику на таких данных не слишком надежно). Так вот в случае at least once залитые в Kafka данные требуется отфильтровать (например, избавиться от дублей одной записи) и оставить только те события, которые реально нужно рассматривать.
  2. Если разные части нашего будущего датасета пишутся в разные топики, то данные, прочитанные из разных топиков, следует объединить между собой. Часто для этого нужно, чтобы в записях разных топиков были общий идентификатор.
  3. Из текстовых данных нужно получить числовые значения, которые в последующем мы будем анализировать.


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

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

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


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

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

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

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

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

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

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

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

Только после этого дата-инженер передает эстафету (вместе с датасетом) дата-сайентисту.

А дальше

Что же делает дата-сайентист?

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

В этой статье я не буду детально затрагивать вопрос выбора модели. Но для тех, кто только начинает работать с ML, отмечу, что есть множество подходов к выбору модели.
Например, такие:
  1. Применить экспертные знания это тот случай, когда вы знаете, какая модель в каком случае работает. Например, если у вас антифрод, то скорее всего вам нужна какая-то из моделей классификации. А если рекомендательная система, то применить коллаборативную фильтрацию. Если таких знаний нет, то можно пойти куда-нибудь, где эти модели перечислены (см. следующий пункт).
  2. Например, на machinelearing.ru есть целый список моделей с описанием того, что они делают и какие данные им нужны на вход. Описания в разной степени сложности (где-то можно почитать и понять с первого раза, а где-то с пятого). Помимо общего описания модели важно извлечь из такой документации, как исходные данные должны выглядеть и в каком виде модель дает ответ. Если вы, например, строите регрессию и вам нужно на выходе число, то понятно, что бинарная классификация вряд ли поможет.
  3. Если таким способом построить гипотезу не удалось стоит прочитать про опыт других компаний, кто что недавно в этой области делал (например, в статьях или на конференциях/митапах).
  4. Ну а если все предыдущие шаги не сработали можно думать про разработку собственного алгоритма.


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

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

Однако после изобретения машинного обучения ответ может стать более предсказуемым:

А если все спрыгнут с крыши, ты тоже спрыгнешь?
[изобретено машинное обучение]
Да!

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

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

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

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



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

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

В итоге

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

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

Тестирование для мобильных разработчиков полезные видео с Android-митапа

04.08.2020 14:20:22 | Автор: admin
Неважно, работаете ли вы в стартапе или крупной организации, продуктовой компании или аутсорсинговой. Всё это совершенно неважно, если в один момент вы решили не просто писать код, но и нести ответственность за него.

Именно этой теме мы посвятили встречу Android-разработчиков и мобильных тестировщиков на митапе Android Paranoid и обсудили:

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

Таймкоды проставлены, добро пожаловать под кат.




Стабильность 3д

Владимир Генович, ведущий программист (Яндекс.Деньги)

Я довольно поздно начал писать тесты. Всё потому, что во многих материалах по тестированию условный пример выглядит как assertEquals(2+2, 4), а потом ты смотришь на свой код и не знаешь, за что взяться. И вот настал день, когда на новом проекте я решил писать код так, чтобы он был лучше подготовлен к тестированию. Потом я разобрался в том, почему некоторые тесты не помогают и как этого избежать, а дальше научился применять все это к legacy-коду.

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



Таймкоды

0:20 Как началась история тестирования
1:46 Готовим свой код к тестированию. Чистые функции
3:02 А что делать с legaсу? Подход 3д: доказывай, доверяй, допускай.
3:40 Доказывай, что код работает, с помощью тестов
5:00 Тестирование чистых функций на диапазоне входных значений
6:30 Почему не надо использовать случайные значения
8:12 Как выбирать диапазоны значений для тестирования
10:39 Когда Unit-тесты могут не помочь?
11:36 Доверяй своим типам данных и проверенному коду
12:48 Оборачиваем примитивы в объекты для уменьшения возможных вариантов
14:05 Фабричные методы для создания объектов
15:08 Концепция Either
16:44 2 кейса для тестирования фабричных методов
17:43 Покрытый тестами код работает, но приложение падает: почему?
18:09 Допускай, что внешние системы могут работать некорректно
18:50 Either для защиты
19:23 Создание чистых конвейеров от ввода до вывода
21:20 Зачем писать столько тестов, всё же работает?
22:28 Подведение итогов: доказывай, доверяй, допускай.



Как упростить жизнь мобильному тестировщику

Дмитрий Жаков, тестировщик (Яндекс.Деньги)

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



Таймкоды

1:55 С чего начинается путь тестировщика? Методы тестирования
2:15 Совет 1. Логирование: для чего нужно и что делать, если логов слишком много
4:03 Логирование при проверке пользовательских событий
7:00 Проверка событий поведения пользователей: Appium и Espresso
10:29 Совет 2. Забота о matchers и доступах UI-элементов
12:35 Chuck: инструмент для быстрого доступа к информации
13:50 Секретное меню для разработчика и QA
16:48 Запуск приложения
18:42 Как идентифицировать устройство в мобильном зоопарке?
23:12 Тестовое окружение: тестовый сервер, подмена трафика и система подготовки пользователей
29:56 Подведение итогов: чем разработчик может помочь тестировщику




Самый модный UI-test фреймворк в 2к20

Дмитрий Манько, Android-разработчик (Ситимобил)

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



Таймкоды

0:32 Что такое тестирование?
1:05 Первый шаг к тестированию: выбор фреймворка
1:55 PageObject: один из критериев выбора
3:55 Проверка фреймворков на UI-test и test-case (пример с проверкой номера телефона)
6:19 1 тест на Espresso: ожидание и реальные запросы
11:52 2 тест на UIAutomator
14:08 3 тест на Barista
15:45 4 тест на Kakao: отличительные особенности
17:28 5 тест Kaspresso: 3 довольных Дрейка.
20:49 Подведение итогов: что необходимо сделать при выборе фреймворка.
Подробнее..

Быть или не быть дискуссии о тестировании в мобильной разработке

03.09.2020 16:16:34 | Автор: admin
На Android-митапе мы устроили короткие дискуссии на 10-15 минут, где вместе с экспертами из Авито, Ситимобила и Revolut делимся различными взглядами на необходимость тестирования в разных проектах, говорим о регрессе и тестировании на пользователях.

Смотрите видео, читайте расшифровку и пишите в комментариях своё мнение на озвученные вопросы. Вместе разберемся: быть или не быть?

Дискуссия number one



Таймкоды

0:56 Всегда ли нужно вводить тестирование?
2:00 Зачем тестировать, если нужно скорее выкатывать фичи на рынок?
3:24 Можно ли тестировать только базовый функционал или одну часть приложения?
5:29 Критерии тестирования функциональности
7:28 В какой момент стартапу или аутсорсинговой компании нужно прекратить релизить фичи и начать тратить время на тестирование

Митап сразу начался с горячего с обсуждений. Поэтому представим участников нашей онлайн-дискуссии:

  • Дмитрий Воронин, Lead engineer в команде Speed (Авито).
  • Юрий Чечёткин, мобильный разработчик (Revolut)
  • Дмитрий Манько, Android-разработчик (Ситимобил)
  • Нина Семкина, старший программист (Яндекс.Деньги)
  • Владимир Генович, ведущий программист (Яндекс.Деньги)
  • Дмитрий Жаков, тестировщик (Яндекс.Деньги)


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

Дмитрий Манько: А что тестировать собрались?

Нина Семкина: Android-приложение. Когда мне нужно понять, что его 100% нужно тестировать?

Дмитрий Манько: Если рынок не ждет появление какой-либо функциональности, то, с точки зрения разработки или с точки зрения покрытия, тестирование можно упростить или им вообще пренебречь. Все зависит от продукта. Если мы делаем калькулятор с 2 функциями, то серию тест-кейсов мы, скорее всего, прошли и не раз. Таким образом, тесты можно не писать, быстрее выложить на рынок приложение и сократить time-to-market.

Нина Семкина: У нас всегда есть гонка time-to-market, рынок всегда требует кучу фичей, и мы не можем их тормозить. Особенно если речь идет о только-только начинающемся проекте, который нужно выпустить на рынок прямо сейчас, имени у нас никакого нет, мы конкурируем с другими компаниями. Какое нам дело в этот момент до тестирования? Нам нужно снабдить наше приложение фичами и быстрее их выкинуть, а то устареют через 3 недели. Зачем их тестировать?

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

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

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

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

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

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

Дмитрий Жаков: Тестирование в целом вообще нужно. Не надо забывать, что тестирование это проверка тех требований, которые мы предъявляем к продукту. Если что-то не соответствует требованиям, то это проблема, баг, issue. Все тест-кейсы и тестирование можно автоматизировать, и если времени не хватает, то вначале стоит проверять критичные моменты, а потом все остальное. Например, если у вас завтра релиз и бизнес хочет фичу именно завтра, то вы проверяете самый критичный функционал. А если времени достаточно, то можете позволить себе проверить medium, low-кейсы. Тут больше вопрос, будет ли ваше тестирование мануальным или автоматизированным. Будут ли это метрики или UI-тестирование, полностью проверяемое роботом.

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

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

Юрий Чечёткин: Мой опыт работы в крупных компаниях Яндекс, Альфа-Банк, Revolut в финтехе, где критичность любого бага просто зашкаливает. При этом у меня есть опыт в стартапе, и даже там тестирование было абсолютно нужно. Считаю, что неважно, стартап это или нет, потому что разработчик должен отвечать за свой код, и тесты это гарантия того, что этот код работает. Разработчик это в первую очередь инженер, который отвечает за разрабатываемый продукт. Поэтому тесты писать нужно не потому, что надо, а потому, что они должны тебе помочь. Если это тесты, написанные для галочки, то это может тормозить разработку. А если тесты тебе нужны и ты это сам понимаешь, то их обязательно нужно писать. Если разработчик пишет код и уверен, что он работает без тестов, это риск, и это его выбор. А я все-таки считаю, что разработчик не должен так рисковать и должен прикрывать себя и покрывать все тестами.

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

Дискуссия number two



Таймкоды

0:09 Как снять регрессионную нагрузку с QA перед релизами? Есть ли в компаниях стратегия по улучшению стабильности приложения?
4:25 Есть ли смысл использовать моки или фейк-объекты в UI-тестах
8:05 Тестирование на пользователях: допустимо или нет?

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

Дмитрий Жаков: У нас стратегия такая, что мы тестируем всё. Потому что мы являемся последним рубежом, как сотрудники перед пользователями. Поэтому отдаем только такое приложение клиенту, которое стабильно работает всегда и везде. Вопрос только в скорости. Изначально ручной прогон у нас занимал много времени до недели. Но благодаря автоматизации мы достигли того, что релиз длится в среднем сутки. Поэтому если вы разрабатываете какой-либо функционал, то нужно договориться, что или вы или тестировщики будут сразу писать автотесты. И какие-то mobile specific кейсы, которые вы не можете автоматизировать, останется проверить только на регрессе, а все остальное проверит робот. Тем самым вы разгрузите тестировщиков, они будут заниматься более интересной, исследовательской работой, а всю рутину прокликивание сценариев вы отдаете роботу.

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

Владимир Генович: Вы его автоматизировали, наверное?

Юрий Чечёткин: Не совсем так, он был только на начальных этапах проекта, а затем его не стало вовсе.

Владимир Генович: Вы же гоняете UI-тесты?

Юрий Чечёткин: UI-тесты есть, конечно.

Владимир Генович: И Unit-тесты? Так запуск этих тестов при выпуске релиза это разве не регресс?

Юрий Чечёткин: Да, это регресс, но того мануального тестирования, о котором привыкли говорить, нет. И это довольно интересный подход. Он отрезвляет и превращает разработчика из ребенка, который пишет код и отдает его тестировщикам, в более взрослого и самостоятельного инженера, который сам отвечает за свой код. Что касается визуальных вещей ревью может проводить дизайнер или PO. И есть такие штуки, как скриншот-тесты, например, у Facebook. Так что кажется, что сейчас продуктовые компании могут обойтись и без QA. А сами тестировщики могут заниматься более интересной работой. Конечно, немного другая история в аутсорсе там продаются человеко-часы, и QA может продаваться как дополнительная услуга.

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

Юрий Чечёткин: Да, например, тестирование на пользователях.

Нина Семкина: Перед тем, как мы затронем это очень опасную тему, я бы хотела зачитать следующий вопрос от наших слушателей. Есть ли смысл использовать моки или фейк-объекты в UI-тестах?

Дмитрий Воронин: Есть смысл, и без них никуда. Потому что UI-тесты с полной интеграцией это очень ненадежная штука. И вы никогда не сможете полагаться на тест, в котором 30 систем, в каждой из которой по куче точек отказа будет запускаться пул-реквест. Такие тесты нежизнеспособны. И никто ни в одной компании не смог такие штуки заставить работать. Поэтому UI-тесты это проклятье мобильной разработки. Если есть возможность, то лучше тестировать без UI. Но из-за того, что мы вынуждены жить с фреймворком, а единственная альтернатива это какой-нибудь роболетрик, а в iOS даже и такого нет. И чтобы проверить взаимодействие хотя бы с одной из важных для нас систем, мы запускаем всё на устройстве. UI здесь постольку, поскольку по нашей незрелости разработки мы хотим захватить по максимуму, чтобы проверить, как нажимает юзер, нам так спокойнее. Мне кажется, что через какое-то время это уйдет в прошлое и мы перестанем бояться моков, нажатия и не будем бороться с системой, чтобы проверять все как надо, потому что все равно мы все не проверим. Могут быть визуальные баги, которые никакими UI-тестами не проверятся. Поэтому считаю, что мокировать и в UI-тестах можно и нужно, и главная цель у этого повысить стабильность этого инструмента, довести его до такого состояния, чтобы он приносил пользу. А реальная польза в данном случае убедиться в отсутствии регрессий. И любой инструмент, который флакует, превращается во второе Д из предыдущего доклада Владимира Геновича, когда мы перестаем доверять. Это происходит тогда, когда нам в тест начинают прилетать случайные значения в огромном количестве. И такой тест не дает никакой уверенности в себе, а только дает ложную надежду, что что-то протестировано.

Дмитрий Жаков: У нас около 70% кейсов автоматизированы, и они не используют ни одного мока на приложении. Возможно, их проще перенести на бэкенд. Например, если это относится к номеру карточки, то вы ожидаете, что у вас 3DS не запросится. То есть приложение не знает, что оно замокано. Думаю, что это проблема инфраструктуры.

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

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

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

Юрий Чечёткин: Однозначно да. В нашем случае мы имеем демо, внутреннюю раскатку и тестирование на 5% пользователей вместо ручного тестирования. Конечно, после релиза фичи нужно посмотреть. Раскатка не должна быть на 100% сразу это главный защитный механизм.

Дмитрий Воронин: Этический вопрос тестирования на пользователях за нас решает Google. У Apple вроде такого нет. Есть специальные каналы распространения, как вы знаете (альфа, бета production). Каждый может вступить в бета-тестирование, и он соглашается со вполне понятной формой, в которой говорится, что он в здравом уме соглашается с тем, что может получить нестабильную версию продукта. И таким образом он хочет поволонтерить и помочь компании сделать продукт лучше. Как только мы открыто говорим человеку о таком, думаю, этот вопрос должен сниматься и мы не должны бояться раскатывать туда версию, в которой не уверены на 100%. А еще лучше, когда у нас есть фидбек оттуда, и с каждым таким нестабильным релизом этот процесс улучшать. Если в компании есть процессы, которые отслеживают тенденции качества в бете, то все должно становиться только лучше. А юзерам это тоже в плюс они будут первыми получать фичи. В основном это замотивированные и лояльные вашему продукту пользователи, и они сами захотят протестировать новые вещи, которые появляются в приложении. И даже будут готовы пожертвовать чем-нибудь за это.

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

Владимир Генович: А как же early adopter, который любит тебя, как бы компания ни косячила? И, скорее всего, эта компания сможет возместить убытки. Согласись, если мы выкатим какую-нибудь штуку скажем пользователю: Слушай, мы очень боимся. И ты можешь потерять 1000 рублей. Но мы тебе возместим. Скорее всего, такой пользователь на свой страх и риск сделает это, и если деньги потеряются, то мы не скажем ему потом: Ну ты сам виноват. Поэтому, думаю, даже в случае банковского приложения мы можем помочь пользователям.

Дмитрий Жаков: И если у вас бета-тестеров слишком мало, то можно использовать А/Б-тестирование с помощью конфигов включать/выключать какую-нибудь фичу, чтобы в случае падения можно было сразу что-то отключить и протестировать как надо. Как мы помним, в mobile очень сложно откатываться, поэтому перед релизом лучше по максимуму все проверять.

Владимир Генович: Или писать на React Native))

Нина Семкина: Прерву нашу беседу, так как подошло время следующего доклада. Дима, передаю слово тебе.

Дискуссия number three



Таймкоды

0:05 Как улучшать регрессионное тестирование? Как и когда вводят тестирование при разработке фич (опыт Авито)
10:43 Где гоняются Unit-тесты: на CI или локально перед пушом?


Нина Семкина: Я бы хотела обратиться к Диме Воронину, чтобы послушать его мнение и про его опыт о том, как они в компании улучшали регрессионное тестирование и когда они вводят тестирование при разработке фич.

Дмитрий Воронин: Мне правда есть чем поделиться. Это пятилетняя история борьбы с ручным регрессом. И это частично продолжение ответа на вопрос, который у нас был между 2 первыми докладами. Этот вопрос про то, как быть, если у тебя есть ручной регресс. Потому что опыт Revolut повторить не у всех получится. Ребята молодцы, что рубанули с плеча, и у них получилось сделать надежно. Для этого нужно иметь много смелости, хорошую культуру разработки и самое важное понимающих руководителей разработки, для которых такой подход не выглядит диким. Так получается, потому что в нашей работе есть инерция и менять устои, особенно в больших компаниях, бывает сложно. Пример Revolut доказывает, что если это работает, то это как минимум быстрее, чем ручной регресс, и каждый разработчик начинает задавать себе правильные вопросы. То есть он начинает быть ответственным за большую часть релизного цикла, то есть не до того момента, когда он закоммитил изменения, а как любой взрослый инженер, он еще и ведет продукт в релизной стадии.

Что произошло у нас? Мы находились в точке, когда у нас был ручной регресс, который выполняли 5 человек 12 рабочих дней, и без этого мобильное приложение не катилось. Это было в 2015 году. И в тот момент у нас не было ни одного автоматизированного UI-теста. Unit-тесты мы писали практически с самого начала и писали достаточно активно. Вот Владимир в докладе рассказывал про 10 секунд и 1000 тестов мне это страшно представить, когда мы прошли такой момент в 2014 году. Сейчас у нас 12 000 Unit-тестов, и идут они далеко не 10 секунд, это тоже не бесплатная штука. Даже с учетом того, что все инженеры понимают и пишут тесты, был сложный момент. Все эти Unit-тесты ни грамма не доказывают про баги в продакшене и про то, как приложение себя ведет. То есть тестирование фиксирует поведение, позволяет проще вносить изменения и дает фидбек, правильно ли ты это делаешь. Проблема в том, что есть отдел QA. Конечно, не в нем проблема. Проблема в том, что у них есть задача обеспечить определенный уровень качества. И они привыкли добиваться этого уровня, они берут на себя эту ответственность. И переломить этот момент сложно, если это идет не с самого начала вашего продукта. Какие здесь есть рецепты? Самое правильное не включать жесткий режим, когда мы всех увольняем и все захватывает автоматизация. Это наверное самый страшный и незрелый подход, который я видел. Что тут плохого? Во-первых, на какое-то время потеряется качество тестирования. Во-вторых, все процессы разрушаются, а новые быстро не строятся.

Что сделали мы? Мы начали оптимизацию с того, что писали UI-тесты, которые заменяют регресс. То есть это полноценные инфраструктурные тесты, которые задевают бэкенд с тестовыми пользователями. И, собственно, результатом этой работы стали, как вы знаете, всякие популярные фреймворки например, Kaspresso. Это как раз то, что мы закладывали, когда всё начинали. Мы после себя оставили кучу артефактов, которые могут помочь разработчикам. И поэтому входить в тестирование сейчас проще. Также мы положили в опен-сорс различные раннеры, и все желающие могут посмотреть, как мы с ними работаем. Но мы не забывали про ручное тестирование, про его оптимизацию и про то, как эти два отдела начинают сливаться в один эффективный процесс. Наверное, точка Б это состояние Revolut. Но наша дорога из точки А в точку Б, как и у многих других компаний, занимает долгое время. Сейчас мы на том этапе, когда QA выполняет роль исследователей, они больше погружаются в продукт, занимаются проработкой функциональных требований, пишут автотесты.

Самое интересное про практики улучшения ручного регресса это impact-анализ. То есть попытка ответить на вопрос: А что же поменялось в этот релиз? И что мы можем тестировать, а что со спокойной душой выкатывать на следующие этапы. Impact-анализ это сложный вопрос, потому что когда у тебя большой релизный цикл, то есть вы релизитесь 2-3 месяца, то impact-анализ ответит тебе всегда одинаково, потому что за такое время вряд ли какую-то часть приложения не потрогали. Но если сократить этот релизный цикл до недели, а еще лучше до дня, то impact-анализ показывает вполне адекватные вещи, оставляет отметки, которые помогут оптимизировать ручной регресс. Мы эту практику применили вполне успешно. Вначале были ошибки, но мы разово сокращали объем ручного тестирования.

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

Вот эти три направления позволили нам дойти до того, что мы 1 раз в день релизим в бету, раз в неделю это долетает до 100% пользователей, ручного регресса нет. Я надеюсь, эта история побудит к действиям компании, которые недовольны своим состоянием релиза, чтобы в будущем только нажимать на кнопку релиз, все катится на пользователей, а все смотрят только на графики.

Юрий Чечёткин: Это, конечно, не только практики Revolut, но и мировые, их применяют Google, Facebook и так далее. Согласен, что это должен быть плавный переход. И когда многие становятся PO или уходят в автоматизированный QA все это немного размывается, эволюционирует и превращается во что-то сказанное. И в России этот тренд, правда, только начинается. И как ты правильно сказал, он должен быть максимально здоровым.

Нина Семкина: Поступил такой вопрос. У кого где гоняются Unit-тесты? На CI или локально перед пушем?

Юрий Чечёткин: Кажется, что гонять локально это задача разработчика, то есть насильно этого делать не стоит. Мне очевидно, что должно быть 100% на CI.

Нина Семкина: Спасибо всем участникам за дискуссию! Передаю слово нашему спикеру Диме Манько с его докладом.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru