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

Блог компании yota

Готовьсь, цельсь, пли! Как не обжечься при сборке Gradle-приложения, и настолько ли всё серьезно?

18.03.2021 16:05:16 | Автор: admin

Доброго дня, читатель! Меня зовут Стручков Михаил и я Android-разработчик в команде мобильного оператора Yota.

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

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

Очень сложно рассмотреть работу всю работу с Gradle в одной статье, поэтому планирую последовательно пополнять список:

  1. Готовьсь, цельсь, пли! Как не обжечься при сборке Gradle-приложения, и настолько ли всё серьезно?

  2. Пишем свой Gradle-плагин

  3. Пишем эффективные Gradle-задачи

Для удобства навигации по статье, ниже представлено оглавление:

Структура проекта

Инициализация

Конфигурация плагинов

Подключение Gradle-проектов и композитная сборка

Конфигурация

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

Типы зависимостей

Производительность конфигурации

Как сделать задачу для этапа конфигурации?

Немного о buildSrc

Куда вынести общую логику билдскриптов?

Сборка

Коротко про Gradle Task

Gradle Daemon

Несколько советов по оптимизации скорости сборки

Заключение

Список докладов

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

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

Структура проекта

Итак, главная сущность в мире Gradle это Project. Project-ом выступает само наше приложение, которое мы только что создали. У project-а могут быть subproject-ы, у subproject-а могут быть свои subproject-ы, и таким образом получается древовидная структура. Хорошей практикой является подход, при котором степень вложенности не превышает двух. Такая структура подходит для большинства проектов. При этом subproject-ы можно просто называть Gradle-модулями.

Если вы пользуетесь IDE от JetBrains или Android Studio, по умолчанию они не дадут вам создать иерархию больше двух (для стандартных проектов), что уже наталкивает на мысль, что так делать не стоит.

На картинке снизу subproject-ы (Gradle-модули) - это app и lib. Корнем Gradle-структуры является сам проект (вот эта маленькая точка сверху):

Project узнаёт обо всех своих subproject из файла конфигурации settings.gradle (.kts). Написанный здесь скрипт будет выполняться на этапе инициализации проекта.

Инициализация

Итак, в settings.gradle (.kts) мы определяем содержимое нашего приложения, и учим Gradle к нему подступаться. В самом начале задаем имя нашего проекта:

rootProject.name = "myproject"

Теперь мы можем легко его получить из любого subproject-а на последующих этапах.

Конфигурация плагинов

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

Внутри блока pluginsесть возможность указать дефолтную версию для плагина, если не используется никакая другая. При этом эту версию можно брать извне, например, из gradle.properties:

val helloPluginVersion: String by settingspluginManagement {plugins {id("com.example.hello") version "${helloPluginVersion}"}}

gradle.properties:

helloPluginVersion=1.0.0

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

По умолчанию все наши плагины подключаются из gradlePluginPortal. Если же плагин необходимо достать из другого репозитория, в блоке repositories можно его определить. Например, мы хотим подключить Android Gradle Plugin. Он лежит в гугловском репозитории, что и объявляем явно:

repositories {gradlePluginPortal()google()}

Готово! Теперь можно добавить зависимость Android Gradle Plugin в classpath (о котором чуть позже) и затем успешно подключать Android-плагины в билдскриптах.

В блоке resolutionStrategy мы можем определить правила для подключения плагинов, используемых проекте. На коде ниже приведен пример того, как можно хитрым образом динамически подключить Android Gradle Plugin на тот случай, если в проекте он начнёт использоваться:

resolutionStrategy {  eachPlugin {    if (requested.id.namespace == "com.android") {      useModule("com.android.tools.build:gradle:${requested.version}")    }  }}

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

build.gradle.kts (root):

plugins {  id("com.android.application") version "4.1.0" apply false}

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

Важный момент: версию плагинов в явном виде стоит определять именно в рутовом build.gradle (.kts). Если сделать это как-то по-другому, чаще всего будет появляться следующее:

Caused by: org.gradle.plugin.management.internal.InvalidPluginRequestException: Plugin request for plugin already on the classpath must not include a version

Реже следующее:

Caused by: java.lang.IllegalArgumentException: org.gradle.api.internal.initialization.DefaultClassLoaderScope@68d65269 must be locked before it can be used to compute a classpath!

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

Подключение Gradle-проектов и композитная сборка

Далее с помощью includeобъявляем существующие в нашем проекте подпроекты (они же по-простому gradle-модули). При этом, если модуль лежит где-то в другом месте и вообще он гриб, можно явно указать, как и где его найти с помощью project:

include("some-subproject")project("some-subproject").projectDir = file("../somesubproject")project(":some-subproject ").buildFileName = "some-subproject.gradle"

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

