Как за 40 часов распознать всех поросят с помощью компьютерного зрения. Решение задачи на AgroCode Hack

2021 год был очень насыщенный на хакатоны и ИТ-чемпионаты. Мы неоднократно писали о том,  что специализируемся на проектах по компьютерному зрению. В этом наша сила. На AgroCode Hack нам предстояло за 40 часов решить кейс с использованием компьютерного зрения и AI по сегментации и отслеживанию поросят. Рассказываем, как в очередной раз заняли призовое место на хакатоне и отследили всех хрюш. 

Привет, меня зовут Вова! И я Data Scientist в Napoleon IT. Недавно ребята из моего отдела писали статью про участие в хакатоне. Через неделю мы уже приняли участие в двух хакатонах и провели выходные в офисе тремя командами. В этот раз расскажу про участие в AgroCode Hack от Россельхозбанка. Наша команда LateDev состояла из 3 человек: я в роли Data Scientist, Ваня в роли Frontend Developer и Артур в роли Machine Learning Engineer. Таким составом мы участвовали и раньше, и даже пару раз заняли первые места на Цифровом прорыве. 

Подготовка к хакатону

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

Постановка задач и ресурсы

Далее был технический созвон, на котором подробно рассказали о задаче и объяснили в каком виде эксперты ждут решение. Была возможность задать кейсосодержателю интересующие вопросы и уточнить некоторые моменты решения. Организаторы выделили всем участникам сервер с GPU nvidia tesla t4 и дали доступы. Суть задачи была в построении системы отслеживания и мониторинга активности животных в специальных “станках”. Датасет был не размечен и по факту это были просто нарезанные видео с установленной над “станком” камеры наблюдения. Животные на этих видео могли двигаться хаотично или наоборот не проявлять активности, находиться очень близко друг к другу. Всех их нужно было сегментировать.Также иногда в зону наблюдения заходил работник и его необходимо было не сегментировать как животное. Как делать сегментацию и трекинг было понятно, а вот для задачи оценки активности животных нет общепринятого решения и его нужно было придумать самим.

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

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

Исходные данные

Обучающая выборка неразмеченных видеороликов, полученная системой машинного зрения в условиях промышленного свинокомплекса. На видеороликах сняты животные в условиях производственного станка. Число животных в станке варьируется. Съёмка производится стационарной камерой. Для обучения предоставляется 10 минутных роликов разрешением 1700×1700 пикселей и частотой следования кадров 10 fps Изображения цветные, палитра RGB. 

Техническое решение

Мы начали с задачи сегментации животных. Решили отказаться от mmdetection из-за непростой установки библиотеки и обучать Mask RCNN Inception ResNet V2 из tensorflow object detection, т.к. понимали что для запуска такой модели в дальнейшем нужно будет установить только tensorflow без каких-либо дополнительных зависимостей. Как мы уже упоминали на представленных видео не было разметки, а мы слишком ленивы, чтобы размечать самим. Но нашли выход — репозиторий, в котором решается похожая задача. Правда там оказалось всего 24 изображения в train и 6 в test. Мы сначала не поверили, что именно на этих данных обучалась модель, но решили попробовать тренировать свою, и она действительно заработала на наших данных. Но мы столкнулись с одним артефактом — сотрудники фермы, которые иногда заходили в станок, тоже распознавались как свинки!

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

Красным цветом выделена слепая зона
Красным цветом выделена слепая зона

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

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

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

Подобрали несколько порогов и выделили несколько классов активности:

  • серый: нулевая активность ( не двигается)

  • зеленый: низкий уровень активности

  • желтый: средний уровень

  • красный: высокий уровень

В итоге мы заняли 2 место 🙂

Презентация работы  можете найти по ссылке

А код решения посмотреть здесь  


ссылка на оригинал статьи https://habr.com/ru/post/653497/

TypeScript тип any против всех

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

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

// из lib.es5.d.ts interface JSON {     parse(text: string, reviver?: (this: any, key: string, value: any) => any): any;     stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;     stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string; }

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

Использование слияния интерфейсов и перегрузки методов
interface JSON {     parse(         text: string,         reviver?: (this: unknown, key: string, value: unknown) => unknown,     ): unknown; }

Песочница

Слияние деклараций интерфейсов

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

В простейшем случае описания просто добавляются. Следующий пример показывает счастливый TypeScript.

interface User {     name: string; }  interface User {     memberSince: number; }  const user: User = {     memberSince: 2022,     name: 'author' }

