Применение Low-Code В Аналитических Платформах

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

Создание аналитических платформ — сложная и трудоемкая задача.

Однако любую задачу можно упростить.

В этой статье я хочу поделиться своим опытом использования инструментов low-code для создания аналитических решений.

Этот опыт был приобретен в ходе реализации ряда проектов по направлению Big Data Solutions компании «Неофлекс».

С 2005 года направление Big Data Solutions компании «Неофлекс» занимается вопросами построения хранилищ и озер данных, решением задач оптимизации скорости обработки информации и разработкой методологии управления качеством данных.



Применение low-code в аналитических платформах

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

Возможно, даже если мы говорим о малом бизнесе.

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

.

В первом приближении проблему можно решить «на коленке».

Но по мере роста бизнеса приход на аналитическую площадку все равно неизбежен.

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

Чтобы упростить науку о ракетостроении, вы можете съесть слона по частям.



Применение low-code в аналитических платформах

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

Практически все наши клиенты пришли к этому постулату, перестроив ландшафт на основе инженерных практик DevOps-команд. Но даже при «раздельном, слоновьем» питании у нас есть хорошие шансы на «перенасыщение» ИТ-ландшафта.

В этот момент стоит остановиться, выдохнуть и посмотреть в сторону.

инженерная платформа с низким кодом .

Многих разработчиков пугает перспектива тупика в карьере при переходе от непосредственно написания кода к «перетаскиванию» стрелок в UI-интерфейсах low-code систем.

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

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

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

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

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

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

Проведем аналогию с языками программирования низкого и высокого уровня.

Переход от низкоуровневых языков к высокоуровневым — это переход от написания «прямых директив на языке аппаратуры» к «директивам на языке людей».

То есть добавление некоторого уровня абстракции.

В данном случае переход на low-code платформы с языков программирования высокого уровня — это переход от «директив на языке людей» к «директивам на языке бизнеса».

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

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

Поэтому low-code — это всего лишь видимость другого уровня абстракции.



Прикладной опыт использования low-code

Тема low-code достаточно широкая, но сейчас мне бы хотелось поговорить о практическом применении «концепций low-code» на примере одного из наших проектов.

Подразделение Big Data Solutions компании «Неофлекс» специализируется больше на финансовом секторе бизнеса, построении хранилищ и озер данных и автоматизации различной отчетности.

В этой нише использование low-code уже давно стало стандартом.

Среди других low-code инструментов можно отметить инструменты для организации ETL-процессов: Informatica Power Center, IBM Datastage, Pentaho Data Integration. Или Oracle Apex, выступающий средой быстрой разработки интерфейсов доступа и редактирования данных.

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

Используя low-code платформы, вы также можете организовать оркестровку потоков данных, создать платформы для анализа данных или, например, модули для проверки качества данных.

Одним из прикладных примеров опыта использования инструментов low-code разработки является сотрудничество компаний «Неофлекс» и Mediascope, одного из лидеров российского рынка медиаисследований.

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



Применение low-code в аналитических платформах

Медиаисследования — технологически нагруженная сфера бизнеса.

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

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

Самым простым решением масштабирования уже функционирующей аналитической платформы Mediascope могло бы стать увеличение IT-персонала.

Но гораздо более эффективное решение — ускорить процесс разработки.

Одним из шагов в этом направлении может стать использование low-code платформ.

На момент запуска проекта у компании уже было функционирующее продуктовое решение.

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

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

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

HDFS стала стандартом хранения данных с использованием паркетных файлов.

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

Загрузка данных в хранилище реализована с помощью Kafka и Apache NiFi. Инструмент Лоу-кода в этой концепции использовался для оптимизации самой трудоемкой задачи построения аналитической платформы — задачи расчета данных.



Применение low-code в аналитических платформах

В качестве основного механизма сопоставления данных был выбран малокодовый инструмент Datagram. Неофлекс Дейтаграмма — это инструмент для разработки преобразований и потоков данных.

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

Код Scala генерируется автоматически с использованием подхода Model Driven Architecture. Очевидным преимуществом такого подхода является ускорение процесса разработки.