includeBuild("some-other-project") {  dependencySubstitution {    substitute(module("org.sample:mysample")).with(project(":"))   }}

C помощью лямбды в dependencySubstitution можно подменить зависимости, используемые в includeBuild-проекте, в том числе на те, что предоставляет наш проект, как на примере выше.

Где можно использовать композитную сборку?

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

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

P.S. Отладить таким образом можно не только Gradle-плагин, но и все содержимое build.gradle (kts), и в том числе на Groovy!Где ещё может пригодиться композитная сборка, поговорим немного дальше по ходу статьи.

Также settings.gradle (.kts) может с успехом отсутствовать. В этом случае Gradle поймёт, что других модулей проекте нет, и на этом успокоится.

Многие уже привыкли видеть settings.gradle (.kts) как скрипт, где только перечислены все известные в приложении Gradle-проекты. По опыту починки различных поломок с Gradle могу сказать, что сюда посмотрят в последнюю очередь. Если есть возможность не дописывать сложную логику сюда, лучше этого не делать. В большинстве случаев эту логику можно реализовать в build.gradle (.kts) рутового Gradle-проекта, что будет более очевидно для других разработчиков.

После выполнения инициализации Gradle создает объекты типа Project, с которыми мы продолжаем работу уже на этапе конфигурации.

Конфигурация

Также известна под именами Sync Project With Gradle Files, Load Gradle Changes, Reload All Gradle Projects. На данном этапе главными игроками выступают билдскрипты build.gradle (.kts).

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

  1. Резолвятся и загружаются зависимости для каждого из известного в settings.gradle (.kts) Gradle-проекта;

  2. Строится граф выполнения Gradle-задач для этапа сборки;

  3. Определяются переменные и конфигурируются данные для выполнения задач на этапе сборки.

О подкапотном пространстве 2 и 3 этапов предлагаю поговорить в статье про Gradle-задачи и в комментариях, а сейчас давайте немного сосредоточимся на том, как быть с зависимостями.

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

Для подключения зависимостей в Gradle-проект существует два ключевых блока: repositoriesи dependencies.

repositories {  mavenCentral()  maven(url = "https://www.myrepo.io")  flatDir {    dirs("lib1", "lib2")}} dependencies {  implementation(kotlin("stdlib"))}

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

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

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

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

