Создание системы A/B-тестирования в Go: практическое руководство по разумному экспериментированию

Итак, вы хотите запустить A/B-тесты в Go. Хорошая новость: это не ракетостроение. Плохая новость: это также не так просто, как перевернуть выключатель. Но вот в чём дело — как только вы настроите систему, у вас появятся сверхспособности проверять свои идеи реальными данными, а не интуицией. И вот тогда всё становится интересно.

В этой статье мы построим полную систему A/B-тестирования с нуля. Мы охватим всё: от настройки базового приложения Go до развёртывания готовых к производству экспериментов, которые действительно дадут вам полезную информацию. Без воды, без жестов рукой, только солидная инженерная работа.

Почему A/B-тестирование важно (и почему Go идеально подходит для этого)

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

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

Обзор архитектуры: как всё работает вместе

Прежде чем написать хоть одну строку кода, давайте визуализируем, как работает система A/B-тестирования:

graph TD A[Запрос пользователя] -->|distinctId| B[Служба флагов функций] B -->|Fetch Flag| C[Контроль или вариант?] C -->|Decision| D[Предоставление опыта] D -->|Событие с информацией о флаге| E[Аналитический бэкенд] E -->|Aggregate Results| F[Анализ и результаты] F -->|Победитель?| G[Развёртывание или продолжение тестирования]

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

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

Перед началом убедитесь, что у вас есть:

  • Go 1.19 или новее (честно говоря, 1.20+ лучше)
  • Редактор кода (VSCode, GoLand, Vim — что угодно, что вас устраивает)
  • Базовое понимание HTTP и REST API
  • Аккаунт PostHog (бесплатный уровень подойдёт для начала)
  • 30 минут и приличный кофе

Шаг 1: Создание базового приложения Go

Давайте начнём с простейшего возможного приложения Go, которое обслуживает веб-страницу. Это наша отправная точка.

Сначала создайте новую директорию и инициализируйте модуль Go:

mkdir go-ab-tests
cd go-ab-tests
go mod init go-ab-tests

Теперь создайте файл main.go с базовым HTTP-сервером:

package main
import (
	"fmt"
	"net/http"
)
func main() {
	http.HandleFunc("/", handleHome)
	fmt.Println("Сервер запускается на http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}
func handleHome(w http.ResponseWriter, r *http.Request) {
	html := `
	<!DOCTYPE html>
	<html>
	<head>
		<title>Демонстрация A/B-тестирования</title>
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.container { max-width: 600px; margin: 0 auto; }
		</style>
	</head>
	<body>
		<div class="container">
			<h1>Добро пожаловать в A/B-тестирование</h1>
			<p id="variant-text">Загрузка вашего опыта...</p>
		</div>
	</body>
	</html>
	`
	w.Header().Set("Content-Type", "text/html")
	fmt.Fprint(w, html)
}

Запустите его с помощью go run main.go и посетите http://localhost:8080. Вы должны увидеть базовую страницу. Поздравляем — вы уже на 10% пути.

Шаг 2: Интеграция PostHog: мозг вашего A/B-тестирования

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

Сначала установите PostHog SDK:

go get github.com/posthog/posthog-go

Теперь обновите main.go, чтобы инициализировать PostHog:

package main
import (
	"fmt"
	"log"
	"net/http"
	"os"
	"github.com/posthog/posthog-go"
)
var client posthog.Client
func init() {
	var err error
	client, err = posthog.NewWithConfig(
		"<ВАШ_API_КЛЮЧ_POSTHOG>",
		posthog.Config{
			Endpoint: "https://app.posthog.com", // или ваш URL для самостоятельного хостинга
		},
	)
	if err != nil {
		log.Fatal("Не удалось инициализировать PostHog:", err)
	}
}
func main() {
	defer client.Close()
	http.HandleFunc("/", handleHome)
	fmt.Println("Сервер запускается на http://localhost:8080")
	http.ListenAndServe(":8080", nil)
}
func handleHome(w http.ResponseWriter, r *http.Request) {
	// Захват события просмотра страницы
	client.Enqueue(posthog.Capture{
		DistinctId: "placeholder-user-id",
		Event:      "$pageview",
		Properties: posthog.NewProperties(),
	})
	html := `
	<!DOCTYPE html>
	<html>
	<head>
		<title>Демонстрация A/B-тестирования</title>
		<style>
			body { font-family: Arial, sans-serif; margin: 40px; }
			.container { max-width: 600px; margin: 0 auto; }
			.variant-box { 
				border: 2px solid #007bff; 
				padding: 20px; 
				border-radius: 8px; 
				margin-top: 20px;
			}
		</style>
	</head>
	<body>
		<div class="container">
			<h1>Добро пожаловать в A/B-тестирование</h1>
			<div class="variant-box">
				<p id="variant-text">Загрузка вашего опыта...</p>
			</div>
		</div>
	</body>
	</html>
	`
	w.Header().Set("Content-Type", "text/html")
	fmt.Fprint(w, html)
}

Важно: получите свой API-ключ PostHog из настроек проекта и создайте личный API-ключ. Нам понадобятся оба.

Шаг 3: Создание вашего первого A/B-теста в PostHog

Теперь давайте создадим эксперимент на панели управления PostHog:

  1. Войдите в свой экземпляр PostHog.
  2. Перейдите на вкладку A/B-тестирование.
  3. Нажмите Новый эксперимент.
  4. Заполните детали:
    • Название: «Тест кнопки на главной странице»
    • Ключ флага функции: homepage-button-test
    • Оставьте другие поля по умолчанию.
  5. Нажмите Сохранить как черновик.
  6. Установите основную метрику как тренд $pageview.
  7. Нажмите Запустить.

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

Шаг 4: Реализация флагов функций в вашем коде Go

Здесь находится логика A/B-тестирования. Мы будем:

  1. Получать флаг функции для пользователя.
  2. Определять, какой вариант он увидит.
  3. Предоставлять соответствующий опыт.

Вот обновлённый код: