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

Блог компании райффайзенбанк

Frontend Meetup 2004

19.04.2021 16:09:25 | Автор: admin

Вместе со спикерами из Devexperts, Почты России, Леруа Мерлен и Райффайзенбанка узнаем об опыте разработки продуктов: как найти подход к Blazor, использовать плагин Figma для работы с white label, разрабатывать картографический раздел отделений и внедрять микрофронтенды.

О чем поговорим

Blazor поневоле

Александр Кильганов, Райффайзенбанк

О докладе: Я не Frontend-разработчик, но с Blazor пришлось познакомиться: подход к нему получилось найти не сразу, об этом и расскажу с какими болями и трудностями при работе столкнулся и как их решал. Также расскажу, как смешивал несмешиваемые компоненты Blazor, C# и HTML и что это из этого получилось. Ну, и отвечу на главный вопрос: стоит ли Blazor вообще использовать?

Плагин в Figma для работы с white label

Наталья Ильина, Devexperts

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

Опыт отрисовки отделений на карте в Почте России

Михаил Вовренчук, Почта России

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

Эволюция микрофронтендной платформы в Леруа Мерлен

Роман Соколов, Леруа Мерлен

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


Начнем митап в 19:00 (мск).
Зарегистрируйтесь, чтобы получить ссылку на трансляцию: письмо придет вам на почту.

Подробнее..

DGTL Communications Meetup 2101

18.01.2021 12:13:17 | Автор: admin

Присоединяйтесь к нам 21 января на онлайн-митап: поговорим о системах объединенных коммуникаций и средствах общения. В программе три доклада от спикеров из компаний DataLine, Microsoft и Райффайзенбанка.

Регистрируйтесь на митап

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

О чем поговорим

Observability для Windows приложений
Станислав Булдаков,Райффайзенбанк

Best practices для Exchange Server в виртуальных средах
Евгений Парфенов,DataLine

Решение вопросов производительности в Exchange Server за 60 минут
Виктория Гиндосова, Microsoft

>>> Начнем митап в 18:00 (МСК).
Регистрируйтесь, чтобы получить ссылку на трансляцию: письмо придет вам на почту!


До встречи online!

Подробнее..

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

07.04.2021 14:14:13 | Автор: admin
Всем привет! Меня зовут Борис Николаев, сегодня я хотел бы поделиться с вами своими наработками по технической реализации простого шахматного движка на Kotlin.

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



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

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

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


Обозначения для шахматных фигур


Для начала определимся с терминами и названиями. Не все, что стоит на доске, является фигурой (англ. piece). Пешку к фигурам не относят. Но это скорее профессиональный сленг. Мы для простоты все будем называть фигурами.

Познакомимся c фигурами и запомним их вид в нашем движке.
Иконка Фигура
Пешка pawn
Конь knight
Слон bishop
Ладья rook
Ферзь queen
Король king
Обзор фигур, и как они ходят
Здесь кратко напомню, как ходят фигуры.

Пешка (англ. pawn) самая слабая фигура. Фактически, пушечное мясо. Двигается только вперед. Атакует только по диагонали вперед на одну клетку.

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

Ладья (устар. тура, англ. rook) фигура основательная. Хотя бы своим видом, похожим на башню. Ходит по горизонтали и вертикали в любом направлении на любое количество клеток, пока не встретит на своем пути другую фигуру. У каждого игрока по две ладьи, которые ставятся по углам доски.

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

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

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

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

Обозначения ходов


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

Расскажу и покажу наглядно.

Сперва пишется первая буква, обозначающая фигуру (для пешек букву не используем). Затем поле, с которого фигура совершает ход. Координата по Х обозначается буквами от a до h, по Y цифрами, начиная с 1. Очень похоже на морской бой.

Если в ходе была уничтожена вражеская фигура, то пишем x, если никто не пострадал, то будет . Затем указываем поле, на которое перешла фигура. Ну, и в конце обозначаем особые случаи: для шаха +, для мата ++, для пата =. Для превращения пешки указываем в конце тип новой фигуры.

Техническая реализация


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

data class Point(    val x: Int,    val y: Int)

Data class это неизменяемый тип, автоматически определяющий такие методы, как equals и hashCode, а потому его можно использовать в качестве ключа мапы. Х расположение фигуры по горизонтали, а Y по вертикали.

Для самой фигуры определим два параметра: цвет и тип.

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

enum class PieceColor(val text: String) {    WHITE("white"),    BLACK("black");    fun other(): PieceColor =    when (this) {        WHITE -> BLACK        BLACK -> WHITE    }}

Тип фигуры также определим в виде enum class с параметрами: название, ценность и краткое обозначение.

enum class PieceType(val nameEn: String,val nameRu: String,val price: Int,val notation: String,val useForPromotion: Boolean) {PAWN("pawn", "пешка", 100, "", false),KNIGHT("knight", "конь", 320, "N", true),BISHOP("bishop", "слон", 330, "B", true),ROOK("rook", "ладья", 500, "R", true),QUEEN("queen", "ферзь", 900, "Q", true),KING("king", "король", 20_000, "K", false)}

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

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

Теперь мы подошли к такому вопросу, как ценность фигур.

Ценность фигур


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

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

Движок


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