buildscript {  repositories {    //...  }  dependencies {    classpath("com.android.tools.build:gradle:$agpVersion")}}

На примере выше я добавляю зависимость от Android Gradle Plugin чтобы использовать com.android.* плагины для конфигурации Android-приложения.

Для подключения зависимостей на этапе сборки, блоки dependencies и repositoriesдобавляются в корень билдскрипта build.gradle (.kts). В качестве зависимостей могут быть как другие gradle-проекты, так и внешние/локальные библиотеки:

dependencies {  runtimeOnly(group = "org.springframework", name = "spring-core", version = "2.5")  implementation(fileTree(mapOf("include" to listOf(".jar"), "dir" to "libs")))  implementation(kotlin("stdlib"))  implementation(project(:project-a))}

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

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

Could not resolve project :project-a.Required by:    project :project-b

, а в худшем - c NullPointerException, и проблему тогда станет искать намного сложнее.

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

Типы зависимостей

У Gradle бывают два типа зависимостей - runtime и compile-time. Хорошо объясняет положение вещей следующий рисунок:

При подключении зависимостей в compileClasspath, мы получим runtime exception при попытке достучаться до кода зависимости во время выполнения, поскольку зависимость не попала в приложение. Но в то же время код зависимости будет доступен на этапе сборки проекта. Подключая зависимости в runtimeClasspath, мы гарантируем их попадание в приложение, а значит, и безопасность выполнения кода в runtime. Здесь-то и приходит понимание, что implementation и api добавляют зависимости в оба classpath-а. При этом api также позволяет получить доступ к коду gradle-проекта в случае его транзитивного подключения.

В качестве apiElements и runtimeElements на рисунке обозначен код, который мы хотим отдать на использование в другие gradle-модули.

Производительность конфигурации

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

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

subprojects {  apply(plugin = "java")    repositories {    mavenCentral()  }    tasks.register<MyTask>("myTask")}

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

Как сделать задачу для этапа конфигурации?

У Gradle есть на этот случай колбэки. Самый простой способ добавить колбэк для этапа конфигурации определить блоки afterEvaluate или beforeEvaluate. Блок afterEvaluate можно использовать, например, в случае, когда мы хотим добавить задачу в граф выполнения и хотим, чтобы она выполнялась по определенному правилу. Например, после задачи myTask, как на примере ниже:

аfterEvaluate {  tasks.all {    if (this is org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {      dependsOn(tasks.named("myTask"))    }  }}
Почему не следует использовать dependsOn

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

Чтобы избежать подобных проблем, задачи следует связывать с помощью их inputs и outputs. В этом случае в качестве бонуса мы получим еще и инкрементальность (aka up-to-date проверки), что значительно снизит время повторной сборки. Чтобы во всем разобраться, можно посмотреть доклад Степана Гончарова (таймкод) и пример из документации.

Немного о buildSrc

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

Но, к сожалению, не всё так гладко, как хотелось бы. У buildSrc есть одна достаточно весомая проблема - при любом его изменении мы теряем наш билд-кеш, и как следствие, заставляем проект пересобираться "на холодную". Если проект большой, это может быть особенно критично. О том, как решать проблему buildSrc, можно почитать в статье от ребят из Badoo. (Спойлер - решается миграцией на композитный билд).

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

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

Если вы используете Groovy, можно вынести логику в отдельный билдскрипт и подключать его в нужные места вот так:

build.gradle (Gradle-модуля):

 apply from: common.gradle

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

Если вы пишете подключаемые билдскрипты на Kotlin DSL, то они обязательно должны лежать в buildSrc. Связано это с тем, что Kotlin-скрипт должен быть скомпилирован перед использованием. При этом для подключения нужно выполнить небольшой финт ушами и в build.gradle (.kts) модуля buildSrc добавить следующее:

build.gradle.kts (buildSrc):

plugins {`kotlin-dsl``kotlin-dsl-precompiled-script-plugins`}

Теперь можем добавить Kotlin-скрипт в buildSrc/src/main/kotlin (java):

common.gradle.kts:

dependencies {  add("implementation", "org.sample:some-shared-dependency:1.0.0")}

И подключить его вот так:

build.gradle.kts (Gradle-модуля):

apply(id = "common")//...

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

Для того, чтобы связать Kotlin и Groovy, в Kotlin-скрипты можно подключать стандартные *.gradle с помощью того же apply:

build.gradle.kts (Gradle-модуля):

apply(from = "common.gradle")//...

Сборка

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

Коротко про Gradle Task

Gradle Task представляет собой единицу работы, которую выполняет сборка. К примеру, это может быть компиляция классов, создание JAR, создание документации Javadoc или публикация в репозиторий.

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

tasks.register("printAllProjectNames") {  group = project names  description = Prints all projects names  doFirst {    println(Start execution)  }  doLast {    println("Root project name is: ${project.name}") project.subprojects.forEach { project ->      println("Child project name is: ${project.name}")    }  }

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

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

gradle ${your_task_name}

Gradle Daemon

Непосредственным выполнением сборки занимается Gradle Deamon. Он включен по умолчанию для Gradle версии 3.0 и выше. Gradle Daemon является долгоживущим системным процессом, периодически осуществляющим сборку, когда мы этого хотим. Внутри него происходит много in-memory кеша, оптимизации работы с файловой системой и оптимизации кода выполнения сборки. Если коротко - всё идет на пользу. Пожалуй, исключение только одно - он довольно прожорлив, и Gradle любит держать несколько демонов на разные случаи жизни. Если система начинает ощутимо лагать, всегда можно всех за раз прибить командой

gradle --stop

Несколько советов по оптимизации скорости сборки

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

  1. Параллельное выполнение тасок.

    Всё просто - org.gradle.parallel=true в вашем gradle.properties, и Gradle будет стараться максимально распараллелить выполнения тасок на этапе сборки. Этот параметр по умолчанию включен при создании проекта.

  2. Обновление Gradle.

    Gradle важно периодически обновлять. Связано это с тем, что с каждой версией в Gradle привносят улучшения по скорости сборки, исправления багов и новые интересные плюшки. Для удобства обновления, был придуман Gradle Wrapper (или просто Wrapper).Это ни что иное, как обычная Gradle-задача. Теперь для обновления версии можно написать в рутовом build.gradle (.kts) следующее:

    tasks.withType<Wrapper> {  val projectGradleVersion = "6.8.3"  gradleVersion = projectGradleVersion}
    

    , а затем выполнить команду gradle wrapper. Или же выполнить

    gradle wrapper --gradle-version ${gradle_version}
    

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

  3. Правильное использование api/implementation.

    При изменении реализации зависимости Gradle пересобирает "на холодную" все зависящие от неё модули. Я уже упомянул про api и implementation в разговоре о способах подключения зависимостей, и теперь понятно, что при подключении зависимости через api, она также транзитивно попадает в classpath-ы модулей, в которые мы подключили наш модуль. Тем самым увеличивается количество модулей, которые gradle будет пересобирать при изменении зависимости. Если нет необходимости в транзитивном использовании кода из зависимости, для её подключения следует использовать implementation.

  4. Инкрементальность и build-кеш.

    Оптимизация Gradle позволяет нам пропускать выполнение задачи при определенных условиях. У Gradle существует 5 состояний задач - EXECUTED, UP-TO-DATE, FROM-CACHE, SKIPPED и NO-SOURCE. В разговоре про кеш нам интересны два из них - UP-TO-DATE и FROM-CACHE. Они сигнализируют о том, что результаты выполнения наших тасок были успешно подтянуты гредлом из результатов предыдущей сборки. Об остальных состояниях можно почитать в документации.

    UP-TO-DATE. Возникает в случае, если разработчик задачи позаботился о ней и самостоятельно реализовал инкрементальность её выполнения (проверки на up-to-date), или же все зависимости этой задачи, если они есть, были успешно взяты из кеша, или признаны гредлом up-to-date.

    FROM-CACHE. Это состояние возникает в случае, если Gradle смог восстановить outputs задачи из билд-кеша. При этом по умолчанию build-cache выключен. Build-cache довольно удобно использовать на CI, таким образом ускорив выполнение пайплайнов Gradle-сборки. Как организовать build-cache всегда можно узнать тут.

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

Бонус для дочитавших до конца: Gradle-плагины

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

public interface Plugin<T> {  void apply(T target);}

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

Пожалуй, самыми яркими примерами будут являться представители из Android Gradle Plugin: "com.android.application" и "com.android.library". Подключая их в билдскрипты, мы получаем возможность собирать и конфигурировать сборку Android-приложений.

Подключать плагины в наши билдскрипты мы можем с помощью apply:

apply(plugin = "com.android.application")

, или в блоке plugins:

plugins {  `application`}

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

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

Заключение

Gradle действительно мощный инструмент для сборки проектов, хоть и работа с ним не всегда проста. После появления возможности использовать Kotlin для реализации своих Gradle-задумок, магия постепенно начинает уходить и на stackoverflow хочется заходить реже. К тому же Gradle ведут работу над созданием хорошей документации, что, несомненно, очень радует (правда, её космический объём не остановит только настоящих энтузиастов).

И конечно же, Gradle это open-source. Можете с удовольствием скрасить один из вечеров в репозитории Gradle на Github.

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

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

Список докладов

Степан Гончаров - Gradle [A-Z]. Доклад про Gradle под капотом, объясняет способы реализации Gradle-тасок и (о боже) про недостатки Kotlin DSL.

Stefan Oehme - Composite Builds with Gradle. Доклад про суть композитной сборки в Gradle и способах ее применения (на английском).

Филипп Уваров - Gradle Plugin Development. Доклад с AppsConf про разработку Gradle-плагинов. Раскрывает область применения плагинов, способы их реализации и по каждому их преимущества/недостатки.

Подробнее..

Business Intelligence на очень больших данных опыт Yota

16.02.2021 16:13:42 | Автор: admin


Всем привет! Меня зовут Михаил Волошин, и я, как руководитель отдела инструментов бизнес-анализа, хочу верхнеуровнево рассказать о плюсах и особенностях BI-решения Yota.

200 Tb Vertica, 400 Tb Hadoop, кластер Tableau, специфичная организация процесса разработки и многое другое ждут вас под катом.

Внимательный читатель спросит: А причем тут Vertica и слоник Hadoop, технологии же разные? Да ни при чем это лишь КДПВ.

1. DWH: ода Вертике


Vertica. На ее базе построено корпоративное хранилище данных (data warehouse, DWH), являющееся ядром решения. Наша Vertica первая инсталляция в СНГ была развернута в 2012 году (я пришел лишь в 2016). 8 лет назад не было и половины зоопарка продуктов Apache, а выбор происходил между Netezza, Greenplum и, собственно, Vertica. Время показало, что выбор оказался верным: IBM прекратила техническую поддержку Netezza в 2019, Greenplum еще в 2015 стал opensource продуктом (т.к. никто не покупал шардированный Postgress). И к началу 2021 года в мире осталось 2 серьезных аналитических on-premise БД: Vertica и Teradata. Не хочу разводить холивар, но буду рад услышать об иных решениях, позволяющих обычным аналитикам в adhoc запросах оперировать >1 трлн строк за разумное время в минутах и без поддержки команды data engineer + dataops.

Итак, Vertica это колоночная MPP БД. Т.е. данные хранятся в колонках, что ускоряет доступ к ним и позволяет оптимизировать хранение. Запросы выполняются одновременно всеми нодами кластера, что также позитивно сказывается на скорости обработки данных (однако происходит высокая утилизация сети и дисков). При этом входной порог для доступа к терабайтам и петабайтам данных низок за счет ANSI SQL 99 с небольшими расширениями. 1-й Tb этого великолепия бесплатно. Важный момент все колоночные решения не соответствуют ACID, т.е. не могут заменить классических OLTP БД для условного биллинга, но отлично подходят для целей анализа данных. Более подробно об архитектуре Vertica здесь.

У нас 161 Tb на 34 rack нодах HP, каждая из которых имеет:

  • 2*CPU по 20 ядер
  • 256Gb RAM
  • 2*10G сеть
  • быстрые 10k SAS HDD RAID 10 (в 2017/18, когда мы планировали обновление и обновляли RAID массивы, SSD стоили как чугунный мост и были не такими надежными как сейчас)

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

В целом продукт достаточно надежный: за все время, что я работаю в Yota (5-й год пошел), кластер ни разу не падал целиком. Были кейсы, когда 9 нод вываливались в течение 10 минут (диски, контроллеры рейдов, иные технические проблемы), и это приводило к просадкам производительности, но кластер не рассыпался, и после вывода сбоивших нод из кластера на горячую производительность восстанавливалась. Вывод необходим, т.к. кластер всегда работает со скоростью самой медленной ноды (вспоминаем рекомендацию вендора о гомогенности). Теоретически из строя может выйти до половины всех узлов кластера, но может хватить и 2 нод (при k-safety=1, параметр репликации данных со стандартным значением для большинства инсталляций в мире).

Еще одним фактом, касающимся надежности DWH, хотя и не красящим нас, является появление бэкапа: он у нас появился лишь в 2019 перед мажорным обновлением версии Vertica. И это при том, что до 2018 года наша Vertica была самой большой в СНГ (сейчас по объему вторая-третья, но по сложности самого хранилища, по-прежнему, первая).

Обновлялись мы, кстати, сразу на 2 версии (7 -> 8, 8 -> 9). Ну, как обновлялись: в 13:00 остановили кластер и запустили .py скрипт от вендора, а в 21:10 мы уже открывали пиво, после того как кластер начал подниматься. Никаких эксцессов не было. И тут вспомнилась статья на Хабре от коллег из телекома про обновление кластера Greenplum c 4-ой до 5-ой версии. Так они, насколько помню, потратили сотни дней разработчиков на costylmaking из-за несовместимости типов данных между мажорными версиями одного продукта.

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

Anchor modeling, Datavault 2.0 всего этого у нас нет. Мы не фокусировались на жестком соблюдении какой-то одной изначально выбранной методологии, иначе сами себе устроили бы приключения. Почему? Хотя бы потому, что при разворачивании DWH, Yota была независимой компанией и крупнейшим оператором 4G, но предоставлявшим доступ в сеть только для модемных устройств. После покупки МегаФоном в Yota появились голосовые абоненты, а голос принципиально иной продукт, и мы бы просто не запустились в крайне сжатые сроки, если бы не определенная архитектурная свобода. У нас 37 схем, и архитектура внутри каждой не то, что схемы, но даже витрины, может отличаться от мейнстрима и выбирается в соответствии с решаемой задачей с учетом особенностей хранения в источниках.

И еще момент во внутренней команде нет ни архитектора, ни девопс-гуру. Они просто не нужны fulltime, т.к. Vertica не требует постоянного обслуживания. Эти роли у нас выполняются подрядчиком, а внутренняя команда сфокусирована на создании инструментов анализа бизнес-данных для всей компании и совместном с бизнесом улучшении продуктов. Как бы высокопарно это ни звучало, но Yota изначально data driven business. У нас под сотню персональных учеток для adhoc-запросов и широкого доступа к данным всем, кому он нужен.

В завершение разговора о Vertica хочется обсудить регулярно поднимающийся вопрос: Дорого же! Зачем оно надо?. По моему скромному мнению, в бизнесе нет понятий дорого/дешево, но есть понятие эффективно/не эффективно. Давным-давно я работал в складской логистике, так вот, строительство склада начинается с изучения характеристик будущих единиц хранения (SKU) и потоков движения этих SKU. При проектировании хранилища ситуация должна быть аналогичной: изучение данных, подразумеваемых для обработки внутри DWH, выбор наиболее оптимальной архитектуры с параллельными расчетами финансовой модели. Звучит просто, но это позволит избежать догматов: Делаем только на opensource или Наш потрясающий стартап может себе позволить Teradata в топ-комплектации. Пару месяцев назад создал модель Vertica total cost of ownership, и эффективность текущего решения Yota вышла оптимальной. Поделиться, к сожалению, по понятным причинам не смогу.

Hadoop. Их у нас целых 2 кластера (Cloudera 6.3), которые мы используем как дешевое хранилище некритичных для бизнеса данных. К данным, хранящимся в наших Hadoop, не требуется скорость доcтупа, предъявляемая к Вертике. Здесь стоит отметить подставу со стороны Cloudera: когда мы наши Хадупы планировали и разворачивали в 2018-2019, то существовавшая Comminity Edition нас вполне устраивала; однако в феврале 2020 пришла полярная лисичка в виде изменения политики лицензирования и, по сути, отмены т.н. free версий. Из-за этого вынуждены думать сейчас о редеплое кластера из 23 нод на CH 5.16 с потерей данных (ими можно пожертвовать). А на маленький кластер Hadoop вынуждены оформлять ненужную нам лицензию.

Oracle. Легаси-вишенкой на торте DWH выступает хранилище Oracle объемом всего 1.4 Tb. Его мы иногда используем для собственной обработки в ODS слое высокочастотных потоков малонасыщенных данных. Например, 100 000 файлов в сутки по несколько строк в каждом, конечно, можно писать в Вертику напрямую, но разумнее сначала в транзакционную БД, а уже затем часовыми батчами в DWH. Движемся дальше.

2. ETL


В нашем случае зачастую ELT, так как наше DWH позволяет перемалывать терабайты внутри себя без реализации стадии Transform на относительно слабых ETL-серверах.

Высоконагруженные потоки данных. У нас 9 пайплайнов по 2-8 ETL-джобов в каждом. Они редко меняются, и поскольку границы не выходят за staging слой, то мы отдали их нашим подрядчикам. Тем же, которые поддерживают Vertica. Коллеги написали свой Loader на Groovy 3, который сами и поддерживают. Loader вполне неплохо перемалывает свой 1 Tb в сутки, поступающий в Vertica, и до 10 Tb в большой Hadoop.

Из интересного стоит упомянуть используемый нами механизм CDC от Oracle Oracle Golden Gate. Kafka пока не используем, но, возможно, начнем, т.к. переезд на Oracle 19 имеет специфичную реализацию Oracle for BigData вместо старого доброго OGG. На текущий момент мы еще в процессе исследований, но как бы не пришлось свои костыли писать

Остальные потоки данных. Здесь кроется соль нашего решения формирование промежуточных и конечных витрин как на основе данных из п. 2.1, так и на собственных интеграциях примерно с 150 системами-источниками. Этим занимается исключительно внутренняя команда. Здесь примерно 1150 ETL-джобов. В основе стэка разработки: Talend Data Integration 7.1. Инструмент условно бесплатный. Условно, т.к. требует лицензии для использования среды выполнения и оркестрации. Я уже не застал того благостного времени, когда использовалась Talend Administration Console, но старшие товарищи рассказывали, что это был тот еще садомазочуланчик папаши Мюллера образцовый UI, привносящий незабываемый UX. Можно, конечно, деплоить джобы Talend в виде .zip пакетов сразу в .sh и оркестрировать в cron, а потом грепать логи. Но было решено еще в 2016 году, что деплоить джобы Talend будем сразу в Scheduler (рантайм с web UI для доступа к нему). Который, как уже понятно, написал под нас тот же самый подрядчик. Разумеется, и лицензия стоит дешевле чем TAC, UI оставляет более позитивный UX, и доработки под наши пожелания не затягиваются во времени.

Пара слов про Talend Data Integration. Это среда визуального программирования потоков интеграции. Сам инструмент не уступает Informatica PowerCenter по производительности. JVM под капотом у обоих. Максимум, что придется писать руками SQL для стадии Transform внутри некоторых компонентов, но его и нет смысла пытаться чем-то заменить. Чтобы не было сомнений в возможностях Talend и иных интеграционных комбайнов, 2 факта:

  • до появления Loader сотни Гб бинарников CDR парсились джобами Talend. Loader и появился из доработки джобов Talend, которые перестали справляться с нагрузкой;
  • внутренняя команда иногда переписывает за подрядчиком пайплайны, созданные в их Loader, и время на обработку данных уменьшается. Понятно, что ситуация разовая, и 1 Tb в сутки из бинарников вряд ли Talend распарсит, но факт есть факт.

3. Визуализация данных


Используем следующие инструменты: MS Analysis Services, Tableau, есть у нас и любимое легаси в виде SAP BO.

MS Analysis Services. Исторически аналитические кубы были значимым инструментом. В проде у нас всего 16 кубов весом от 6 Mb до 144 Gb, а через пару месяцев после доработок и до 200 Gb. В 2020 году возникла идея о возможном переносе кубов в Tableau, но там уже при экстракте в 5 Gb дэшборд стал люто тормозить. В нашем случае платформа оказалась безальтернативной. Кстати, используем последний free version MS AS 11. Не PowerBI, конечно, но нулевые траты на лицензии нас вполне устраивают.

Tableau. На конец 2020 у нас было 277 дэшбордов, и бизнесу они адски заходят. Одна из целей 2021 максимальная автоматизация ручной отчетности аналитиков. И тут мы споткнулись, т.к. наши аналитики, как и любые нормальные аналитики, для прототипирования используют Excel. Без шуток.

Есть у этих самых аналитиков любовь к типам диаграмм 'водопад':

Прошу прощения за низкое качество изображения, но суть передана верно

Очень круто выглядит и нравится топ-менеджменту. Как бывший аналитик данных, сам кайфую, когда вижу такую красоту. Но чтобы реализовать такой водопад в Tableau, нужно сделать 5 графиков, обеспечить синхронизацию фильтров между ними Ок, пару накликать можно. А если в дэшборде их 171? Ну, вы поняли. На одной стороне весов 12 человеко-часов аналитиков на ежемесячный сбор презентации. На другой полгода разработки сеньором + 100% гарантия превращения дэшборда в недвижимость. Недавно был тяжелый разговор с аналитиками, где мы зафиксировали, что такой красоты может быть не больше 2-3 графиков на весь дэшборд. Но продолжаем искать пути автоматизации именно этого типа визуализации в юзкейсах наших аналитиков адская идея скриптами powershell повторить ручные действия в Excel (там их пилят при помощи платной надстройки ThinkCell) пока не отпала. Офтопом стоит отметить сам факт повторения многостраничных презентаций в Tableau, где на самом деле однотипные данные намертво распечатаны в .pdf во всех возможных измерениях имеющихся в дэшборде. Конечно же, подход спорный, но мы очень клиентоориентированы по отношению к внутренним заказчикам, и мысли об изменении в сторону сторителлинга аккуратно и потихоньку продвигаем в жизнь.

Sap BO. Очевидная legacy система визуализации устаревшая чуть более, чем полностью. Аккуратно уходим от нее в сторону более современных и гибких решений, т.к. она прекрасна для point-to-point повторения отчетов (именно тут необходимо собирать большие и однотипные презентации аналитиков, но трудозатраты будут еще выше, да и такие водопады вообще не факт, что реализуемы в SAP BO), но не позволяет создавать интерактивные дэшборды. Следует отметить, что сам подход реализации point-to-point больших презентаций актуален для большого российского бизнеса, например, из сферы добычи сырья. В 2к21 это, на мой взгляд, выглядит морально устаревшим, особенно для Yota, средних размеров data driven business. Поэтому нам не имеет смысла заниматься реализацией намертво прибитых по брендбуку отчетов на миллион вкладок/страниц.

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

4. Data science (machine learning)


Кроме классического BI в отделе есть команда DS и, надеюсь, в этом году здесь появится ссылка на статью о Data Science в Yota, написанную профессионалом. Я таковым не являюсь, т.к. вырос из разработчиков классического BI. Извините, если кто-то зашел сюда только ради этого :-)

5. Agile? Нет У нас своё


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

В направлении классического BI 6 инженеров и тимлид. При этом нет ни выделенных архитекторов, ни аналитиков, ни тестировщиков, ни релиз-менеджеров. Каждый инженер = BI-фулстэк, реализует задачу под ключ, напрямую общаясь с бизнес-заказчиком и лично ответственен за конечный результат. Кодеров по ТЗ/токсичных рок-звезд нет и не будет от слова совсем. Но у всей команды изначально хорошие софт-скилы вдобавок к хард. В теории взаимозаменяемы, но жизнь вносит свои коррективы, и кто-то оказывается более сильным в ETL, а кому-то интереснее визуализация в Tableau пожелания в развитии каждого учитываются и мной, и тимлидом.

Работа по заявке идет с упором на 2 показателя: time-to-market (TTM) и customer satisfaction index (CSI). Причем сразу на проде, если речь об ETL-задачах в DWH. Тестовая зона, конечно же, есть, но подготовка данных на наших объемах занимает сильно больше времени, чем сама разработка. Важный момент: сообщения в чате наподобие ой, я оттранкейтил справочник... встречаются не чаще 1-2 раз в год и исправляются за 5-10 минут. Потерь невосстановимых, критичных для компании данных я не помню. В этом плане интереснее обращения от коллег из систем-источников на 100% реплицируемых в DWH с просьбой выслать из нашего бэкапа какую-нибудь таблицу фактов, которую массово проапдейтили, но что-то пошло не так За последний год такое было 2 раза.

Вы спросите, почему все так необычно устроено?

Кроме самого исчерпывающего объяснения

Так повелось в этом нашем лесу (с)

Есть очевидные минусы, с которыми мы умеем жить:

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

и плюсы:

  • Высокий TTM и высокая пропускная способность команды в целом. Весь проектный портфель компании (почти во всех проектах есть фичи на отдел) составляет 15-20% общего объема разработки отдела. Остальное прямые пожелания конечных бизнес-заказчиков, реализуемые с минимумом бюрократии.
  • Стабильно высокий CSI, демонстрирующий правильность выбранного подхода в организации разработки. Один раз в квартал мы проводим опрос среди бизнес-заказчиков. В 4Q20 из 43 респондентов ответили 21. По итогу получили 4,89 из 5. Это упавший CSI, хотя я предполагал падение до 4,5. Стандартно у нас ближе к 5. Объясняется это гибкостью в подходе к реализациям задумок бизнес-заказчиков и скоростью появления конечного результата с максимально эффективным использованием имеющихся инструментов/технологий.

В опросе CSI также можно оставить комментарий, например такой


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

Пользуясь случаем хочу поблагодарить #BI_TEAM за стабильно высокие результаты: ребята вы крутые, мне повезло работать со всеми вами! Спасибо.

6. Заключение


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

По идее здесь должны быть вакансии отдела, но извините full house) И даже есть небольшой лист ожидания Однако в соседних, не менее интересных, командах еще требуются люди. Буду рад комментариям нам есть куда расти.
Подробнее..

Расчет рекомендованных предложений для клиентов Yota что под капотом?

28.05.2021 04:14:05 | Автор: admin

Привет, хабровчане!


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


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


Контекст решения


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


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

В сборе и анализе данных участвуют IT-домены, которые ближе всего находятся к сетевому оборудованию:


  • Домен Биллинга, а именно рейтер и биллинговая система, в которую рейтер регистрирует данные о звонке, включая его длительность
  • Домен Управления сетевым оборудованием и качеством передачи данных, а именно свитчи и роутеры, через которые проходит клиентский трафик, DPI системы анализа пакетов данных и применения политик, определяемых PCRF системой, которая обеспечивает контроль использования трафика, включая накопленный объем
  • Домен Аналитики данных, а именно системы сбора/регистрации данных из операционных систем, хранилище данных, а также системы, обеспечивающие поток обработки поступивших данных и подготовку продукта данных (data product) для его дальнейшего использования при генерации рекомендованного предложения

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


  • Домен Управления продуктами, а именно продуктовый каталог, системы, определяющие доступность предложений и инстанцирование продуктов в случае его принятия
  • Домен Вычисления контекста состояния клиента, а именно движок бизнес-правил и набор хэндлеров, позволяющих вычислить контекст состояния клиента и объектов, с ним связанных, таких как баланс, продукты, срок жизни и т.п.
  • Домен Сервисов информирования, а именно системы, обеспечивающие сборку сообщений и их отправку в нужный канал
  • Домены-витрины/каналы, такие, как Мобильное приложение, CRM и другие

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


Получение и анализ статистики потребления


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


image

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


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


В случае контроля интернет-трафика, с точки зрения его сбора и анализа, все оказалось несколько сложнее. Здесь есть четкая привязка к оборудованию и его возможностям, а именно поддержке протокола IPFIX. IPFIX расшифровывается как IP Flow Information Export, то есть экспорт информации IP-потока. IPFIX позволяет сетевым инженерам и администраторам собирать информацию о трафике с коммутаторов, маршрутизаторов и любых других сетевых устройств, поддерживающих протокол, и анализировать отправляемую информацию, обрабатывая ее с помощью системы анализа трафика.
Именно система анализа трафика должна поддерживать данный протокол, полученная информация по которому может быть использована при расчете предложения, включающего соответствующие безлимитные приложения для оптимизации затрат клиента на трафик. В связи с тем, что нам потребовалось обновить программное обеспечение систем анализа трафика в разных регионах, усовершенствованная версия продукта Максимум на первый месяц с возможностью рекомендаций безлимитных приложений была запущена уже по факту апгрейда этих систем.


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


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


Генерация рекомендованного предложения


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


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


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


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


image

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


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


Продолжим тему генерации рекомендованного предложения. Диспетчер, получая событие, сигнализирующее о необходимости расчета предложения, отправляет запрос на движок бизнес-правил, получает ответ о выполнении набора правил и формирует рекомендованный пресет. Движок в нашем случае не только информирует об успешности выполнения правил (true/false), но и сообщает вычисленные значения ресурсов для формирования пресета, используя правила-формулы и подготовленный продукт данных доменом Аналитики данных в качестве базисных значений для расчета.
По факту формирования рекомендованного пресета диспетчер отправляет событие, получаемое доменом Систем информирования. Основным компонентом данного домена является процессор динамической сборки сообщений. Процессор собирает сообщение для информирования и отправляет его по каналам взаимодействия с клиентом, таким как пуш-сообщение в Мобильном приложении и SMS.


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


Заключение


Резюмируем основные положения статьи:


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

Категории

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

  • Имя: Макс
    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