Зачем нужен хэш с солью в A/B экспериментах? 😭 Начнем с хэширования. Когда мы запускаем тест, нужно понять, в какую группу попадет пользователь? В контрольную или тестовую? Чтобы сделать это случайным образом, но при этом всегда стабильно, используется хэширование. Берем уникальный идентификатор пользователя, например user_id, пропускаем его через хэш-функцию (чаще MD5), а результат делим по модулю. Например, если результат деления на 2 равен 0, пользователь идет в группу A, если 1, то в группу B. Это гарантирует, что один и тот же пользователь всегда будет попадать в одну и ту же группу.

`import hashlib

user_id = "12345" hash_value = int(hashlib.md5(user_id.encode()).hexdigest(), 16) group = "A" if hash_value % 2 == 0 else "B" print(group)

🧂 Теперь про соль. Если пользователь участвует сразу в нескольких тестах, его распределение в группы может повторяться. Например, в тесте кнопки “Купить” он будет в группе A, и в тесте фильтра товаров он тоже будет в группе A. Это создает пересечения экспериментов и искажает результаты (особенно, когда речь идет про разные слои, которые могут с собой конкурировать). Соль решает эту проблему. Это уникальная строка для каждого теста, которую мы добавляем к user_id перед хэшированием. Она изолирует тесты друг от друга, даже если пользователь участвует сразу в нескольких. То есть соль + хэш позволяет перемешать пользователей псевдорандомом, обеспечивая воспроизмодимость сплитования на платформе.

`experiment_name = "new_checkout_flow" salted_id = f"{experiment_name}_{user_id}" hash_value = int(hashlib.md5(salted_id.encode()).hexdigest(), 16) group = "A" if hash_value % 2 == 0 else "B"

Таким образом, мы разбили на 2 разные группы. Привязались к идентификатору, конкретному эксперименту и сделали псевдорандомизацию. Можно также генерировать на A/A тестах с изменением соли, обеспечивая рандомизацию пользователей. Это не просто взять и четные значения хэша менять на нечетные и наоборот. Посмотрите, как от соли меняется значение конечного хэша + соли. `print(int(hashlib.md5(f'salt2{123}'.encode()).hexdigest(), 16)), print(int(hashlib.md5(f'salt9{123}'.encode()).hexdigest(), 16))

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

И еще один плюс: если вы решите изменить пропорцию распределения, например, сделать 70% пользователей тестовыми, а 30% контрольными, это легко сделать с помощью хэширования. Нужно просто поменять границы.

`split_percentage = 70 group = "A" if hash_value % 100 < split_percentage else "B"

Понравился пост? Если соберется 100 🐳, выложу пост про виды хэшей и чем они различаются (ну или про слои в A/B экспериментах)````