class BoardImpl : Board {private val pieces = mutableMapOf<Point, Piece>()private val history = mutableListOf<HistoryItem>()// ...}

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

rnbqkbnrpppppppp................................PPPPPPPPRNBQKBNR

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

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

Генерация доступных ходов


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

interface Turn {val sourcePiece: Pieceval from: Pointval to: Pointval enemyPiece: Piece?fun execute(pieces: MutableMap<Point, Piece>)fun revert(pieces: MutableMap<Point, Piece>)}

Каждый ход содержит информацию о фигуре sourcePiece, которая этот ход совершает, ее исходную позицию from, пункт назначения to и вражескую фигуру enemyPiece (опционально, если она находится в пункте назначения). Также имеется два метода, принимающие текущее состояние доски: execute() для выполнения хода и revert() для его отмены. По сути это паттерн Команда.

Обычный ход


Этот интерфейс реализует класс NormalTurn. Его метод для выполнения хода execute() выглядит так:

override fun execute(pieces: MutableMap<Point, Piece>) {    pieces.remove(from)    pieces[to] = sourcePiece}

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

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

override fun revert(pieces: MutableMap<Point, Piece>) {    pieces.remove(to)    pieces[from] = sourcePiece    enemyPiece?.let { pieces[to] = it }}

Ход с превращением


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

override fun execute(pieces: MutableMap<Point, Piece>) {    pieces.remove(from)    pieces[to] = sourcePiece.copy(type = toType)}

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

override fun revert(pieces: MutableMap<Point, Piece>) {    pieces.remove(to)    pieces[from] = sourcePiece    enemyPiece?.let { pieces[to] = it }}

Генератор ходов


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

interface TurnGenerator {    fun getTurns(        position: Point,         pieces: Map<Point, Piece>    ): Set<Turn>}

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

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

Метод addPointIfPossible() принимает текущую позицию, относительно которой ищем ходы, состояние доски, а также смещение deltaX и deltaY относительно текущей позиции. В методе мы проверяем, не выходит ли новая точка за пределы доски, а также смотрим, нет ли в полученной точке фигуры. Если фигуры нет ход доступен. Если фигура вражеская тоже ход доступен. Дополнительно сохраняем информацию о вражеской фигуре. Ну, и если в полученной точке есть другая наша фигура, то ход недоступен.

fun MutableSet<Turn>.addPointIfPossible(position: Point,pieces: Map<Point, Piece>,deltaX: Int,deltaY: Int): Boolean {val current = pieces.getValue(position)val from = positionval to = Point(from.x + deltaX, from.y + deltaY)val otherPiece = pieces[to]return to.takeIf { it.x in 0..7 && it.y in 0..7 }    ?.let {        when {                otherPiece == null -> { // нет фигуры                this += NormalTurn(sourcePiece = current, from = from, to = to)                true                }                otherPiece.color != current.color -> { // вражеская фигура                this += NormalTurn(sourcePiece = current, from = from, to = to, enemyPiece = otherPiece)                false                }                else -> { // своя фигура                false                }        }    } ?: false}

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

fun generateRectangularTurns(position: Point, pieces: Map<Point, Piece>, maxRange: Int): Set<Turn> {val spaces = mutableSetOf<Turn>()var left = truevar right = truevar top = truevar bottom = truefor (i in 1..maxRange) {        if (left) {        left = spaces.addPointIfPossible(position, pieces, -i, 0)        }        if (right) {        right = spaces.addPointIfPossible(position, pieces, i, 0)        }        if (top) {        top = spaces.addPointIfPossible(position, pieces, 0, i)        }        if (bottom) {        bottom = spaces.addPointIfPossible(position, pieces, 0, -i)        }}return spaces}

Эта логика поиска доступных ходов характерна для ладьи.

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

fun generateDiagonalTurns(position: Point, pieces: Map<Point, Piece>, maxRange: Int): Set<Turn> {val spaces = mutableSetOf<Turn>()var leftTop = truevar rightTop = truevar leftBottom = truevar rightBottom = truefor (i in 1..maxRange) {        if (leftTop) {        leftTop = spaces.addPointIfPossible(position, pieces, -i, i)        }        if (rightTop) {        rightTop = spaces.addPointIfPossible(position, pieces, i, i)        }        if (leftBottom) {        leftBottom = spaces.addPointIfPossible(position, pieces, -i, -i)        }        if (rightBottom) {        rightBottom = spaces.addPointIfPossible(position, pieces, i, -i)        }}return spaces}

Эта логика поиска подходит для слона.

Генераторы ходов для каждой фигуры


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

Для ладьи вызовем generateRectangularTurns() и укажем максимальный диапазон, в котором следует сгенерить ходы (8 клеток в каждом направлении):

class RookTurnGenerator : TurnGenerator {override fun getTurns(position: Point, pieces: Map<Point, Piece>): Set<Turn> =    generateRectangularTurns(position, pieces, MAX_RANGE)private companion object {        const val MAX_RANGE = 8}}

Для ладьи также будем генерить ходы в диапазоне 8 клеток, но с помощью метода generateDiagonalTurns().

class BishopTurnGenerator : TurnGenerator {override fun getTurns(position: Point, pieces: Map<Point, Piece>): Set<Turn> =    generateDiagonalTurns(position, pieces, MAX_RANGE)private companion object {        const val MAX_RANGE = 8}}

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

class QueenTurnGenerator : TurnGenerator {override fun getTurns(position: Point, pieces: Map<Point, Piece>): Set<Turn> =    listOf(    generateRectangularTurns(position, pieces, MAX_RANGE),    generateDiagonalTurns(position, pieces, MAX_RANGE)    )    .flatten()    .toSet()    private companion object {         const val MAX_RANGE = 8    }}

Для короля будет все так же, за исключением того, что MAX_RANGE будет равен 1 клетке.

class KingTurnGenerator : TurnGenerator {override fun getTurns(position: Point, pieces: Map<Point, Piece>): Set<Turn> =     listOf(    generateRectangularTurns(position, pieces, MAX_RANGE),    generateDiagonalTurns(position, pieces, MAX_RANGE)    )    .flatten()    .toSet()    private companion object {        const val MAX_RANGE = 1    }}

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

class KnightTurnGenerator : TurnGenerator {    override fun getTurns(position: Point, pieces: Map<Point, Piece>): Set<Turn> {    val spaces = mutableSetOf<Turn>()    spaces.addPointsIfCan(position, pieces, 1, 2)    spaces.addPointsIfCan(position, pieces, 2, 1)    return spaces    }    private fun MutableSet<Turn>.addPointsIfCan(position: Point, pieces: Map<Point, Piece>, absX: Int, absY: Int) {    this.addPointIfPossible(position, pieces, absX, absY)    this.addPointIfPossible(position, pieces, absX, -absY)    this.addPointIfPossible(position, pieces, -absX, absY)    this.addPointIfPossible(position, pieces, -absX, -absY)    }

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

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

class PawnTurnGenerator : TurnGenerator {    override fun getTurns(position: Point, pieces: Map<Point, Piece>): Set<Turn> {    val turns = mutableSetOf<Turn>()    val current = pieces.getValue(position)

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

val range = if (position.y == getStartY(current.color)) 2 else 1val from = position

Метод getDirectionY() в зависимости от цвета определяет направление хода пешки (приращение по вертикали), так как она может двигаться только вперед.

val directionY = getDirectionY(current.color)for (i in 1..range) {    val to = Point(from.x, from.y + directionY * i)

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

if (to in pieces) {    break} else {    turns.addTurnWithPromotionCheck(position, current, to, null)}

Наконец, проверяем клетки атаки впереди слева и впереди справа от пешки.

   addAttackPoint(position, current, 1, directionY, pieces, turns)    addAttackPoint(position, current, -1, directionY, pieces, turns)    return turns        .filter { it.to.x in 0..7 && it.to.y in 0..7 }        .toSet()}//  другие вспомогательные методы}

Объединяем все вместе


Теперь пришла пора объединить все эти классы внутри нашего движка.

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

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

fun getSpacesUnderAttack(pieces: Map<Point, Piece>): Map<PieceColor, Set<Point>> {    val spacesUnderAttack = mutableMapOf<PieceColor, MutableSet<Point>>()    pieces.entries.forEach { (position, piece) ->        spacesUnderAttack.putIfAbsent(piece.color, mutableSetOf())        spacesUnderAttack.getValue(piece.color).addAll(getTurnsForPiece(position, pieces).map { turn -> turn.to })    }    return spacesUnderAttack} 

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

fun isKingUnderAttack(pieces: Map<Point, Piece>, kingColor: PieceColor): Boolean {    val spacesUnderAttack = getSpacesUnderAttack(pieces).getValue(kingColor.other())    val king = pieces.entries        .first { it.value.type == PieceType.KING && it.value.color == kingColor }    return king.key in spacesUnderAttack}

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

override fun getTurnsForPiece(position: Point): Set<Turn> {    val turns = UTILS.getTurnsForPiece(position, pieces)    val result = mutableSetOf<Turn>()    val kingColor = pieces.getValue(position).color    // нужно исключить каждый ход фигуры, который ставит её короля под удар    turns.forEach { turn ->            turn.execute(pieces)            if (!UTILS.isKingUnderAttack(pieces, kingColor)) {            result += turn            }            turn.revert(pieces)    }    return result}

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

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

Выполнение хода и проверка статуса игры


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

override fun executeTurn(turn: Turn): GameState {    val selectedPiece = pieces.getValue(turn.from)    turn.execute(pieces)    val state = getGameState(pieces, selectedPiece.color.other())    saveTurnHistory(selectedPiece, turn, state)    return state}

Проверка состояния в методе getGameState() производится по следующей логике:
Игрок может сделать хотя бы один ход? Его король под ударом? Статус игры
Шах
Обычное состояние, игра продолжается
Мат
Пат
Небольшое лирическое рассуждение про пат
Раньше у меня было какое-то упрощенное понятие пата. Я думал, что это когда ни один игрок не может совершить ход. В обоих случаях вражеский король загнан в угол, и по факту битва уже проиграна. Но если он никем не атакован и при этом не может совершить ни один ход (так как под мат ходить нельзя), то это уже ничья. Согласитесь, что это неочевидно?

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

Дальше дело за ИИ


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

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

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

21.04.2021 16:08:09 | Автор: admin
Продолжаю рассказывать, как докручиваю свой шахматный движок, и это вторая часть статьи. Она небольшая, здесь я подсвечу настройку ИИ в игре. Сыграем с соперником в лице собственного компьютера.



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

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

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

Все исходники проекта выложил на Github.

Задаем алгоритм игры компьютера


Создадим класс с очень амбициозным именем Ai и свойством color, который будет содержать цвет игрока-компьютера (чёрный или белый). Класс содержит единственный публичный метод nextTurn(). Этот метод принимает текущее состояние доски в виде фигур и возвращает объект Turn, который он считает наиболее оптимальным.

class Ai(private val color: PieceColor) {    fun nextTurn(board: Board): Turn { ... }

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

val pieces = HashMap(board.getPieces())val currentSpacesUnderEnemyAttack = utils.getSpacesUnderAttack(pieces)    .getValue(color.other())

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

val profits = board.getTurnsForColor(color)    .entries.map { (from, turns) ->        turns.map { turn ->                TurnProfitInfo(                        from = from,                        turn = turn,                profit = turn.getProfit(pieces, currentSpacesUnderEnemyAttack)                )        }    }    .flatten()

Сама логика вычисления профита содержится в методе расширения Turn.getProfit(). После вычисления всех профитов найдем максимальный.

val maxOwnProfit = profits.maxOf { it.profit }

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

val turnPriceInfo = profits.filter { it.profit == maxOwnProfit }    .shuffled()    .first()return turnPriceInfo.turn}

Оценка хода, или какая фигура будет уничтожена


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

private fun Turn.getProfit(pieces: HashMap<Point, Piece>,currentSpacesUnderEnemyAttack: Set<Point>): Int {var profit = 0

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

this.enemyPiece?.let { profit += it.getPrice() }this.execute(pieces)

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

val newSpacesUnderEnemyAttack = utils.getSpacesUnderAttack(pieces)    .getValue(color.other())

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

if (this.from in currentSpacesUnderEnemyAttack && this.to !in newSpacesUnderEnemyAttack) {    profit += this.sourcePiece.getPrice()} else if (this.from !in currentSpacesUnderEnemyAttack && this.to in newSpacesUnderEnemyAttack) {    profit -= this.sourcePiece.getPrice()}

В конце отменяем пробный ход.

this.revert(pieces)return profit}

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

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

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


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

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

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

О плюсах парного программирования

03.12.2020 14:20:34 | Автор: admin


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

Парное программирование


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

Так же и в парном программировании.

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

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

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

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

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

Обучение новичка




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

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

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

Шеринг знаний и ликвидация Башни




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

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

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

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

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

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

Решение сложных задач



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

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

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

Смешанные задачи




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

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

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

Итого


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

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

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

О проблемах нормальной оценки фич и как их решить

18.02.2021 18:15:13 | Автор: admin
image

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

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

Но, в конечном счете, нам всем бы хотелось получать зарплату, а зарплата не из воздуха появляется, ее компания берет из выручки, в отдельном случае из инвестиций. А чтобы эта самая выручка была, нам надо достигать бизнес-цели. А люди, которые формулируют бизнес-цели очень любят всякие финансовые формулы ROI, LTV и прочая EBITDA. А в этих формулах постоянно фигурируют сроки. Без них крокодил не ловится, не растет кокос.

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

Как следствие: скорее всего, оценивать все же придется. Смиритесь.

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

  • Оцениваем всю работу в человекоднях.
  • Добавляем 10% на всякий случай.
  • Делим на количество разработчиков.
  • Прибавляем получившееся количество дней к текущей дате и получаем итоговую дату.
  • Вот и все.

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

Ты не выделывайся со своими сторипоинтами, ты рукой покажи.

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


Начнем с идеальной ситуации:

  • У нас есть атомарная (простая, неделимая) задача.
  • У нее нет зависимостей от других задач, не надо ничего согласовывать.
  • На задачу есть на 100% выделенный человек, который знает, как ее делать.

Даже в таком случае встает вопрос Кто будет делать оценку?. В этот момент запускается неумолимая машина управления. Сначала менеджер думает: если это будет делать разработчик что ему помешает указать огромные трудозатраты чтобы повалять дурака? -> Поэтому менеджер оценивает задачу сам. -> Однако менеджер недостаточно глубоко разбирается в теме и не видит (или не хочет видеть) подводные камни. -> Оценка оказывается непоправимо заниженной. -> Команда не укладывается в срок. -> Смерть и тлен.



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

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

Новейший пример культуры страха релиз игры Cyberpunk 2077. Игра вышла в отвратительном качестве на консолях прошлого поколения. СЕО компании в своем заявлении сказал, что как оказалось, во время тестирования не были обнаружены многие проблемы, с которыми вы столкнулись в игре. Что, разумеется, тотальная ложь. Проблемы были видны невооруженным глазом, тестеры физически не могли такое пропустить. Это типичная ситуация для культуры страха: проблемы замалчиваются. Так информация по пути до верхнего этажа менеджмента превратилась из игра неиграбельна на базовых консолях в давайте релизить.

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

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

image

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

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

  • Хотелки клиентов или Product Ownera.
  • Внезапные проблемы, под которые надо что-то доработать.
  • Неожиданный legal.
  • И тонны всего прочего.

Самое непредсказуемое проблема разной скорости разработчиков.

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

  • Кто-то неделю будет пилить и отлаживать код, а кто-то за полдня прикрутит открытую библиотеку.
  • Кто-то будет курить Stack overflow, а кто-то уже решал такие задачи и сходу начнет приносить пользу.

В итоге наша гауссиана превращается во что-то такое (так же выглядит оценка, когда задача недостаточно отгрумлена):



В общем, все сложно, мы тут не траншеи роем. Как же сделать хорошую оценку в таких условиях?

Критерии хорошей оценки:

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

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

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

image

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

image

Если Product Owner очень креативый, то может быть даже так:

image

А теперь вспоминаем, что оценка подчиняется законам нормального распределения, а вот и сюжетный поворот такие гауссианы отлично складываются. Поэтому получается вот что (это называется enchanced burndown chart):

image

Казалось бы, сбылась мечта юного математика: из кучи хаоса мы получили красивый график и можем с умным видом вещать что с 50% вероятностью мы закончим в 14 спринте, с 80% вероятностью в 17-м, с 95% в 19-м.

Во всем этом процессе есть ряд подводных камней.

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

Во-вторых, проблема разработчики работают с разной продуктивностью никак не решается в принципе. А значит, у нас получается очень пологое нарастание вероятности, которое мало помогает принимать управленческие решения: с 50% вероятностью мы закончим в 14 спринте, с 80% вероятностью в 27-м, с 95% в 39-м так на языке математики звучит пальцем в небо.

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

Метод Покер планирования


Это одна из самых популярных техник оценки, наверное, потому что самая старая.

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

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

Метод выстраивания порядка


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

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

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

Метод Большой/маленький/непонятный


Пользовался несколько раз, но не прижилось.

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

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

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

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

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



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

Epic Scrum Fails предновогодний скрам-стендап

11.12.2020 16:14:18 | Автор: admin
Встретимся 15 декабря и вместе посмеёмся над историями скрам-мастеров, помня, что в каждой шутке есть своя мораль. В программе вредные советы от Сбера, МТС, Альфа-Банка, ОТП и Райффайзенбанка.

Присоединяйтесь к нам!



О чем будем говорить


Что бывает, когда 8 шапок скрам-мастеравстречаются с реальной жизнью!

Наташа Епейкина, Райффайзенбанк

От создателей это не на нашей стороне и в Jira этого не было.

Фейлы скрам-команд, и что можно с этим сделать

Росянок Виталий, МТС

Фейлы, с которыми встречаются все скрам-мастера. Обсудим тривиальные косяки скрам-команд в комичной форме, увидим себя и разберём варианты решений.

Молотки, гвозди и парное программирование

Арсений Кельдышев, Райффайзенбанк

История о нанесении добра и несусветной пользы.

Как перестать волноваться и начать жить СМу?

Екатерина Шевченко, ОТП Банк

На что похожи взаимоотношения СМ и команды? Два кейса из реальной практики.

Сейчас смешно, а раньше было поучительно

Никита Щербаков, Сбер

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

Самые Большие Ошибки Скрам-мастера

Сергей Макаркин, Альфа-Банк

Как гарантировать провал Agile и привить сотрудникам отвращение к Scrum.

>>> Начнем митап в 19:00 (МСК).
Регистрируйтесь, чтобы получить ссылку на трансляцию: письмо придет вам на почту.

До встречи онлайн!
Подробнее..

Мифический человеко-месяц 45 лет спустя

16.12.2020 16:22:14 | Автор: admin
Впервые о книге Фредерика Брукса я услышал лет десять назад, ещё учась в универе. Её настоятельно советовал почитать наш научный руководитель. Как часто бывает в таких случаях, когда кто-то вам советует что-то почитать, то вы вежливо говорите нечто вроде да-да, в скором времени, непременно этим займусь, заносите очередной пункт в свой grow list (в лучшем случае) и благополучно об этом забываете.



Через пару лет я вернулся к этой книге и наконец с ней ознакомился. К тому моменту у меня уже было несколько лет работы в IT-индустрии. И когда я начал читать, то удивился, насколько книга, написанная в 1975, да ещё и в сфере разработки ПО, по-прежнему актуальна!

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

Пара слов об авторе книги


Фредерик Брукс был менеджером проекта по созданию IBM OS/360 (группа операционных систем, разработанных IBM для мейнфреймов System/360). Для ускорения разработки он предпринял попытку привлечь ещё больше разработчиков, но решение это оказалось фатальным. Чтобы никто более не наступал на те же грабли, Брукс впоследствии написал серию очерков, которую мы теперь знаем как Мифический человеко-месяц. Считается, что каждому менеджеру проекта следует ознакомиться с этой книгой.


Высокая кухня требует времени


Именно такой эпиграф предваряет вторую главу книги, а начинается она со слов:
Все программисты оптимисты.



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

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

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

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

Брукс проводит наглядную аналогию между приготовлением еды и разработкой ПО:
Мило, когда вам обещают приготовить омлет за две минуты. Но когда две минуты прошли, а омлет ещё не готов, у клиента остаётся два варианта продолжать ждать либо съесть его сырым. Повар может предложить ещё один вариант добавить огня. В результате омлет уже ничем не спасёшь: подгорит с одной стороны и будет сырым с другой.
Также он приводит эмпирическое правило, что написание кода в нашей работе занимает лишь от всего времени, которое мы тратим на задачу. Совпадает ли его оценка с вашей?

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

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

Поскольку Брукс сам погорел на этом при разработке IBM OS/360, он сформулировал такой закон:
Если проект не укладывается в сроки, то добавление рабочей силы задержит его ещё больше.

Хирургическая бригада


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

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

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

Итак, какой же состав dreamteam по Бруксу:
Хирург главный программист. Он лично задаёт спецификации, разрабатывает дизайн программы, реализует её и пишет документацию. Имеет большой талант, десятилетний опыт и значительные прикладные знания. В большинстве современных команд это тимлид или архитектор.
Второй пилот альтер эго хирурга, чуть менее опытный, но способен выполнять любой участок работы. Досконально знает весь код. Хирург обсуждает с ним свои идеи, но он не связан по рукам его советами. По описанию очень напоминает старшего программиста.
Администратор собственно, человек, который разгружает хирурга в части решения различных оргвопросов, которых в крупных компаниях бывает немало.
Редактор пишет документацию, беря за основу черновик, написанный хирургом. То есть правильно оформляет её, снабжает ссылками. Получается, это технический писатель. Брукс настаивает на том, что черновик документации должен писать именно тот, кто пишет код, то есть хирург.
Секретарь обрабатывает переписку, связанную с проектом, а также документы, не относящиеся к продукту. К слову, в нашей команде необходимость найма секретаря уже стала предметом многочисленных шуток.
Инструментальщик создаёт различные специализированные утилиты и скрипты. Очень похоже на роль девопса.
Тестировщик пишет тест-кейсы и тестирует код приложения. Также занимается созданием вспомогательных средств, необходимых для тестирования компонентов.
Языковой консультант разбирается в тонкостях используемого языка и умеет находить эффективные решения каких-нибудь каверзных задач. Часто проводит небольшие исследования в течение двух-трёх дней. Один такой консультант может работать сразу с несколькими командами. На мой взгляд, это некий разработчик единой платформы в рамках всей компании, которая позволяет командам сосредоточиться на написании самой бизнес-логики, специфичной для их проекта.
В этом распределении ролей Брукс находит два преимущества, которые выгодно отличают такую команду от обычной, где все равномерно распределяют между собой задачи. А именно концептуальная целостность и отсутствие конфликта интересов.

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

Эффект второй системы


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

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

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

Тут сложно что-либо добавить или опровергнуть. Я с автором полностью согласен. Решением данной проблемы является, на мой взгляд, принцип KISS (keep it simple, stupid). Потому что в современных реалиях любые попытки угадать дальнейшее развитие системы являются делом неблагодарным.

Пилотная установка

В этом мире нет ничего постоянного, кроме непостоянства.

Нельзя не согласиться


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

Планируйте выбросить первую версию вы всё равно это сделаете.

Как вы уже догадались, речь идёт об MVP (minimum viable product). Это некий прототип, позволяющий проверить ту или иную гипотезу бизнеса. Продолжая предыдущую тему, на этапе MVP следует выключить внутреннего перфекциониста. А уж если результат эксперимента окажется положительным, тогда получится быстрее с нуля написать вторую версию как положено.

Два шага вперёд и шаг назад


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

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

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

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

И грянул гром


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

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

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

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

Самодокументированные программы


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

Однако есть и другая точка зрения на этот вопрос. Например, Мартин (Роберт, а не Джордж), автор книги Чистый код, утверждает, что комментарии это зло. Даже будучи среди исходного кода они всё равно могут стать неактуальными. Не трать время на написание комментариев, говорит Мартин. Вместо этого он предлагает более тщательно подходить к процессу именования переменных, методов и классов. Если всё делается правильно, то и необходимость в комментариях отпадает. А какой точки зрения придерживаетесь вы, документируете ли свой код непосредственно в исходниках?

Модель инкрементальной разработки


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



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

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

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

Зачем понадобилось переиздавать книгу


Тут хотелось бы просто привести цитату Брукса, в которой он иронизирует над самим собой. Он описывает случай, произошедший в самолёте:

Незнакомец, сидевший рядом со мной, читал Мифический человеко-месяц, и я ждал, как он отреагирует словом или знаком. Наконец, когда мы вырулили к выходу, я не выдержал:
Как вам эта книга? Рекомендуете?
Гм! Ничего такого, чего бы я уже не знал.

Я предпочёл не представляться.

Действительно, зачем переиздавать книгу, которой вот уже 45 лет и которая посвящена такой динамично развивающейся отрасли, как разработка ПО? Весь материал, который я привёл выше, показывает, что многие вопросы, рассматриваемые в книге, актуальны до сих пор. Да, у нас есть scrum, agile, стори-поинты, но если присмотреться, то все новое забытое, но проявившее себя вновь, старое.

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

Scrum Community Meetup 1805

06.05.2021 16:19:55 | Автор: admin

Новый мир, болезненные челленджи, сложные кейсы и критические препятствия перед Agile-трансформациями и агентами изменений. Обсудим эти темы на онлайн-митапе 18 мая со спикерами Райффайзенбанка, AgileVerse и Tinkoff.

Регистрируйтесь и присоединяйтесь к нам

О чем поговорим

Сложно, много и опасно. Part 1: как сделать трансформацию на удаленке, наступить на все грабли и выжить

Анастасия Ломакова, ФёдорСлесаренко, Райффайзенбанк

Расскажем про свой кейс LeSS-трансформации на удаленке. Сложности, с которыми мы столкнулись; грабли, на которые наступили, и уроки, которые для себя вынесли.

Сложно, много и опасно. Part 2: что может пойти не так в вашей трансформации

Левон Гончаров,AgileVerse

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

Трансформация как путь. По каким сторонам стоит смотреть, чтобы повысить шансы команды дойти до финиша?

Виктор Никишин, Tinkoff

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

Расскажу о вещах, которые лежат немного в стороне от цели, но которые стоят внимания, когда вы запускаете продуктовую трансформацию 25+ команд.

Изменения в online-эпоху

Михаил Вязанкин,AgileVerse

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

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


Начнем митап в 19:00 (мск)
Регистрируйтесь, чтобы получить ссылку на трансляцию: письмо придет вам на почту.

И присоединяйтесь к открытому чатуScrumCommunity @ Raiffeisenbank в Telegram. У нас активное коммьюнити, и мы всем рады!

Подробнее..

Как не испортить своего джуна

12.11.2020 12:19:49 | Автор: admin


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

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

Страх, страх и еще раз страх


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

Точно такой же стереотип существует и в области разработки программного обеспечения. Сформулировать его можно так:

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

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

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

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

Я считаю, что программирование это история о созидании, о творчестве.

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

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

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

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

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

Давайте новичку настоящие и актуальные задачи


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

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

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

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

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

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

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

А что если наш джун соответствует всем стереотипам о программистах? Что если он нерешителен в живом общении, замкнут в себе и банально стесняется подходить к незнакомым людям со своими разговорами? Если он боится показаться посмешищем, ведь он и так толком ничего не умеет, потому что новичок? Или это молодая девушка, которая решила связать свою карьеру с разработкой ПО, но при этом не хочет давать поводов для сплетен о том, что кто-то из команды делает за нее всю работу? Как быть им?

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

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

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

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

Практикуем парное программирование


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

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

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

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

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

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

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

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

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

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

Относитесь к джуну, как к равному


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

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

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

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

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

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

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

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

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

Итог


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

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

P.S.


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

Open Architecture Meetup 311

28.10.2020 14:12:50 | Автор: admin
Приглашаем вас обсуждать актуальное микросервисы. Встречаемся на онлайн-митапе 3 ноября, где вместе со спикерами ответим на вопросы: как вынести части, которые можно переиспользовать, и отдать другим командам, и как микросервисная архитектура может помочь развитию сотрудников внутри компании?

Присоединяйтесь к нам!



О чём поговорим


Микрофронтенд или Как всё разбить на маленькие кусочки и собрать вместе


Дмитрий Григоров, Газпромбанк

О спикере: Тимлид команды интернет-банка, девелопер, спикер и просто хороший специалист по реакту. Более 5 лет в разработке и продвижении продуктов.

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

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

Как микросервисная архитектура помогает развитию сотрудников внутри компании


Сергей Огородников, Райффайзенбанк

О спикере: Профессионально разрабатывает на C# с 2005 года, пришёл в.Net за пару месяцев до того, как подвезли generics. Сейчас работает старшим разработчиком в Райффайзенбанке в команде, занимающейся разработкой продуктов для HR. Интересуется DDD, software architecture, разработкой анализаторов кода, немного ФП.

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

Начнем митап в 19:00 (МСК)

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

До встречи онлайн!
Подробнее..

System Analysis Meetup 1012

03.12.2020 16:09:25 | Автор: admin
Присоединяйтесь 10 декабря к онлайн-митапу сообщества System Analysis Райффайзенбанка. Обсудим тему Low-Code/No-Code: как технологии совершают революцию в создании корпоративных приложений и как использовать эти технологии для решения задач аналитика. Еще сразимся с хаосом узнаем, как структурировать изменения с помощью моделей.

До встречи онлайн!



О чем будем говорить


Борьба с хаосом с помощью моделей

Евгений Асламов, независимый эксперт

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

Low-Code/No-Code: революция создания корпоративных приложений (наших дней)

Алексей Трефилов, ELMA

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

Low-Code/No-Code: как стать частью революции

Анна Казаченко, Райффайзенбанк

О докладе: В своем докладе Анна подробно расскажет о том, как можно использовать технологии Low-Code/No-Code для решения задач аналитика.

Активничаем в сообществе в Telegram, присоединяйтесь: @Open_SA_Community_Raif

Начнем митап в 18:30

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

Кластер PostgreSQL внутри Kubernetes что нужно знать для успешного внедрения

04.02.2021 16:05:13 | Автор: admin
Хабр, привет!

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



Будут схемы-примеры для наглядности и обзор возможных кейсов, начнем!

Для погружения (совсем) краткая история PostgreSQL


Postgre вышел в opensource из университета Беркли в 1996 году. Следующие два года шла стабилизация его работы и разрабатывалась базовая функциональность. Дальше возник вопрос: как сделать совместимой эту систему со стандартными SQL? И вот уже в 1998 году началось развитие самого ядра. Позже появилась необходимость в разработке возможностей enterprise уровня. Одной из таких возможностей, о которой мы в подробностях поговорим далее, является потоковая репликация. Именно она лежит в ядре отказоустойчивости PostgreSQL и без нее не было бы данной статьи.

Потоковая репликация


Она появилась в 2010 году вместе с релизом PostgreSQL 9.0. Прошло уже более 10 лет, однако, пока ни один релиз не включил в себя штатные механизмы переключения между мастером и репликой. Из-за этого могут возникать различные проблемы. Рассмотрим, какие они бывают, на типичных кейсах.

Кейс 1 идеальный (без потери данных)

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

Кейс 2 более проблемный (часть данных потеряна)

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

Кейс 3 самый неприятный (split brain)

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


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

Есть ли решение?


Тут мы не забываем, что PostgreSQL opensource-продукт, и его можно дорабатывать. Сторонние компании разрабатывали свои утилиты для обеспечения high availability и автоматического переключения между master и standby. Самые популярные из них:

  • Corosync/pacemaker. С помощью Corosync мы можем соединить ряд серверов в один кластер, а pacemaker позволяет управлять PostgreSQL как одним из сервисов внутри кластера.
  • Stolon. Создает дополнительные компоненты как proxy, являющийся точкой входа для пользователей и приложений, keeper, который управляет PostgreSQL, и sentinel, который, в свою очередь, управляет keeper и proxy.
  • repmgr. Утилита для управления реплицией и переключениями, использующая встроенный протокол репликации PostgreSQL.
  • Patroni. На мой взгляд, самый интересный продукт. В отличие от других продуктов и утилит Patroni является шаблоном для построения high availability для PostgreSQL. В качестве компонентов для обеспечения того или иного функционала можно использовать различные решения, что очень положительно сказывается на гибкости и возможности кастомизации построения high availability. Поэтому именно на patroni предлагаю взглянуть внимательнее.

Знакомство с Patroni


Patroni показал себя как тот самый вожак стада, который с течением времени проявил себя как самый сильный и выносливый слон. Данная утилита сейчас является де-факто стандартом для обеспечения high availability для PostgreSQL.



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


Теперь появляется следующий компонент DCS (distributed consensus system).
Из названия уже понятно, что эта система нужна для обеспечения консенсуса. С помощью DCS мы однозначно можем определить, где у нас мастер. И если у нас возникают с ним какие-то проблемы, то этот компонент позволяет нам выбрать новый мастер и продолжить работу с ним. В качестве компонента DCS могут выступать: etcd, протокол raft, Kubernetes, zookeeper, aws callbacks и так далее. Самые интересные для нас первые три.

  • etcd: это распределенное хранилище типа ключ-значение, объединенное в кластер. Оно может быть установлено как на отдельно стоящих серверах, так и на серверах, где уже установлен PostgreSQL вместе с Patroni.
  • протокол raft: отмечу, что сам etcd работает на протоколе raft, и вместе с релизом версии Patroni 2.0 появилась возможность не устанавливать целую базу etcd, а использовать чистый протокол raft. Это очень упрощает эксплуатацию решения и позволяет использовать на один компонент меньше.
  • Kubernetes: этот компонент как раз нам и нужен для разворачивания Patroni внутри кластера Kubernetes, где уже есть своя etcd-база. С помощью API вызовов к этой etcd-базе мы можем обеспечивать консенсус в нашем Patroni кластере.




Еще один компонент Load balancer, он опциональный в архитектуре Patroni. Может быть полезен для балансировки нагрузки на primary или на standby. Еще один случай применения Load balancer необходимость единой точки входа к нашим PostgreSQL-базам. Вы всегда можете подключиться к одному и тому же IP, который, в свою очередь, уже будет прикреплен к серверу, где у нас располагается мастер. Внутри Райффайзенбанка в качестве Load balancer для Patroni мы используем vip-manager.



Гладя на такую архитектуру, с высокой доступностью и отказоустойчивостью, возникла идея а что если перенести ее в Kubernetes?

Воплощаем задуманное: PostgreSQL кластер внутри Kubernetes


Механизмы для обеспечения high availability


Начнем с контроллеров Deployment, позволяет управлять stateless-приложениями, и StatefulSet, позволяет управлять statefull-приложениями. Возможно, непонятно, что это за слова.

Поясню на примерах
Stateless-приложения приложения, которым не нужно хранить свое состояние. Самым популярным примером для stateless-приложения является web-сайт. Ему необязательно хранить свое состояние. Вы размещаете его в виде deployment внутри Kubernetes, и он отлично, при необходимости, масштабирует нагрузку: нагрузка возросла он создал дополнительное количество podов, чтобы обработать всю возросшую нагрузку на сайт.

Statefull-приложения. Они уже как раз должны хранить свое состояние. Самым популярным примером statefull-приложения является база данных.

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

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

Опять же, наглядно, есть задача вывести в режим обслуживания два сервера. Podы, которые крутятся на этих серверах, будут недоступны. Kubernetes требуется решить такую проблему. Что делаем: задаем PodDisruptionBudget в количестве одной штуки. И, соответственно, в этой ситуации сначала у нас переедет один pod на другой сервер. Ждем, пока он станет доступен. И теперь второй pod тоже переедет на другой сервер. Приложение будет корректно продолжать свою работу.



Хранение данных


Один из вариантов хранить данные в сетевом блочном устройстве Network Block Device. В нашем случае в Kubernetes кластере создаем StatefulSet, с базой данных. Kubernetes умеет создавать по шаблону диски для podов из Network Block Device. Соответственно, оттуда выделились диски и прикрепились к podам, и наш StatefulSet корректно начал работать.



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



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



Kubernetes-операторы


Познакомимся с самыми популярными операторами, которые существуют для работы PostgreSQL внутри Kubernetes.

Crunchy Data
У этого оператора есть лицензия Apache 2.0, поэтому при желании можно использовать этот продукт бесплатно. Если нужна поддержка, то ее можно приобрести за плату. Кстати, из плюсов этот продукт поддерживается и в Kubernetes, и в OpenShift, и в VMware PKS. Ну, и ключевой особенностью для этого и для других Kubernetes-операторов (которые обсудим далее) является то, что для обеспечения high availability самого PostgreSQL используется компонент Patroni. Так что он является де-факто стандартом для обеспечения high availability как внутри Kubernetes, так и на обычных серверах.

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

Zalando postgres-operator
Еще один интересный Kubernetes-оператор. И вот почему: именно компания Zalando разработала Patroni, и в продолжение своей разработки они написали этот оператор, чтобы их продукт мог также работать в кластерах Kubernetes.
У Zalando есть лицензия MIT, которая позволяет бесплатно использовать этот продукт. Но тут ребята не предоставляют платной поддержки, и если вы решите использовать именно его, то саппортить его вам нужно будет своими силами.

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

Также стоит отметить, что Crunchy Data и Stackgres имеют внутри себя встроенные средства для мониторинга PostgreSQL, чего, к сожалению, нет в postgres-operarot'е от Zalando.

В качестве итогов: плюсы и минусы размещения БД PostgreSQL внутри Kubernetes


Почему удобно разрабатывать:

  • база данных живет рядом с приложением
  • уменьшение time to market
  • полный переход на методологию CI/CD


И что стоит иметь в виду при разработке:

  • нагруженным базам данных нужны быстрые диски
  • шумные соседи: тут нужно ограничить использование ресурсов podами
  • дополнительные сетевые задержки внутри Kubernetes задерживают работу базы данных

Глобальный лаконичный вывод использовать PostgreSQL внутри Kubernetes нужно осторожно :) Учитывайте все возможные минусы и подводные камни, которые могут вам встретиться. Зная про все нюансы, вы успешно сможете использовать базу данных внутри Kubernetes!

>>> В этой статье поделился основными тезисами и добавил новые подробности из доклада на IT-конференции code/R. Посмотреть вживую и послушать все выступление можно тут.
Подробнее..

Выступает DMN, дирижирует ZeeBe как использовать бизнес-правила в микросервисах

11.03.2021 18:13:13 | Автор: admin

Меня зовут Николай Первухин, я Senior Java Developer в Райффайзенбанке. Так сложилось, что, единожды попробовав бизнес-процессы на Camunda, я стал адептом этой технологии и стараюсь ее применять в проектах со сложной логикой. Действительно сама идея подкупает: рисуешь процесс в удобном GUI-редакторе (моделлере), а фреймворк выполняет эти действия по порядку, соблюдая большой спектр элементов нотации BPMN.

К тому же в Camunda есть встроенная поддержка еще одной нотации DMN (Decision Model and Notation): она позволяет в простой и понятной форме создавать таблицы принятия решений по входящим наборам данных.

Но чего-то все же не хватает... Может, добавим немного скорости?

Почему ускоряем процессы

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

Что обычно характеризует такие процессы:

  • от момента создания до завершения процесса может пройти несколько дней;

  • участвует большое количество сотрудников;

  • осуществляется интеграция со множеством банковских подсистем.

Фреймворк Camunda прекрасно справляется с такими задачами, однако, заглянем под капот: там находитсяклассическая база данных для осуществления транзакционности.

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

Отличные новости: воспользуемся ZeeBe

В июле 2019 года было официально объявлено, что после двух лет разработки фреймворк ZeeBe готов к использованию на боевой среде. ZeeBe специально разрабатывался под задачи highload и, по утверждению автора, был протестирован при 10 000 процессов в секунду. В отличие от Camunda, ядро фреймворка ZeeBe принципиально не использует базу данных из него убраны все вспомогательные подсистемы, в том числе и процессор правил DMN.

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

Итак, дано:

  • микросервис, инициирующий событие и запускающий процесс (event-handler);

  • микросервис обработки бизнес-правил (rules-engine);

  • микросервис, эмулирующий действия (action).

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

Из оркестрации у нас:

  • микросервис с брокером сообщений ZeeBe (zeebe);

  • микросервис визуализации работающих процессов simplemonitor (zeebe-simple-monitor).

А присматривать за всеми микросервисами будет кластер k8s.

Схема взаимодействия

С точки зрения бизнес-логики в примере будет рассмотрен следующий бизнес-сценарий:

  • из внешней системы происходит запрос в виде rest-обращения с передачей параметров;

  • запускается бизнес-процесс, который пропускает входящие параметры через бизнес-правило;

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

Теперь поговорим подробнее о каждом микросервисе.

Микросервис zeebe

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

Принцип ZeeBe минимальное число компонентов, входящих в ядро, поэтому по умолчанию ZeeBe это брокер сообщений, работающий по схемам BPMN. Дополнительные модули подключаются отдельно: например, для отображения процессов в GUI понадобится экспортер (доступны разные экспортеры, к примеру, в ElasticSearch, в базу данных и т.п.).

В данном примере возьмемэкспортер в Hazelcast. И подключим его:

  • добавим zeebe-hazelcast-exporter-0.10.0-jar-with-dependencies.jar в папку exporters;

  • добавим в файл config/application.yamlследующие настройки:

exporters:      hazelcast:        className: io.zeebe.hazelcast.exporter.HazelcastExporter        jarPath: exporters/zeebe-hazelcast-exporter-0.10.0-jar-with-dependencies.jar        args:          enabledValueTypes: "JOB,WORKFLOW_INSTANCE,DEPLOYMENT,INCIDENT,TIMER,VARIABLE,MESSAGE,MESSAGE_SUBSCRIPTION,MESSAGE_START_EVENT_SUBSCRIPTION"          # Hazelcast port          port: 5701

Данные активных процессов будут храниться в памяти, пока simplemonitor их не считает. Hazelcast будет доступен для подключения по порту 5701.

Микросервис zeebe-simplemonitor

Во фреймворке ZeeBe есть две версии GUI-интерфейса. Основная версия, Operate, обладает большим функционалом и удобным интерфейсом, однако, использование Operate ограничено специальной лицензией (доступна только версия для разработки, а лицензию для прода следует запрашивать у производителя).

Также есть облегченный вариант simplemonitor (лицензируется по Apache License, Version 2.0)

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

Можно выбрать любую базу данных Spring Data JDBC, в данном примере используется файловая h2, где настройки, как и в любом Spring Boot приложении, вынесены в application.yml

spring:  datasource:    url: jdbc:h2:file:/opt/simple-monitor/data/simple-monitor-db;DB_CLOSE_DELAY=-1

Микросервис event-handler

Это первый сервис в цепочке, он принимает данные по rest и запускает процесс.При старте сервис осуществляет поиск файлов bpmn в папке ресурсов:

private void deploy() throws IOException {        Arrays.stream(resourceResolver.getResources("classpath:workflow/*.bpmn"))                .forEach(resource -> {                    try {                        zeebeClient.newDeployCommand().addResourceStream(resource.getInputStream(), resource.getFilename())                                .send().join();                        logger.info("Deployed: {}", resource.getFilename());                    } catch (IOException e) {                        logger.error(e.getMessage(), e);                    }                });    }

Микросервис имеет endpoint, и для простоты принимает вызовы по rest. В нашем примере передаются 2 параметра, сумма и лимит:

http://адрес-сервиса:порт/start?sum=100&limit=500
@GetMapping    public String getLoad(@RequestParam Integer sum, @RequestParam Double limit) throws JsonProcessingException {        Map<String, Object> variables = new HashMap<>();        variables.put("sum", sum);        variables.put("limit", limit);        zeebeService.startProcess(processName, variables);        return "Process started";    }

Следующий код отвечает за запуск процесса:

 public void startProcess(String processName, Map<String, Object> variables) throws JsonProcessingException {         zeebeClient.newCreateInstanceCommand()                .bpmnProcessId(processName)                .latestVersion()                .variables(variables)                .send();    }

Сам процесс нарисован в специальной программе ZeeBe modeler (почти копия редактора Camunda modeler) и сохраняется в формате bpmn в папке workflow в ресурсах микросервиса. Графически процессвыглядит как:

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

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

После старта процесс продвинется на один шаг, и появится сообщение типа DMN.

Микросервис rules-engine

Благодаря прекрасной модульной архитектуре Camunda есть возможность использовать в своем приложении (отдельно от самого фреймворка Camunda) движок правил принятия решения.

Для его интеграции с вашим приложением достаточно добавить его в зависимости maven:

        <dependency>            <groupId>org.camunda.bpm.dmn</groupId>            <artifactId>camunda-engine-dmn</artifactId>            <version>${camunda.version}</version>        </dependency>

Сами правила создаются в специальном графическом редакторе Camunda modeler. Одна диаграмма DMN имеет два вида отображения.

Entity Relation Diagram (вид сверху) показывает зависимости правил друг от друга и от внешних параметров:

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

Само же бизнес-правило содержит более детальный вид:

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

Посмотрим на примере, где такой файл располагается в папке dmn-models в ресурсах микросервиса. Для регистрации диаграммы при старте микросервиса происходит его однократная загрузка:

 public void init() throws IOException {        Arrays.stream(resourceResolver.getResources("classpath:dmn-models/*.dmn"))                .forEach(resource -> {                    try {                        logger.debug("loading model: {}", resource.getFilename());                        final DmnModelInstance dmnModel = Dmn.readModelFromStream((InputStream) Resources                                .getResource("dmn-models/" + resource.getFilename()).getContent());                        dmnEngine.parseDecisions(dmnModel).forEach(decision -> {                            logger.debug("Found decision with id '{}' in file: {}", decision.getKey(),                                    resource.getFilename());                            registry.put(decision.getKey(), decision);                        });                    } catch (IOException e) {                        logger.error("Error parsing dmn: {}", resource, e);                    }        });    }

Для того, чтобы подписаться на сообщения от ZeeBe, требуется осуществить регистрацию workerа:

private void subscribeToDMNJob() {        zeebeClient.newWorker().jobType(String.valueOf(jobWorker)).handler(                (jobClient, activatedJob) -> {                    logger.debug("processing DMN");                    final String decisionId = readHeader(activatedJob, DECISION_ID_HEADER);                    final Map<String, Object> variables = activatedJob.getVariablesAsMap();                    DmnDecisionResult decisionResult = camundaService.evaluateDecision(decisionId, variables);                    if (decisionResult.size() == 1) {                        if (decisionResult.get(0).containsKey(RESULT_DECISION_FIELD)) {                            variables.put(RESULT_DECISION_FIELD, decisionResult.get(0).get(RESULT_DECISION_FIELD));                        }                    } else {                        throw new DecisionException("Нет результата решения.");                    }                    jobClient.newCompleteCommand(activatedJob.getKey())                            .variables(variables)                            .send()                            .join();                }        ).open();    }

В данном коде осуществляется подписка на событие DMN, вызов модели правил при получении сообщения от ZeeBe и результат выполнения правила сохранятся обратно в бизнес-процесс в виде переменной result (константа RESULT_DECISION_FIELD).

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

Микросервис action

Микросервис action совсем простой. Он также осуществляет подписку на сообщения от ZeeBe, но другого типа action.

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

Также передачу параметров можно сделать и через закладку Input/Output, тогда параметры придут вместе с переменными процесса, но передача через headers является более каноничной.

Посмотрим на получение сообщения в микросервисе:

private void subscribe() {        zeebeClient.newWorker().jobType(String.valueOf(jobWorker)).handler(                (jobClient, activatedJob) -> {                    logger.debug("Received message from Workflow");                    actionService.testAction(                            activatedJob.getCustomHeaders().get(STATUS_TYPE_FIELD),                            activatedJob.getVariablesAsMap());                    jobClient.newCompleteCommand(activatedJob.getKey())                            .send()                            .join();                }        ).open();    }

Здесь происходит логирование всех переменных бизнес-процесса:

 public void testAction(String statusType, Map<String, Object> variables) {        logger.info("Event Logged with statusType {}", statusType);        variables.entrySet().forEach(item -> logger.info("Variable {} = {}", item.getKey(), item.getValue()));    }

Исходный код

Весь исходный код прототипа можно найти в открытом репозитории GitLab.

Компиляция образов Docker

Все микросервисы проекта собираются командой ./build.sh

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

Загрузка микросервисов в кластер k8s

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

  1. Создать namespace в кластере kubectl create namespace zeebe-dmn-example

  2. Создать config-map общих настроек

kind: ConfigMapapiVersion: v1metadata:  name: shared-settings  namespace: zeebe-dmn-exampledata:  shared_servers_zeebe: <IP адрес кластера>

Далее создаем два персистентных хранилища для хранения данных zeebe и simplemonitor. Это позволит осуществлять перезапуск соответствующих подов без потери информации:

kubectl apply -f zeebe--sm-volume.yml

kubectl apply -f zeebe-volume.yml

Yml-файлы находятся в соответствующих проектах:

Теперь осталось последовательно создать поды и сервисы. Указанные yml-файлы находятся в корне соответствующих проектов.

kubctl apply -f zeebe-deployment.yml

kubctl apply -f zeebe-sm-deployment.yml

kubctl apply -f event-handler-deployment.yml

kubctl apply -f rules-engine-deployment.yml

kubctl apply -f action-deployment.yml

Смотрим, как отображаются наборы подов в кластере:

И мы готовы к тестовому запуску!

Запуск тестового процесса

Запуск процесса осуществляется открытием в браузере соответствующий URL. К примеру, сервис event-handler имеет сервис с внешним IP и портом 81 для быстрого доступа.

http://адрес-кластера:81/start?sum=600&limit=5000
Process started

Далее можно проверить отображение процесса в simplemonitor. У данного микросевиса тоже есть внешний сервис с портом 82.

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

Теперь можно просмотреть лог микросервиса action, там можно увидеть значение переменной statusType, которое соответствует варианту прохождения процесса.

Поделюсь, какими ресурсами пользовался для подготовки прототипа

Небольшое послесловие вместо итогов

Из плюсов:

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

  • простая нотация BPMN и DMN позволяет привлекать аналитиков и бизнес к обсуждению сложной логики;

  • Zeebe показал себя как очень быстрый фреймворк, задержки на получение/отправку сообщений практически отсутствуют;

  • Zeebe изначально разрабатывался для работы в кластере, в случае необходимости можно быстро нарастить мощности;

  • без ZeeBe Operate можно вполне обойтись, Simple-Monitor отвечает минимальным требованиям.

Из минусов:

  • хотелось бы иметь возможность редактирования DMN непосредственно в ZeeBe modeler (как это реализовано в Camunda), на данный момент, приходится использовать оба моделлера;

  • к сожалению, только в Enterprise версии Camunda есть возможность просмотра пути, по которому принималось решение:

Это очень полезная функция при отладке правил. В Community версии приходится добавлять дополнительное поле типа output для логирования, либо разработать свое решение визуализации.

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

Где применять такие технологии:

  • как оркестрация внутри одной команды или продукта в виде перекладывания сложной логики на диаграммы BPMN / DMN;

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

  • как частичная альтернатива существующего стека ESB или Kafka для интеграции между командами.

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

Подробнее..

QA Online Meetup 2411

19.11.2020 18:06:36 | Автор: admin
Присоединяйтесь на второй открытый митап 24 ноября, который посвятим интеграционному тестированию. Приготовили отличные доклады, и вот о чем поговорим: зачем и как использовать Cypress для интеграционного тестирования, и возможно ли добиться нуля ошибок по таким тестам?

Ждем вас онлайн!



О чем будем говорить


Cypress для интеграционного тестирования. Зачем? Как?

Светлана Голдобина, Райффайзенбанк

О спикере: Старший тестировщик в Райффайзенбанке, команда Cash Management. Опыт в автоматизации тестирования больше 3-х лет в крупных банках. За карьерный путь успела поработать как с BDD фреймворками, в том числе Akita, и поучаствовать в ее развитии, так и перейти полностью на сторону тестирования на стеке разработчиков JavaScript/TypeScript, Java + Spring.

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

О докладе: В нашей команде писали тесты в BDD стиле на русском языке (Selenium/Selenide + Cucumber + Java). Казалось бы, куда еще проще и прозрачнее для команды? Однако, как только мы лишились нескольких QA, и разработчикам пришлось писать и дорабатывать тесты, наш инструмент стал стоппером в тестировании, и BDD тут ничем не помог. В докладе расскажу, как мы опустили тестирование на дно и начали его восстанавливать.

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

Максим Плавченок, Bercut

О спикере: Работаю в компании Bercut с 2002. Начинал карьеру в телекоме: прошёл путь от сменного инженера до руководителя направления интеграционного тестирования. Был разработчиком, тестировщиком, менеджером продукта. Люблю заниматься тем, что приносит проблемы (и решать их), поэтому и пришёл в тестирование.

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

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

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

>>> Начнем митап в 18:00 (МСК).
Зарегистрируйтесь, чтобы получить ссылку: письмо с трансляцией придет на почту всем участникам.

До встречи онлайн!
Подробнее..

Acceleration Community Meetup 2801

21.01.2021 16:23:47 | Автор: admin
Ждем вас на онлайн-митап Acceleration Community 28 января: поделимся опытом смены инструмента в большой организации, вместе познаем искусство удерживать баланс между бизнес-ценностями и техническим долгом, а также узнаем, какой он современный подход к безопасной разработке в крупных IT-компаниях.

Регистрируйтесь и присоединяйтесь к нам!



О чем поговорим


Из зоопарка в лунапарк, или как мы всем банком Gitlab внедряли

Сергей Куприянов, Райффайзенбанк

О спикере: Сергей product owner команды backend tools, части acceleration team. Команда разрабатывает и внедряет инструменты для разработчиков внутри Райффайзенбанка. Сергей пришел в банк тестировщиком, работал в команде финансов. Сейчас занимается, инфраструктурными проектами, DevOps, CI/CD процессами.

О докладе: Казалось бы, совсем недавно мы избавились от зоопарка инструментов и перешли на стек Atlassian и Bamboo, в частности, но счастье оказалось недолгим наши запросы возросли, и мы встали перед необходимостью выбора нового инструмента Ci/Cd.

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

Искусство канатоходца бизнес и искусство

Андрей Юмашев, ЛитРес

О спикере: CTO по информационному обеспечению в ЛитРес. Более 15 лет в IT, последние несколько лет евангелист DevOps-философии, специалист по построению коммуникаций и процессов в IT-части бизнеса.

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

Cовременный подход к безопасной разработке в крупных IT-компаниях

Владимир Пазухин, Ernst & Young (EY)

О спикере: Владимир менеджер компании Ernst & Young, с 2013 года занимается выполнением проектов в области кибербезопасности и специализируется на тестировании защищенности приложений, анализе безопасности исходного кода, анализе рисков информационных систем и совершенствовании процессов кибербезопасности. Область интересов: интеграция контролей и тестов информационной безопасности в процессы DevOps, анализ уязвимостей современных онлайн-сервисов и мобильных приложений, а также автоматизация выявления подобных уязвимостей.

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

>>> Начнем митап в 18:00 (МСК).
Регистрируйтесь, чтобы получить ссылку на трансляцию: письмо придет вам на почту.

До встречи online!
Подробнее..

Scrum Community Meetup 1102

09.02.2021 16:13:11 | Автор: admin

Нельзя просто так взять и взрастить своих скрам-мастеровесть очень много нюансов, которые стоит учесть. Об этом поговорим на онлайн-митапе со спикерами QIWI, Газпромбанка и Райффайзенбанка.

О чем поговорим

2 провала, 1 успех

Антон Бевзюк, Райффайзенбанк

Как мы запускали Scrum Bootcamp и ProScrum в 2020. Я расскажу, как мы дважды НЕ запустили Scrum Bootcamp в 2020, какие уроки из этого извлекли и почему сменили фокус на внутреннее обучение и запустили курс ProScrum.

Наталья Стрельникова, Райффайзенбанк
Адженда скоро появится, ждем подробностей :)

Путь Scrum-джедая

Максим Гапонов, QIWI

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

какие стадии развития Scrum-мастера мы выделили;

какие есть супер-способности и ловушки у каждой стадии;

как понимание этого пути помогает нам подбирать способы и форматы поддержки развития Scrum-мастера.

Scrum master customs

Андрей Редин, Газпромбанк

Я расскажу про развитие скрам-мастера на уровне ШУ, ХА и РИ. Как найти баланс между массовым и индивидуальным подходом.

>>> Активничаем с сообществом в Telegram: присоединяйтесь к Scrum Community @ Raiffeisenbank!

Начнем митап в 19:00 (мск).
Регистрируйтесь, чтобы получить ссылку на трансляцию: письмо придет вам на почту.

До встречи онлайн!

Подробнее..

RAIFHACK История про хакатон, который смог

08.12.2020 16:17:05 | Автор: admin


Если помните, недавно мы публиковали анонс хакатона RAIFHACK, который прошел онлайн 14-15 ноября совместно с командой Russian Hackers. Казалось бы, это обычный хакатон. Но на нем было все: отрицание, гнев, торг, депрессия, принятие, шутки и, конечно же, мемасы.

Основной повесткой RAIFHACK было создание решений для малого и среднего бизнеса в двух треках:

  • Знай клиента и конкурента это об использовании данных. Участники разрабатывали продукт в парадигме Data as a Service на основе анонимизированных клиентских данных.
  • Платить легко это об использовании API системы быстрых платежей. Здесь предлагали полезные для бизнес-клиентов решения на основе API СБП от Райффайзенбанка, которые упростят работу с покупателями.

Про темы и сам хакатон


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

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

Если говорить о продуктах в парадигме Data as a Service, то предыстория такая: в 2019 году после многочисленных кастдевов с партнерами программ лояльности, мы получили следующую картину: бизнес остро ощущает нехватку объективной информации о своих клиентах в реальном конкурентном окружении.

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

Формат, регистрации, таймлайн


В организации RAIFHACK мы решили не идти путем классического хакатона, когда команды получают задачу и 24-48-72 часа на ее выполнение. Нам хотелось, чтобы участники изначально погрузились в сам продукт. Поэтому CJM был таким:

  • зарегистрироваться командой;
  • ознакомиться с задачей трека и прислать свою идею продукта;
  • пройти отбор на финал;
  • получить на финале датасет и доступ к API, допилить продукт и представить демо.

Тема хакатона вышла узкой, но мы получили 900+ индивидуальных регистраций, 100+ командных решений на этапе отбора, а в финал вышло 28 команд.

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

Получив на отборе 60 идей в треке DaaS и 51 в СБП, мы приступили к оценке заявок. Решения смотрели менторы треков: как минимум продуктовый и технический + дополнительные. Уже на этапе отбора мы оценивали, насколько реализуемо решение например, в треке DaaS огромный вес имела DS-составляющая, отчего многие команды получили в этой части очень низкий балл. Эти оценки вызвали много гнева. Как и то, что некоторые проекты были просмотрены бОльшим количеством менторов, другие меньшим, и те, что вызвали более живой интерес, получили и рейтинг повыше. В целом это соответствует реальной ситуации, когда стартап презентует идею инвестору.


Не обошлось без эмоциональных реакций :)

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

По поводу системы оценок готовых решений дискутировать можно вовсе бесконечно. У нас одно видение, у некоторых участников другое. Гнев породил собой гневные комментарии, мемасы и демотиваторы (sic!).



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



Несмотря на все, финал все же состоялся и прошел 14-15 ноября. Расписание было крайне плотным, и мы ожидали, что от одной до трёх команд просто не дойдут до конца это нормально для подобных хакатонов. Удивительно, но у нас до конца дошли все!

Хакатон, кодинг и хардкор


Расписание хакатона жесткое, датасет огромный, пилить приходилось немерено, а еще целых 3 точки контроля менторами и не протестированный командами API. Участникам приходилось подключаться и сдавать, что есть, иначе команда снимается с дистанции.

Все чек-поинты мы разбили на 3 этапа:

  • идея и план реализации;
  • черновая версия прототипа;
  • правки прототипа + обсуждение презентации.

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

Сетка чек-поинтов со стороны менторов выглядела примерно так:



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

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

Демо и питчи


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

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

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

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

Победитель DaaS команда DS29




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

Задача проекта: разработать продукт в парадигме Data as a Service на основе данных о клиентах и их транзакциях.

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



Здесь можно скачать презентацию проекта.

Я ожидала получить фидбек на первоначальную идею, проработать ее и, получить мерч и поесть :) Конечно, мы хотели выиграть и сделали все, чтобы этого достичь. Здорово, что нам удалось Анастасия Кишкун, тимлид и аналитик команды.

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

Победитель СБП команда LIFE Laboratory




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

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

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



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

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



Здесь можно скачать презентацию проекта.

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

Все презентации команд можно посмотреть и оценить здесь, а вот тут есть еще и церемония награждения.

Общий призовой фонд составлял 500 000 рублей. В каждом треке за первое место был выплачен денежный приз в размере 150 000 рублей на команду, а также подарен расширенный пак фирменного мерча нашего банка. За второе место выплачивалось по 100 000 рублей. За третье место каждый участник получил airpods и мерч. Все остальные команды получили мерч и нашу безграничную благодарность за участие, а создателю петиции на change.org мы презентовали фирменные тапочки, которым он был очень рад :)



Увидимся на следующем RAIFHACK!
Подробнее..

Demo Day в Райффайзенбанке какие продукты и сервисы показали команды

19.04.2021 12:12:03 | Автор: admin

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

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

Начинаем трансляцию

Устроились поудобнее и заглянули в zoom, где уже встречаем всех гостей приветственным словом Сергея Монина, председателя правления банка, и играем в квиз, чтобы получить приятный подарок фирменный мерч Open Demo Day Райффайзенбанка.

Теперь переходим к главному, ради чего собрались: восемь демо восемь суперфич!

20:44 >>> Сервис для оптимизации работы курьерской доставки
Команды: Customer Relations for PI, Site, Cards, Notifications & On Demand Development

Показываем, как организовали доставку банковских продуктов для физических и юридических лиц. Начиналось все с нескольких десятков доставок в месяц, и вот у нас уже работает собственная курьерская служба. Большие объемы и стремительное развитие бросают вызовы: нужно соответствовать высоким ожиданиям клиентов и автоматизировать процессы. Для этого и разрабатываем сервис, а под капотом используем наработки собственного open-source решения ViennaNET.

Задавали вопросы? Отвечаем здесь

Подсказки при заполнении ФИО с помощью Dadata? Пользователям нравится? На форме заявки ФИО заполняется при помощи подсказок сервиса Dadata, в том числе пол клиента определяется автоматически. A/b тестирование показало большой прирост конверсии в заявку с использованием этого сервиса.

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

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

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

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

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

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

Мобильные приложения нативны под обе платформы? Только под Android. Ввиду экономики оснащать курьеров телефонами с хорошими характеристиками ОС и камеры дешевле на Android.

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

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

Как считаете экономику? Какие KPI стоят перед командой? Экономика завязана на стоимости доставки. KPI NPS, скорость доставки и конверсия от заявки в выданный продукт.

Как документы попадают в ПО курьерки? Можно ли их изменить силами курьера? В ПО попадают фото документов. Документы на бумаге курьерам для изменения недоступны.

42:19 >>> Переводы по номеру телефонав мобильном банке
Команда Instant &Easy

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

Задавали вопросы? Отвечаем здесь

Как СБП изменил процесс перевода денег? Радикально упростил межбанковские переводы, ради которых раньше пользователи специально открывали карты определенных банков.

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

Перевод по Bluetooth, осуществляется только при версии 5? Если нет, то как защитите перевод? Переводы по Bluetooth полностью безопасны, вне зависимости от версии.

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

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

Какой для вас приоритетный канал перевода как для банка? Перевод по карте или по телефону? По телефону более приоритетный и более быстрорастущий канал.

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

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

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

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

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

Если будет комиссия, то как будут показываться % или сумма, если сумма большая, то как это выглядит? Будет показываться сумма комиссии, чтобы пользователю всегда было понятно, сколько денег он заплатит.

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

Какой процент активных пользователей мобильного банка от общего количества клиентов банка? Примерно 2/3.

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

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

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

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

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

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

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

1:02:58 >>> Интеграция банковских услуг в SAP
Команда CDC Integrations

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

1:22:55 >>> Опросник NPS для кандидатов
Команда Recruitment Dev Team

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

Задавали вопросы? Отвечаем здесь

8 вопросов достаточно много. Текст в свободной форме практически никогда не заполняют, как менялась ваша анкета по NPS со временем? Планируете ли что-то менять в анкете в ближайшее время, какие в анкете сейчас есть явно слабые места? Это второй вариант анкеты, поменялись формулировки вопросов, их стало на один меньше. Хороший response rate (23%) показывает, что ответ на эти вопросы несильно напрягает респондентов. Мы планируем создать и другие варианты анкеты. Комментарий в свободной форме оставили около 50% кандидатов из числа тех, кто заполнил опросник.

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

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

А вы считаете eNPS уже текущего состава команды? Пока нет.

Используется ли ваш продукт для переоценки сотрудников/чекапов/чекпойнтов и т.д.? Или это только про внешний рекрутмент? Продукт используется только для рекрумента.

Накладываете ли вы эти данные на карту пути кандидата? Отдельно или внутри вашей команды? Интересное предложение, спасибо!

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

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

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

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

1:45:43 >>> Омниканальная чат-платформа собственной разработки
Команда Chat

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

Задавали вопросы? Отвечаем здесь

Есть ли у оператора мобильное приложение с чатом? Чтобы он мог общаться с клиентами вне фиксированного рабочего места. Нет. Наши операторы сейчас могут работать и из дома (не обязательно из офиса), так что проблема по итогам 2020 стала неактуальна).

Используется ли на входящей линии КЦ голосовой бот (не IVR)? Да, уже работает в проде с сентября. Сейчас обрабатывает 90% входящих обращений, дает персонализированные ответы и 20% из них закрывает е2е. При этом не мучает клиента просьбами переформулировать вопрос :) Старый IVR остался только в 10% операций (на входе и 1-2 малых ветках). Чуть позже и их убьем.

Какое максимальное количество диалогов у оператора? Зависит от оператора. Каких-то ограничений не вводим.

Ведется ли сбор статистики по тематикам обращений? Как будет реализовано на этой платформе? Сбор тематик реализован на базе отдельного решения речевая аналитика. Уже успешно работает.

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

Вот у вас диалог ждал, пока оператор вернется... А если оператор не вернулся по каким-либо причинам? Все, клиент повис? Состояние диалогов постоянно мониторит руководитель данной группы/сектора. К клиенту обязательно вернутся.

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

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

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

Участвуете ли вы в каких-либо сторонних исследованиях, или сами проводите все продуктовые исследования и в стороннем нет потребности? Проводим как свои исследования (опросы, проблемные интервью), так и внешние(мистери шоппинг, UX аудит, рэнкинги).

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

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

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

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

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

P.S. Intercom отличный пример, решение приетарно облачное, поддерживает только live-chat (чат на сайте) и очень плохо (мне неизвестны кейсы) встраивается в приложение, заточено под собственное бот-решение (а это не конек intercom, так как по факту есть rule-based решение). А для нас чат на сайте это 5-10% траффика. Решение Intercom в целом не является чат-платформой и отвечает на другие вопросы (к примеру, у коллег большой фокус на маркетинг, онбординг продуктов, что не является частью чат-платформ).

2:08:46 >>> Автоматический процесс принятия решения по заявке
Команда Personal Loans

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

Задавали вопросы? Отвечаем здесь

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

Какое количество внешних сервисов подключено к СПР? Всего девять, из них семь влияют на принятие решения по заявке.

А что если номер телефона у клиента начинается с 8? По умолчанию указываем +7. Можно изменить.

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

Планируете ли автоматически загружать данные клиентов из Цифрового Профиля Госуслуг? Да, такие работы ведутся.

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

Кешируются ли данные, полученные из БКИ, чтобы не портить историю частыми запросами? Да, данные кешируются.

Как идет одобрение и оформление карты dual to credit по данному процессу? В пилотном решении выдача дуальной карты не предусмотрена. В дальнейшем функционал будет расширяться и дополняться.

2:26:07 >>> Цифровой маркетинг Райффайзен-Лизинг, новый сайт и маркетплейс
Команда Leasing

Для лизинга 2020 был непростым: в целом рынок упал на 6%. Что делала наша команда в прошлом году? Запустили цифровой Лизинг автомобилей и спецтехники и предоставили доступ в систему нашим партнерам. Еще активно занимались развитием сайта и маркетплейса: появился раздел по каталогам автомобилей и условиям и более заметная кнопка с оформлением заявки.

2:41:51 >>> Автоматизация исходящих платежей на базе блокчейн-платформы
Команды Technosoul Cash Management & Payments Service Team

Командами работали над интересной задачей проведение расчетов через собственную блокчейн-платформу R-chain. Как это все устроено? Есть несколько компаний покупатель и поставщик, есть банк, который поддерживает эти расчетные функции. Все участники на своих серверах устанавливают ноды, узлы блокчейна, и далее информационные системы участников объединяются в единую сеть. Так появляется возможность вести общий реестр сделок и расчетов. В теории объяснили, теперь показываем в действии на демо.

Спасибо, что были с нами!
Второй открытый Demo Day мы уже запланировали на ноябрь, следите за анонсами здесь, в нашем корпоративном блоге, и до следующей встречи :)

Подробнее..

Наследование в Nuget-пакетах

21.01.2021 14:15:10 | Автор: admin
image

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

А раз у нас есть объект, то что мешает попробовать посмотреть на работу с ним со стороны объектно-ориентированной парадигмы? Давайте попробуем применить для nuget-пакетов один из основных принципов ООП наследование.

Предположим, вам нужно сделать nuget-пакет на основе уже существующего, немного изменив его поведение.

Для примера, рассмотрим nuget-пакет с драйверами базы данных DB2: IBM.Data.DB2.Core.

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

Предположим, что у вас есть фреймворк, который использует ORM, например NHibernate. Он содержит специальную обвязку драйвера DB2, которая нужна для обеспечения доступа к этой базе данных через этот ORM: ViennaNET.Orm.DB2.Win.

Сборки внутри ViennaNET.Orm.DB2.Win конечно же ссылаются на IBM.Data.DB2.Core. Но если вы в каком-то новом проекте подключите только пакет ViennaNET.Orm.DB2.Win, то IBM.Data.DB2.Core автоматически не подключится. То есть, драйвера, необходимые для работы с БД, не появятся, если вы не используете менеджер пакетов, который разрешает транзитивные зависимости. В качестве примера такого менеджера можно упомянуть Paket.

Здесь есть несколько решений.

