← Назад к вопросам

Какие паттерны используешь для аналитики?

1.0 Junior🔥 161 комментариев
#Опыт и софт-скиллы#Паттерны проектирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паттерны для интеграции и управления аналитикой в Unity

В моей практике для работы с аналитикой в Unity проектах я применяю сочетание архитектурных паттернов, паттернов проектирования (Design Patterns) и специфических подходов (Approaches), адаптированных под нужды мобильных и игровых приложений. Основная цель — создать систему, которая является масштабируемой, отделенной от игровой логики, легко тестируемой и поддерживающей множество аналитических сервисов.

1. Основные архитектурные паттерны и подходы

Сервисный слой (Service Layer) / Фасад (Facade)

Я создаю отдельный слой для аналитики, который абстрагирует сложность работы с различными SDK (Firebase, Unity Analytics, GameAnalytics, AppMetrica и др.) от основной игровой логики.

// Пример интерфейса фасада аналитики
public interface IAnalyticsService
{
    void SendEvent(string eventName, Dictionary<string, object> parameters = null);
    void SendTransaction(string productId, decimal price, string currency);
    void SetUserProperty(string propertyName, string value);
}

Ключевые преимущества:

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

Паттерн "Событие (Event)" или "Сигнал (Signal)"

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

// Пример системы событий (можно реализовать через встроенные Unity Events, делегаты или специализированные системы)
public class AnalyticsEvents
{
    public static event Action<string, Dictionary<string, object>> OnGameEventOccurred;
}

// В игровой логике только вызываем событие
AnalyticsEvents.OnGameEventOccurred?.Invoke("level_started", new Dictionary<string, object> { { "level_number", 5 } });

// Сервис аналитики подписывается на это событие и отправляет данные
public class FirebaseAnalyticsService : IAnalyticsService
{
    public void Initialize()
    {
        AnalyticsEvents.OnGameEventOccurred += SendEvent;
    }

    private void SendEvent(string eventName, Dictionary<string, object> parameters)
    {
        // Конвертация параметров и вызов Firebase SDK...
    }
}

2. Паттерны проектирования для структуры данных

Паттерн "Строитель (Builder)" для параметров события

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

public class AnalyticsEventBuilder
{
    private string _eventName;
    private Dictionary<string, object> _parameters = new();

    public AnalyticsEventBuilder(string eventName)
    {
        _eventName = eventName;
    }

    public AnalyticsEventBuilder WithParameter(string key, object value)
    {
        _parameters[key] = value;
        return this;
    }

    public void Send()
    {
        AnalyticsEvents.OnGameEventOccurred?.Invoke(_eventName, _parameters);
    }
}

// Использование в коде: чисто и понятно
new AnalyticsEventBuilder("purchase_completed")
    .WithParameter("item_id", "sword_001")
    .WithParameter("price", 4.99)
    .WithParameter("currency", "USD")
    .Send();

Паттерн "Спецификация (Specification)" или "Фильтр"

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

public interface IAnalyticsSpecification
{
    bool IsSatisfied(string eventName, Dictionary<string, object> parameters);
}

public class UserConsentSpecification : IAnalyticsSpecification
{
    public bool IsSatisfied(string eventName, Dictionary<string, object> parameters)
    {
        return PlayerPrefs.GetInt("AnalyticsConsent", 1) == 1;
    }
}

// Сервис аналитики проверяет спецификации перед отправкой
if (_specifications.All(s => s.IsSatisfied(eventName, parameters)))
{
    // Отправляем событие
}

3. Операционные паттерны для надежности

Паттерн "Команда (Command)" с очередью (Queue)

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

public class AnalyticsCommand
{
    public string EventName;
    public Dictionary<string, object> Parameters;
    public DateTime CreationTime;
}

public class PersistentAnalyticsService : IAnalyticsService
{
    private Queue<AnalyticsCommand> _pendingCommands = new();
    
    public void SendEvent(string eventName, Dictionary<string, object> parameters)
    {
        var command = new AnalyticsCommand { EventName = eventName, Parameters = parameters };
        _pendingCommands.Enqueue(command);
        TrySendPendingCommands();
    }

    private void TrySendPendingCommands()
    {
        // Попытка отправки всех команд из очереди, неудачные остаются для повторной попытки
    }
}

Паттерн "Стратегия (Strategy)" для конфигурации

Разные платформы (iOS, Android, WebGL) или режимы (Development, Production) могут требовать разных конфигураций или даже разных сервисов аналитики.

public interface IAnalyticsStrategy
{
    IAnalyticsService GetService();
}

public class ProductionStrategy : IAnalyticsStrategy
{
    public IAnalyticsService GetService() => new FirebaseAnalyticsService();
}

public class DevelopmentStrategy : IAnalyticsStrategy
{
    public IAnalyticsService GetService() => new LoggingAnalyticsService(); // Пишет только в лог
}

Ключевые принципы, которых я придерживаюсь:

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

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