Однако помимо скорости есть и следующие преимущества:

  • Просмотр содержимого и структуры источников/приемников;
  • Отслеживание происхождения объектов потока данных до отдельных полей (lineage);
  • Частичное выполнение преобразований с просмотром промежуточных результатов;
  • Проверка исходного кода и корректировка его перед выполнением;
  • Автоматическая проверка преобразований;
  • Автоматическая загрузка данных 1 в 1.
Барьер для входа в low-code решения для генерации преобразований довольно низок: разработчику необходимо знать SQL и иметь опыт работы с инструментами ETL. Стоит отметить, что генераторы преобразований на основе кода не являются ETL-инструментами в широком смысле этого слова.

Инструменты Low-code могут не иметь собственной среды выполнения кода.

То есть сгенерированный код будет выполняться в той среде, которая существовала на кластере еще до установки low-code решения.

И это, пожалуй, еще один плюс к low-code карме.

Так как параллельно с low-code командой может работать «классическая» команда, реализующая функционал, например, в чистом Scala-коде.

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

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

А по своей сути это разные вещи.

Low-code позволяет разработчику больше вмешиваться в сгенерированный код. В случае с Datagram можно просматривать и редактировать сгенерированный код Scala; no-code может не предоставлять такой возможности.

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



Архитектура решения

Попробуем разобраться, как именно low-code инструмент помогает решить задачу оптимизации скорости разработки функционала расчета данных.

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

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



Применение low-code в аналитических платформах

Источники данных в нашем случае весьма неоднородны и разнообразны:

  • Пипл-метры (ТВ-метры) — это программно-аппаратные устройства, которые считывают поведение пользователей у респондентов телевизионной панели — кто, когда и какой телеканал смотрел в домохозяйстве, участвующем в исследовании.

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

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

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

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

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

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

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

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

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

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

Структура каталогов в HDFS будет создана автоматически и будет соответствовать структуре хранения данных в исходной системе.

Однако в контексте данного проекта мы решили не использовать эту возможность low-code платформы в связи с тем, что компания Mediascope уже самостоятельно начала работу над созданием аналогичного сервиса с использованием комбинации Nifi + Kafka. Стоит сразу указать, что эти инструменты не взаимозаменяемы, а скорее дополняют друг друга.

Нифи и Кафка способны работать как в прямом (Нифи -> Кафка), так и в обратном (Кафка -> Нифи) соединении.

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



Применение low-code в аналитических платформах

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

Инструмент Nifi и использование комбинации Nifi + Kafka также можно назвать low-code подходом к разработке, который имеет низкий барьер входа в технологии Big Data и ускоряет процесс разработки приложений.

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

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

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

На этом этапе генерируются ключи для всех сущностей.

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

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

Платформой для расчета данных был Spark. Описанный функционал по приведению данных к единой семантике также был реализован на основе маппингов из low-code инструмента Datagram. Целевая архитектура требовала доступа к данным SQL для бизнес-пользователей.

Для этого варианта использовался Hive. Объекты регистрируются в Hive автоматически, когда вы включаете опцию «Регистрировать таблицу Hive» в инструменте low-code.

Применение low-code в аналитических платформах



Расчет управления потоком

Datagram имеет интерфейс для создания проектов рабочих процессов.

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

Имеется поддержка сценариев оболочки и программ Java. Также можно использовать сервер Apache Livy. Apache Livy используется для запуска приложений непосредственно из среды разработки.

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

Например, у нас был довольно успешный опыт встраивания маппингов в Scala в оркестраторы, написанные на PLSQL и Kotlin. REST API инструмента low-code включает в себя такие операции, как создание исполняемого года на основе схемы сопоставления, вызов сопоставления, вызов последовательности сопоставлений и, конечно же, передачу параметров в URL-адрес для запуска сопоставлений.

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

Запуск и контроль выполнения процессов (в том числе диаграммы Ганта) только добавляет баллы в карму Airflow. Формат файла конфигурации для запуска сопоставлений решений с низким кодом стал искровой отправкой.

Это произошло по двум причинам.

Во-первых, spark-submit позволяет запускать jar-файл напрямую с консоли.

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

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

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

Поэтому взаимодействие между задачами осуществляется с помощью управляющих операторов, таких как DummyOperator или BranchPythonOperator. В совокупности использование решения Datagram low-code в сочетании с универсализацией конфигурационных файлов (формирующих Dag) привело к значительному ускорению и упрощению процесса разработки потоков загрузки данных.



Витринные расчеты

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

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