  1. Предложить потребителю пакета ViennaNET.Orm.DB2.Win учитывать транзитивную зависимость от пакета IBM.Data.DB2.Core. Это можно сделать вручную или с помощью автоматизированного инструмента типа ранее упоминаемого мною Paket.
  2. Полностью продублировать в проекте пакета ViennaNET.Orm.DB2.Win содержимое и поведение пакета IBM.Data.DB2.Core.
  3. Реализовать наследование содержимого и поведения пакета IBM.Data.DB2.Core в пакете ViennaNET.Orm.DB2.Win.

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

После того, как вы скачаете и разархивируете пакет IBM.Data.DB2.Core, вы увидите примерно такую структуру каталога:

image

В папке build находится папка clidriver с unmanaged-драйвером DB2 и targets-скрипт IBM.Data.DB2.Core.targets, который будет выполняться при сборке проекта, использующего этот пакет. Скрипт содержит следующие инструкции:

<Project xmlns="http://personeltest.ru/away/schemas.microsoft.com/developer/msbuild/2003">    <ItemGroup>        <None Include="$(MSBuildThisFileDirectory)clidriver\**" >            <Link>clidriver\%(RecursiveDir)%(FileName)%(Extension)</Link>            <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>        </None>    </ItemGroup></Project>

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

После сборки проекта в нем появиться папка с контент-ссылками. Причем это именно ссылки на файлы находящиеся в папке пакета IBM.Data.DB2.Core, в папку проекта они не копируются:

image

Теперь, хотелось бы повторить такое же поведение для пакета ViennaNET.Orm.DB2.Win в отношении его потребителя.

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

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