Песочница

В первом варианте описания интерфейс User содержит одно поле `name`, во втором варианте тоже одно поле, но с другим именем. TypeScript объединил оба описания в одно. Все ожидаемо.

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

interface User {     name: string;     memberSince: number; }  interface User {     memberSince: number; }  const user: User = {     memberSince: 2022,     name: 'author' }

Песочница

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

interface User {     name: string;     memberSince: string;// пока еще все хорошо }  interface User {     memberSince: number;//ошибка }  const user: User = {     memberSince: 2022, // ошибка     name: 'author' }

Песочница

Как работает перегрузка функций в TypeScript

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

function getYear():number; function getYear(ticks: number): number; function getYear(iso:string):number; //скрытая от вызывающей стороны реализация function getYear(arg?: undefined| string|number):number{     if(typeof arg === 'undefined'){         return 2022;     }     return new Date(arg).getFullYear(); }

Песочница

Перегрузка методов интерфейса.

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

interface User{     login(token:string):void;     login(name: string, password: string):void;     login():void; }  declare const user:User;  //вариант 1 user.login("--secret--"); //вариант 2 user.login("admin","pa$5w||d"); //вариант 3 user.login();

Песочница

Мы обратим дополнительное внимание на то, что имена методов повторяются. Более того, при слиянии интерфейсов у TypeScript нет требования уникальности имени метода.

Этим мы и воспользуемся для решения вопроса с улучшенной типизацией метода parse интерфейса JSON

Слияние с библиотечным интерфейсом

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

interface JSON {     parse(         text: string,         reviver?: (this: unknown, key: string, value: unknown) => unknown,     ): unknown; } const x = JSON.parse("0", function ():unknown {     console.log(this);// TypeScript подсказывает, что this: unknown     return 42; });  console.log(x) // TypeScript подсказывает, что x:unknown

Теперь мы можем не опасаться что TypeScript перестанет нам помогать в борьбе за качественное ПО.


ссылка на оригинал статьи https://habr.com/ru/post/653779/

RabbitMQ Streams для сбора и обработки телеметрии умного дома

Традиционно для сценариев поточной обработки с использованием Map-Reduce рассматриваются такие решения как Hadoop/Spark, либо используются конвейерные системы (например Kafka), для которых есть возможность реализовать концепцию потоков (streams) с помощью дополнительных инструментов (в случае с Kafka это Kafka Connect (для подключения к источникам и получателям потока) и Kafka Streams для реализации Map-Reduce на потоке сообщений.

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

Обычно RabbitMQ используются в качестве медиатора при создании распределенной системы, основанной на обмене сообщениями, в том числе для сервисно-ориентированной архитектуры (SOA), в основе которой лежит сервисная шина предприятия (Enterprise Service Bus). Кроме того, брокер часто используется как промежуточное хранилище для дальнейшего распределения заданий между исполнителями, связанными с одной или несколькими очередями (это особенно важно в ситуациях, когда время для выполнения задания превышает среднее время между запросами). Брокер сообщений также предоставляет механизмы контроля отправки (уведомления об ошибках, поддержка передачи последовательности сообщений в рамках транзакции, получение квитанций о завершении обработки сообщений или ошибке), а также обеспечивает возможность создания дополнительных очередей для пересылки результата в ответ на запрос, что активно используется в реализации модели Remote Procedure Call (RPC), например в Python Celery. Сообщения в системе не сохраняются и после обработки безвозвратно уничтожаются.

Модель Stream для очереди в RabbitMQ 3.9 позволяет создать иную модель хранения данных, которая напоминает Kafka. В этом сценарии очередь реализуется как «журнал только для добавления данных», который сохраняет предыдущие сообщения и позволяет выполнить агрегацию данных за длительный период, а также «перемотать» положение на более раннюю позицию. При этом для доступа к сообщениям может использоваться как AMQP-совместимые клиенты, так и специальный двоичный протокол и клиентские библиотеки (Go и Java). В любом случае сохраняются все достоинства RabbitMQ при работе в режиме высокой доступности (очереди реплицируются между брокерами в HA-кластере и сохраняются в Mnesia, поэтому могут быть восстановлены при перезагрузке брокеров). Также для отправки сообщений в поток и чтения из потока можно использовать любые поддерживаемые протоколы RabbitMQ (AMQP, STOMP, MQTT), при этом в RabbitMQ поддерживаются внутренние механизмы маршрутизации между Exchange и Queue, что позволяет гибко интегрировать потоковые очереди в существующую архитектуру распределенного приложения.

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

rabbitmq-plugins enable rabbitmq_stream

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

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

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

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

Для начала установим RabbitMQ (будем использовать официальный docker-контейнер) и добавим поддержку MQTT и Streams.

docker run -it --name rabbitmq -p 5672:5672 -p 1883:1883 -p 5552:5552 rabbitmq:3-management     rabbitmq-plugins enable rabbitmq_mqtt rabbitmq-plugins enable rabbitmq_stream rabbitmq-plugins enable rabbitmq_stream_management

Для отправки данных телеметрии создадим пользователя и назначим ему права на vhost

rabbitmqctl add_user mqtt-test mqtt-test rabbitmqctl set_permissions -p / mqtt-test ".*" ".*" ".*" rabbitmqctl set_user_tags mqtt-test management

По умолчанию отправка будет происходить в стандартный exchange amq.topic, для пересылки в потоковую очередь необходимо настроить binding между amq.topic и соответствующей очередью. Теперь создадим потоковую очередь:

 rabbitmqadmin declare queue name=measurements queue_type=stream

Для потоковой очереди можно задавать дополнительные аргументы (x-max-length-bytes — количество байт в потоке, x-max-age — максимальное время хранения сообщений, указывается с единицей измерения, например 30D), x-stream-max-segment-size-bytes указывает максимальный размер файла-сегмента для хранения сообщений.

rabbitmqadmin declare binding source=amq.topic destination=measurements routing_key=temperature.#

Для управления высокой надежностью можно управлять репликацией и просматривать состояние потока через rabbitmq-streams:

  • rabbitmq-streams stream_status measurements — просмотр состояния потока (показывает смещение последнего добавленного сообщения)

  • rabbitmq-streams add_replica measurements node2 — добавить реплику потока на узел node2

  • rabbitmq-streams delete_replica measuments node2 — отключить реплику от узла

При использовании клиентского подключения через AMQP при подключении можно указывать (в аргументе stream-offset) с какой позиции будет происходить чтение сообщений (число со смещением от начала потока) или с момента времени (время в ISO или в виде интервала от текущего момента времени), кроме того можно начать с первого доступного сообщения (first), со следующего поступившего сообщения (next). В нашем примере мы будем использовать драйвер на Go, разработанный для использования очередей в режиме потока.

Для отправки данных в реальных условиях используется датчик DHT11 и NodeMCU (прошивка), но для тестирования мы будем отправлять данные вручную и для этого удобно использовать свободно распространяемый MQTT Explorer.

Подключение к RabbitMQ - MQTT
Подключение к RabbitMQ — MQTT
Отправка сообщения с замером температуры
Отправка сообщения с замером температуры

Теперь сделаем приложение для получения средней температуры за последний час. Для подключения будем использовать клиент на Go. Создадим новый проект и добавим зависимость:

go get -u github.com/rabbitmq/rabbitmq-stream-go-client@v1.0.0-rc9

При необходимости получать только сообщения, полученные с последнего запуска можно использовать stream.OffsetSpecification{}.LastConsumed(). Альтернативно можно забрать сообщения с начала (с учетом политики удаления) stream.OffsetSpecification{}.First(), получить последнее (и все новые) сообщения stream.OffsetSpecification{}.Last(), либо указать время для поиска первого сообщения в UNIX timestamp в миллисекундах stream.OffsetSpecification{}.Timestamp().

Получим все сообщения со смещения на 1 час назад от текущего времени:

package main  import ( "encoding/json" "github.com/rabbitmq/rabbitmq-stream-go-client/pkg/amqp" "github.com/rabbitmq/rabbitmq-stream-go-client/pkg/stream" "log" "time" )  type TemperatureData struct { Temperature float32 `json:"temperature"` Timestamp   int64   `json:"timestamp"` }  func main() {   start := time.Now()   start = start.Add(-1 * time.Hour)//start timestamp    //connect to RabbitMQ stream   consumer, err := env.NewConsumer( streamName, func(consumerContext stream.ConsumerContext, message *amqp.Message) { var pk TemperatureData err := json.Unmarshal(message.GetData(), &pk) if err != nil { panic(err.Error())//JSON decoding error } println(pk.Temperature) }, stream.NewConsumerOptions(). SetConsumerName(streamName). SetOffset(stream.OffsetSpecification{}.Timestamp(start.UnixMilli())). SetCRCCheck(false)) if err != nil { log.Panicln(err.Error()) } defer close(consumer.NotifyClose()) }

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

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

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

package main  import ( "encoding/json" "fmt" "github.com/rabbitmq/rabbitmq-stream-go-client/pkg/amqp" "github.com/rabbitmq/rabbitmq-stream-go-client/pkg/stream" "log" "time" )  type TemperatureData struct { Temperature float32 `json:"temperature"` Timestamp   int64   `json:"timestamp"` }  type MeasurementCallback = func([]TemperatureData)  func extractMeasurements(start time.Time, end time.Time, streamName string, callback MeasurementCallback) { env, _ := stream.NewEnvironment( stream.NewEnvironmentOptions(). SetHost("localhost"). SetPort(5552). SetUser("measurements"). SetPassword("measurements")) var last *amqp.Message  var consumerLast *stream.Consumer var consumerEnd *stream.Consumer  var lastMessage *TemperatureData var endMessage *TemperatureData  measurements := make([]TemperatureData, 0, 0)  consumerLast, _ = env.NewConsumer(streamName, func(consumerContextLast stream.ConsumerContext, message *amqp.Message) { last = message err := json.Unmarshal(last.GetData(), &lastMessage) if err != nil { panic(err.Error()) } }, stream.NewConsumerOptions().SetConsumerName(streamName).SetOffset(stream.OffsetSpecification{}.Last()).SetCRCCheck(false)) defer close(consumerLast.NotifyClose())  consumerEnd, _ = env.NewConsumer(streamName, func(consumerContextEnd stream.ConsumerContext, message *amqp.Message) { err := json.Unmarshal(message.GetData(), &endMessage) if err != nil { panic(err.Error()) } }, stream.NewConsumerOptions().SetConsumerName(streamName).SetOffset(stream.OffsetSpecification{}.Timestamp(end.UnixMilli())).SetCRCCheck(false)) defer close(consumerEnd.NotifyClose())  //sync for first stop-message in next slot (endMessage) and last message in stream (lastMessage) time.Sleep(500 * time.Millisecond)  //connect to stream consumer, err := env.NewConsumer( streamName, func(consumerContext stream.ConsumerContext, message *amqp.Message) { var pk TemperatureData err := json.Unmarshal(message.GetData(), &pk) if err != nil { panic(err.Error()) }       //message from next slot? if endMessage != nil && pk.Timestamp == endMessage.Timestamp { consumerContext.Consumer.Close() consumerLast.Close() consumerEnd.Close() callback(measurements) } measurements = append(measurements, pk)       //last message in stream? if lastMessage != nil && pk.Timestamp == lastMessage.Timestamp { consumerContext.Consumer.Close() consumerLast.Close() consumerEnd.Close() callback(measurements) } }, stream.NewConsumerOptions(). SetConsumerName(streamName). SetOffset(stream.OffsetSpecification{}.Timestamp(start.UnixMilli())). SetCRCCheck(false)) if err != nil { log.Panicln(err.Error()) } defer close(consumer.NotifyClose()) }  func main() { start := time.Now() start = start.Add(-1 * time.Hour) end := time.Now() finished := make(chan bool) extractMeasurements(start, end, "measurements", func(data []TemperatureData) { var avg float32 = 0.0 for _, temp := range data { fmt.Printf("Timestamp=%s, Temperature=%f\n", time.Unix(temp.Timestamp, 0), temp.Temperature) avg += temp.Temperature } avg /= float32(len(data)) fmt.Printf("Average temperature is %f\n", avg) finished <- true }) <-finished }  func close(channelClose stream.ChannelClose) { <-channelClose } 

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

rabbitmqctl set_policy --apply-to queues oneweek 'measurements' "{'max-age':'7D'}"

Мы рассмотрели лишь один из возможных сценариев использования режима streams для очередей RabbitMQ. Аналогично можно реализовать другие задачи поточной обработки, где требуется агрегация по историческим данным или возможность ретроспективного анализа (например, при аудите событий безопасности). Конечно же, для многих задач более подходящим решением может быть какая-либо из баз данных для временных рядов (OpenTSDB, Prometheus, InfluxDB), но полезно помнить, что подобный сценарий использования стал возможен и для RabbitMQ в варианте использования поточных очередей.

Исходные тексты проекта размещены на https://github.com/dzolotov/rabbitmq-streams-example

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


ссылка на оригинал статьи https://habr.com/ru/company/otus/blog/653689/

Функциональная модель торгового предприятия в нотации IDEF0

Проблематика

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

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

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

Почему функции, а не процессы?

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

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

Как  читать модель

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

Что делать, если  за несколько функций отвечает один человек

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

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

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

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

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

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

Можно ли сделать программное обеспечение на основе этой модели?

Да, можно. Я уже создавал ERP-систему для одной из организаций, которая построена по этому принципу. То есть я сначала описывал модель в IDEF0, а потом уже – — процессы в BPMN и, соответственно, автоматизировал, т.е. разработал программное обеспечение.

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

Как я давал названия

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

Модель

Диаграмм A-0

Диграмма A0

Привлечь покупателя

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

Продать товар

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

Закупить товар

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

Сохранить товар

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

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

Доставить товар

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


ссылка на оригинал статьи https://habr.com/ru/post/653785/

NFT, NFT, NFT

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


Криптоархеологи проводят самые настоящие раскопки блокчейнов в попытке обнаружить токены, которые могли бы считаться первыми NFT. Из-за разногласий по поводу формулировки требований к NFT имеют право на существование разные мнения, но превалирует версия, что смарт-контракт Terra Nullius, появившийся 7 августа 2015 г. был первым в своём роде.

Ссылки: [Анонс на reddit] [Код контракта]

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

image

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

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

image

Игра Blockplots (второе название Etheria 1.1) была запущена 29 октября 2015 г. Пользователи покупали участки на карте, которые потом можно было перепродавать другим участникам. В блокчейне каждый кусочек виртуальной землицы был представлен как отдельный токен. Именно наличие функции смены владельца является причиной, по которой этот вид токенов борется за право называться первыми NFT в истории.

image

На тот момент идея продавать кусочки виртуальной собственности уже давно была неновой. В 2005 году некий находчивый студент придумал веб-сайт Million Dollar Homepage для креативного сбора средств на оплату учёбы. Идея сайта заключалась в продаже места на пустой картинке размером 1000×1000 пикселей. Покупатели размещали на выкупленной площади изображение и ссылку на свой ресурс. Один пиксель стоил один доллар, через полгода после запуска сайта молодой человек собрал свой миллион.

image

Именно этот сайт стал вдохновением для разработчика по имени William Entriken (@fulldecent), айтишная активность которого настолько бурная, что его эксперименты даже засветились в журнале Хакер.

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

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

image

В игре CryptoKitties токены представляют котиков. Игроки обменивают NFT (как бы котиков) на криптовалюту Ethereum. Игровой процесс включает размножение и торговлю, пользователи стремятся заполучить самые редкие породы, чтобы заработать на их продаже. Все процессы в игре выполняются с помощью смарт-контрактов. Не только транзакции, но и данные о котятах находятся в блокчейне. Есть два способа заполучить котёнка. Первый — это победить на аукционе. Аукционы позволяют получить котёнка навсегда или в аренду. Другой вариант — это размножение. Чтобы «создать» нового котёнка необходимо иметь доступ к двум родительским особям. Рост системы опирался на желание игроков заполучить самых дорогих котят и выгодно их продать. Подробный анализ справедливости игры на англ. языке

image

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

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

Личные таланты и работоспособность Уильяма привели его к роли ведущего автора стандарта ERC-841, который позже был переименован в ERC-721. Получившийся стандарт был позитивно принят сообществом, работа над альтернативными вариантами была остановлена, и в течение нескольких лет не было предложено никакой замены. 6 июня 2018 г. работа над ERC-721 была официально завершена.

Посмотреть подробное перечисление заметных проектов в мире NFT можно там.

image

▍ Начало настоящего хайпа

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

image

Список стран, из которых приходило больше всего запросов, выглядит очень странно. В первых строчках нет ни США, ни других стран, население которых объективно обладают средствами для рискованных инвестиций. Зато мы видим Китай, откровенно небогатые страны и страны, известные финансовыми «услугами». Причины такого распределения должны нам рассказать много нового о том, как используется NFT. А пока обратим внимание на пик, возникший в феврале 2021 г. Что же тогда случилось?

image

Источник: DappRadar

К тому времени рынок «продажи» цифрового искусства посредством токенов уже появился, но отношение к нему было на уровне очередной высокотехнологичной забавы. Шум возник вокруг видеоролика CrossRoad за авторством компьютерного художника с ником Beeple, дело происходило на криптобазаре «Nifty Gateway (NG)«, где эта работа была впервые продана за 66_666 $ пользователю Pablo (@pablorfraile). Сам NFT содержал ссылку на короткий анимационный ролик, который символически связан с выборами в США в 2020 г. Pablo затем выставлял на продажу этот лот несколько раз, значительно увеличивая цену, в феврале 2021 некто anonymous10 приобрёл его за 6_600_000 $ и передал пользователю Delphina Leucas (@babybeluga). Продажи цифровых фантиков за десятки и тысячи долларов на фоне криптобума никого до этого момента не шокировали, но мир не смог не обратить внимания на то, что какая-то непонятная нелепица стала объектом многомиллионных сделок. Это запустило снежный ком невероятных продаж, и процесс начал сам себя подогревать.

image

Будет ли рынок двигаться дальше или три миллиарда это потолок? Пока неизвестно, прошло слишком мало времени, чтобы судить. Являются ли 200_000 кошельков, совершавших операции, уникальными пользователями? Нет, один пользователь может использовать несколько кошельков по самым разным причинам. Почему распределение по сумме сделок не является нормальным? Скорее всего, провал в распределении связан с существованием как минимум двух разных целей совершения сделок. Небольшие суммы — это то, что соответствует декларируемому назначению NFT: игровые покупки, коллекционирование, пожертвования и баловство. Крупные сделки являются клубком из разных причин, которые сводятся к двум базовым: погоня за прибылью и ЧСВ (чувство собственной важности).

▍ Анализ регионального интереса

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

image

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

▍ Анализ китайского крипторынка

Что нам могут рассказать Google Trends? Вот список тем, интересовавших пользователей, которые искали информацию про NFT:

Тема Пояснения
Искусство Имеются в виду продажи цифрового искусства посредством NFT
Binance Самая известная криптовалютная биржа
OpenSea Один из самых популярных NFT-базаров
Банковские переводы
Токены
Торговые площадки Имеются в виду NFT-базары
Кошелёк Подразумевается личный счёт для операций в блокчейне
Discord Мессенджер, в котором происходит максимум общения по разным темам, касающихся NFT
Аватар Подвид NFT-картинок для аватарок
Взаимозаменяемость
Цифровое творчество
Обезьяна Имеется в виду известный набор NFT „Bored Ape Yacht Club“

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

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

  1. Китай занимается регулированием биткоина больше 10 лет.
  2. Запрет легальных обменников криптовалюты привёл к росту использования неофициальных децентрализованных бирж.
  3. В 2013 банкам было запрещено прикасаться к биткоину, но человечки тут же насочиняли массу схем с промежуточным обменом живых денег на что-то, что позволяло продолжать покупать и продавать криптовалюту.
  4. Недавно майнинг был убит совсем, а вместе с ним любые операции с криптовалютой объявлены незаконными, что имеет последствия в отличие от простых запретов.
  5. Все биржи, которые, изворачиваясь, продолжали работать, свернулись окончательно.
  6. Раздавив то, до чего было легко дотянуться, власти устроили подводный пожар, заставив мигрировать схему «децентрализованная основа + старая инфраструктура» в сторону бурного развития децентрализации.
  7. Взорвался ранее маргинальный рынок DeFi (децентрализованные финансы), который за пару ближайших лет предложит аналоги всех финансовых схем видимого мира и создаст новые инструменты. При этом у DeFi не может быть регуляторов. Это будет похоже на наивный финансовый мир конца XIX века, умноженный в миллионы раз.
  8. С точки зрения официальных регуляторов, DeFi — это анонимные программисты, создающие всё новые блокчейн-сети для анонимных пользователей. Как говорится, нельзя запретить песнь соловья, нельзя запретить пользователю запускать программу на его собственном компьютере, нельзя запретить отправлять и получать данные (даже для одного приложения это выльется в бесконечную гонку в роли догоняющего, воевать против экспоненциального роста — только выключать физическую сеть). Самих блокчейн-сетей пока ещё несколько десятков, но все они раскиданы по тысячам компьютеров в мире, никакое правительство в одиночку не способно остановить этот процесс.
  9. Люди, что создают такие проекты, сами выбирают степень взаимодействия с реальным миром. По щелчку пальцев они вольны поменять страну проживания и целевой рынок. Подчинение локальным законам для них — это мера осознанного выбора.
  10. Всё это звучит слишком анархично, технологические реализации пока больше напоминают ранний интернет: пионеры с барабанами под руководством финансистов удачи, но при наблюдающемся давлении со стороны регуляторов на беспорядочные денежные массы, это явление ждёт сумасшедший рост и оформление во что-то гигантское.
  11. Можно относительно понятно запретить явные криптовалюты. В то же время перестрелять всё семейство DeFi крайне затруднительно, во-первых, без 100 грамм невозможно понять, что несёт риски криптовалют, а что безобидно, а, во-вторых, Китай сам заинтересован в легальных криптофинансах и давно поддерживает крупные эксперименты с управляемыми блокчейнами.
  12. В результате сложилась странная ситуация, что можно плодить блокчейны без токенов. При этом в запретах под словом «токен» имеется в виду значение «криптовалюта». Хотя технически токеном является что угодно, привязанное к пользователю блокчейна. NFT, похоже, не вызывают вопросов у китайских регуляторов, но компании, работающие с NFT, стараются не использовать это название, вместо этого общепринятым стал термин Digital Collection.
  13. Китай официально объявил о запуске в конце января 2022 г. одобренной государством сети Blockchain Services Network (BSN) для размещения правильных NFT. Инфраструктура зовётся BSN-Distributed Digital Certificate (BSN-DDC). Считается, что барьером для незаконной деятельности будет обязательное подтверждение личности пользователей.
  14. На легальных NFT-базарах запрещена перепродажа новых приобретений в течение полугода.

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

▍ Кто, кто в теремочке живёт?

Кипр, Гибралтар, Латвия, Филиппины, Косово, Армения, Афганистан, Босния и Герцеговина, Нигерия, Венесуэла. Почему эти страны объединяет повышенный интерес к NFT? По поисковым запросам из этих регионов ничего интересного обнаружить не удалось, кроме термина nft airdrop. Это словосочетание везде находится в первой десятке, за ним кроется бесплатная раздача NFT с целью накопления аудитории вокруг дальнейшей продажи картинок.

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

image

«95%» — Бо́льшая часть населения Земли пока никак не участвует в этом балагане.

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

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

«Инвесторы» — широкая группа людей, которая включает не только профессиональных спекулянтов, главное что объединяет этих людей — это фрагментарное понимание происходящего на уровне восхищённых статеек. Здесь же находятся «коллекционеры», «меценаты», инстаграмные выпендрёжники, криптоцыгане и гаджетоманы.

«Криптонавты» — крепкие айтишники, которые имеют средства, знания и интерес к покорению цифровых вселенных.

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

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

«Акулы» — кукловоды, которые получают ожидаемую выгоду по сложным схемам, и чаще всего дело не в само́й торговле.

«Криптодиваны» — фанатики криптосвободы, для которых ценность процесса на порядки превышает заинтересованность в материальной выгоде.

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

▍ Криптоигры

Значительную часть экономики NFT составляют игры (сhain games, nft games), они привлекают возможностью постоянного заработка как будто без заметных вложений. Флагманом этого сегмента является игра Axie Infinity. Появившись в 2018 году, она быстро превратилась в самую популярную за счёт переизобретения старых механик на базе блокчейна. Игроки собирают виртуальных героев, которые называются Акси. Каждый Акси уникален и (сюрприз!) привязан к своему NFT, сама игра заключается в дуэлях монстриков, победитель получает немного внутреннего криптобабла, которое используется для расширения зоопарка и покупки криптоземли. Игра притягивает толпы игроков только экономической составляющей, играть там не во что. Все монстрики разделяются по «уникальности», а значит, по силе спроса на них. Зафиксирована покупка Аксика за 368_000 $, так что какие шутки. Криптобабло называется Smooth Love Potion (SLP), его тоже можно продавать и покупать на биржах.

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

image

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

Сочетание комплекса факторов приводят в такие проекты множество игроков из бедных слоёв населения по всему миру. Анализ, проведённый компанией Navik, показал, что по состоянию на август 2021 года опытные игроки зарабатывали выше среднего уровня для Филиппин (41,49 $/день), а большинство игроков зарабатывало чуть больше минимума (7,03 $/день). Такое стало возможно благодаря наличию официального способа сдачи в аренду ценных питомцев, что позволяет людям без значительных вложений участвовать в битвах с другими сильными персонажами и, соответственно, получать заметные выигрыши, из которых владельцу питомцев выплачивается вознаграждение. Самостоятельное вхождение в игру возможно при наличии трёх персонажей, которых надо купить, что может обойтись в сумму, превышающую 1000$, поэтому вариант с арендой является выходом для игроков без бюджета.

Поработившая игровой мир концепция free-to-play, начинает агрессивно отодвигаться концепцией play-to-earn. Этот термин обозначает категорию игр, в которых блокчейн используется для поощрения игроков цифровыми объектами, имеющими ценность внутри криптовселенной, в случае успеха игры эта ценность начинает выражаться в реальных деньгах. На сегодняшний день существуют десятки игр с огромной аудиторией: Gods Unchained, Alien Worlds, Splinterlands и Uplands. В самом Axie Infinity количество активных игроков превышает два миллиона. Пока в одних странах геймеры задаются вопросом «Запустить модный Axie или бесполезный Fortnite?», в других странах вопрос звучит иначе: «Заработать деньги в Axie или на заводе?».

Sky Mavis (разработчик Axie Infinity) недавно запустили автоматическую биржу Katana, где монеты Axie Infinity можно обменять на криптовалюту Эфир, что соединило напрямую игру и бурно растущий рынок DeFi, а сама Katana быстро попала в число самых востребованных сервисов. Axie Infinity притягивает воспроизведением экономической модели реального мира и размытой границей между миром воображаемых и настоящих денег. В игре есть валюта, активы и рынок рабочей силы, которые тесно переплетены. Игроки, у которых нет времени, но есть деньги, передают в аренду свои цифровые активы игрокам, у которых полно времени, но нет денег.

Концепция play-to-earn является воплощением другой концепции «инвестирование для развлечения», то есть вложение денег ради получения удовольствия от азарта и удовлетворения любопытства. Игроки становятся винтиками живой модели капитализма, пусть и в сильно урезанном формате: наёмный труд, инвестирование, потери и приобретения, которые имеют выражение в реальных деньгах. Людям нравится прямая зависимость между усилиями, смекалкой и результатом, то что остаётся лозунгом капитализма, но эволюционно давно исчезло. Подобные игры выводят тиражируемую в некоторых кругах фразу «каждый должен быть инвестором» на новый уровень. Буквально каждый! Ребёнок, заключённый, военнослужащий, вне зависимости от местоположения и дохода, каждый может хотя бы почувствовать себя инвестором, а может даже заработать. Геймификация инвестирования в самом органичном воплощении. Больше нет нужды работать в офисе, больше нет нужды выживать на доллар в день, NFT игры — это комфортное воплощение надежды на хорошую жизнь в условиях общемировой тряски. Если у вас что-то зачесалось, то следует чётко понимать, что это не раздача халявы, без вложения средств вам придётся долго искать незанятое приглашение на наёмничество, но гораздо хуже, что доходы напрямую связаны с притоками новых игроков и уже длительное время они падают (см. SLP Price Chart).

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

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

▍ Какую инвестиционную ценность имеет NFT?

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

Развитие технологий в очередной раз заставляют нас пересматривать устоявшиеся парадигмы. Но является ли NFT новой технологией? Тесные границы искусства в начале XX века были взорваны водородной бомбой под названием „Чёрный квадрат“, это постулирование идеи разрыва между реальным миром и миром, который можно создать воображением. «Чёрный квадрат» был манифестом, кричащим, что описание реального мира — это лишь симпатичная конструкция посреди бесконечного поля комбинирования элементов информации, символ не обязан иметь форму своего значения, ссылка равноценна содержанию.

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

В интернете процветает эпоха «инфлюенсеров», привлечь внимание = привлечь деньги. Если к торговле несуществующими предметами добавить блокчейн, то получается новый рок-н-ролл. NFT отлично укладывается в современную культуру, точнее, не сам NFT, а то чем он стал вместе со своей медиаобёрткой. Именно вся эта праздничная мишура и конфетти, абсурдность и бессмысленность, сопровождающаяся лавинообразным ростом внимания, это всё созвучно с культурой хайпа. В медиапространстве покупка дорогущего автомобиля и NFT выглядит одинаково, причём доказать наличие NFT проще, тем более инстаграм создаёт ощущение, что ролс-ройс сейчас есть у каждого дурачка. NFT не может столько стоить? Фабричная майка тоже не могла стоить 3000 $, пока не нашёлся первый покупатель. Роскошь напоказ потеряла связь с золотом вслед за долларом. Дорогая вещь может отличаться от дешёвой только биркой, в случае NFT даже вещь уже не нужна. За миллион долларов можно купить IZVESTNOST, которую при удачном стечении обстоятельств получится натурально перепродать.

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

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

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

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


ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/653665/