Также есть возможность настройки на местную сеть вещания (местные новости и реклама).

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

Сразу же значения просмотра «взвешиваются» на основе информации об их значимости (расчет поправочного коэффициента).



Применение low-code в аналитических платформах

Отдельный этап подготовки витрин — проверка данных.

Алгоритм проверки предполагает использование ряда математических моделей.

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

Каждое из отображений выполняет узкую задачу.

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

Было принято решение разбить алгоритм проверки на следующие подэтапы:

  • Построение регрессий зависимостей просмотра ТВ-сетей в регионе с просмотром всех сетей региона за 60 дней.

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

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

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

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

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

И, если это действительно «инженер», а не «кодер», то страх профессиональной деградации при использовании low-code инструментов он должен наконец отступить.



Что еще может сделать low-code?

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

Использование low-code при разработке даталейков уже стало для нас стандартом.

Наверное, можно сказать, что решения на базе стека Hadoop идут по пути развития классических СХД на базе СУБД.

Инструменты Low-code в стеке Hadoop позволяют решать как задачи обработки данных, так и задачу построения окончательных BI-интерфейсов.

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

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



Применение low-code в аналитических платформах

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

Для этого инструмент low-code реализует интерфейс с Apache Atlas и Cloudera Navigator. По сути, разработчику необходимо зарегистрировать набор объектов в словарях Atlas и ссылаться на зарегистрированные объекты при построении сопоставлений.

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

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

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



Применение low-code в аналитических платформах



Качество данных и низкий уровень кода

Еще одной задачей, реализованной с помощью инструмента low-code в проекте Mediascope, была задача класса «Качество данных».

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

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

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

Эта функциональность реализована на основе автоматически создаваемых сопоставлений семейства качества данных в Datagram. Генерация кода в этом случае также основана на метаданных модели.

На проекте Mediascope интерфейс осуществлялся с метаданными продукта Enterprise Architect. При объединении инструмента low-code с Enterprise Architect автоматически были сгенерированы следующие проверки:

  • Проверка наличия значений «null» в полях с модификатором «not null»;
  • Проверка наличия дубликатов первичного ключа;
  • Проверка внешнего ключа сущности;
  • Проверка уникальности строки по набору полей.

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

Применение low-code в аналитических платформах

Конечно, автоматическое формирование чеков должно происходить постепенно.

В рамках описываемого проекта этому предшествовали следующие шаги:

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

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

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

  • Все проверки метаданных генерируются автоматически при изменении модели в EA;
  • Проверки доступности данных (определение наличия каких-либо данных в определенный момент времени) могут генерироваться на основе каталога, хранящего ожидаемое время появления следующего фрагмента данных в контексте объектов;
  • Проверки проверки бизнес-данных создаются аналитиками в блокнотах Zeppelin. Оттуда они отправляются непосредственно в таблицы настройки модуля DQ в производственной среде.

При прямой отправке сценариев в производство нет никаких рисков.

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

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



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

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

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

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

Поэтому в этом случае вы можете рассчитывать на лучшее и быстрое решение.

Конечно, low-code — не панацея, и волшебства не произойдет само по себе:

  • Low-code индустрия переживает стадию «усиления», а единых промышленных стандартов пока нет;
  • Многие low-code решения не бесплатны, и их покупка должна быть осознанным шагом, который следует совершать с полной уверенностью в финансовой выгоде от их использования;
  • Многие решения low-code не всегда хорошо работают с GIT/SVN. Либо их неудобно использовать, если сгенерированный код скрыт;
  • При расширении архитектуры может возникнуть необходимость доработки low-code решения — что, в свою очередь, провоцирует эффект «привязанности и зависимости» от поставщика low-code решения.

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

    Low-code платформы следует выбирать не только по принципу поиска выгоды от их использования.

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



Применение low-code в аналитических платформах

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

Более того, переход к нему неизбежен – как неизбежна любая эволюция.

Если один разработчик на low-code платформе делает свою работу быстрее, чем два разработчика без low-code, то это дает компании фору по всем параметрам.

Порог входа в low-code решения ниже, чем в «традиционные» технологии, и это положительно влияет на проблему нехватки кадров.

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

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

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

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

Теги: #Хранилища данных #Большие данные #Hadoop #bigdata #Инжиниринг данных #dwh #low-code #платформа данных

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.