  1. В ссылке на базовый пакет вам нужно указать атрибут GeneratePathProperty="true". Это позволит создать переменную процесса сборки с именем, соответствующим имени пакета. Она нам нужна, так как будет указывать путь к папке с содержимым этого пакета. В самом имени символ '.' будет заменен на символ '_'.

    <ItemGroup>    <PackageReference Include="IBM.Data.DB2.Core"         Version="1.3.0.100"         GeneratePathProperty="true" /></ItemGroup>
    
  2. Добавить контент, ссылающийся на контент базового пакета. Символы '**' обозначают рекурсивное использование всех файлов.

    <Content Include="$(PkgIBM_Data_DB2_Core)\build\clidriver\**"     Pack="true" PackagePath="build\clidriver"     PackageCopyToOutput="false" />
    
  3. Добавить контент, ссылающийся на target-скрипт базового проекта. При этом, чтобы его выполнил MsBuild, необходимо переименовать target-скрипт по имени текущего проекта. Это можно сделать в атрибуте PackagePath.

    <Content Include="$(PkgIBM_Data_DB2_Core)\build\*.targets"     Pack="true" PackagePath="build\$(TargetName).targets"     PackageCopyToOutput="false" />
    

На этом всё.

Теперь при сборке пакета ViennaNET.Orm.DB2.Win в него будут добавлены файлы unmanaged-драйвера DB2 и target-скрипт из пакета IBM.Data.DB2.Core. Это позволит при подключении пакета ViennaNET.Orm.DB2.Win к новому проекту обеспечить размещение драйверов DB2 в папке сборки так, как это происходило бы при подключении пакета IBM.Data.DB2.Core.

Общий вид файла проекта будет выглядеть так:

<Project Sdk="Microsoft.NET.Sdk">  <PropertyGroup>    <TargetFramework>netstandard2.0</TargetFramework>    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>    <RuntimeIdentifiers>win-x64</RuntimeIdentifiers>  </PropertyGroup>  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">    <OutputPath>..\Bin</OutputPath>    <DocumentationFile>..\Bin\ViennaNET.Orm.DB2.Win.xml</DocumentationFile>  </PropertyGroup>  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">    <OutputPath>..\Bin</OutputPath>    <DocumentationFile>..\Bin\ViennaNET.Orm.DB2.Win.xml</DocumentationFile>  </PropertyGroup>  <ItemGroup>    <ProjectReference Include="..\ViennaNET.Orm\ViennaNET.Orm.csproj" />    <ProjectReference Include="..\ViennaNET.Protection\ViennaNET.Protection.csproj" />  </ItemGroup>  <ItemGroup>    <PackageReference Include="IBM.Data.DB2.Core" Version="1.3.0.100"         GeneratePathProperty="true" />  </ItemGroup>  <ItemGroup>    <Content Include="$(PkgIBM_Data_DB2_Core)\build\clidriver\**"         Pack="true" PackagePath="build\clidriver"         PackageCopyToOutput="false" />    <Content Include="$(PkgIBM_Data_DB2_Core)\build\*.targets"         Pack="true" PackagePath="build\$(TargetName).targets"         PackageCopyToOutput="false" />  </ItemGroup></Project>

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

Практическую реализацию решения с наследованием контента и поведения nuget-пакетов можно посмотреть в проекте ViennaNET на GitHub.
Подробнее..

Категории

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

  • Имя: Макс
    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