InquirerSara Duterte trial: Prosecution forgoes CSC exec as witnessPunchSoludo’s wife donates relief materials to rehabilitated inmatesRTP DesportoJoão Ferreira e Filipe Palmeiro venceram a Baja de ReguengosBollywood HungamaEXCLUSIVE: Nani, Raghav Juyal, Sonali Kulkarni and Kayadu Lohar to attend MEGA The Paradise event in Mumbai ahead of releaseInquirer EntertainmentKim Chiu’s sis Lakam under police custody after arrest for qualified theftUOLVeja a previsão do tempo para Ivaiporã nesta segunda (21)ColliderThe Biggest Sci-Fi Hit of 2026 Is Officially Back in the Streaming SpotlightAntara NewsIndonesia eyes coal liquefaction to boost energy securityDeadlineEagle Eye Drama Acquires ‘The Great Dictator’, Matthew Sweet’s Biography Of Barbara Cartlandالشرقوزير الخارجية السعودي يبحث مستجدات الأوضاع الإقليمية هاتفياً مع نظرائه في الكويت ومصر وتركياCBS NewsIran warns new U.S. assault would see it expand "geography of the war"Egypt IndependentPM, CBE Governor discuss economic reforms, FX reserves
The Daily Newsstand · Free, Always
Monday, September 21, 2026

Одинаковые слоты в онлайн-записи — это скрытая переработка: считаем на симуляции

Translate

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

Это и есть место, где мы наступили на грабли, о которых дальше пойдёт речь. Сетка у нас, как почти у всех сервисов, была равномерная — слоты по два часа. Выглядит логично: удобно рисовать, удобно объяснять, удобно считать. Только в сервисе, где длительность обслуживания отличается в четыре раза от клиента к клиенту, равномерная сетка работает как сглаживание: она не убирает разброс, а прячет его — и он вылезает переработкой мастеров и дырами в расписании.

Ниже — модель этой задачи, симуляция на 2000 дней и числа, которые из неё выпадают. Скрипт целиком в конце, менять там надо ровно шесть констант.

Почему слот не равен слоту

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

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

Вот наблюдаемые средние по нашим салонам и доли этих типов в потоке записей:

Длительность визита задаёт структура волоса, а не размер животного: разброс от 45 до 165 минут при одном и том же двухчасовом слоте

Длительность визита задаёт структура волоса, а не размер животного: разброс от 45 до 165 минут при одном и том же двухчасовом слоте

Те же числа лежат в константе ТИПЫ в коде ниже — их удобно скопировать и заменить своими.

Средневзвешенная длительность визита — 116 минут, то есть двухчасовой слот выбран не с потолка: в среднем он подходит. Но средний модуль расхождения — 33 минуты на каждую запись. Половина визитов не добирает до слота, половина из него вылезает, и «в среднем сходится» здесь — ровно та формулировка, из-за которой задачу и не замечают.

Модель

Симулируем рабочий день салона.

  • Три мастера, смена двенадцать часов (10:00–22:00).

  • Поток заявок за день задаём числом: 12, 15 или 18.

  • Тип каждой заявки разыгрывается по долям из таблицы выше.

  • Фактическая длительность визита — нормальная величина вокруг среднего типа, усечённая снизу третью среднего и сверху двумя средними: собака попалась спокойная или, наоборот, всё оказалось хуже, чем на осмотре.

  • Заявка уходит к мастеру с наименьшей забронированной загрузкой; если слот не влезает в смену, запись не принимается.

Сравниваем две сетки:

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

B. Слот по типу шерсти. Длительность подставляется системой в момент записи из пары «услуга + порода» и округляется вверх до пятнадцати минут.

Метрики считаем три:

  • загрузка — доля полезной работы в фонде рабочего времени смены;

  • простой — минуты внутри смены, когда мастер свободен, потому что следующий слот ещё не начался;

  • переработка — минуты за пределами смены, когда мастер доделывает начатое.

Последняя метрика и есть то, ради чего всё считалось: в сервисе она оплачивается не деньгами, а текучкой.

Результаты

Один и тот же сид, один и тот же поток заявок, разные сетки. 2000 прогонов на каждую точку.

Заявок в день

Сетка

Загрузка

Простой

Переработка

Принято

Отказ

Дней с переработкой

12

A. равные 2 ч

63,9%

153 мин

0,5 мин

12,0

0

2%

12

B. по типу

63,9%

70 мин

0,2 мин

12,0

0

1%

15

A. равные 2 ч

80,1%

171 мин

17 мин

15,0

0

27%

15

B. по типу

79,8%

78 мин

7 мин

14,96

0,04

16%

18

A. равные 2 ч

96,1%

195 мин

110 мин

18,0

0

78%

18

B. по типу

90,6%

82 мин

29 мин

17,14

0,86

49%

Что здесь важно.

Куда уходит смена при пятнадцати заявках: загрузка в обоих режимах одинаковая, а простой и переработка отличаются вдвое и втрое

Куда уходит смена при пятнадцати заявках: загрузка в обоих режимах одинаковая, а простой и переработка отличаются вдвое и втрое

Загрузка почти не отличается. Именно поэтому задача годами не видна из отчётов: если смотреть на процент занятости мастеров — а это первое, что показывает любая система записи, — две сетки выглядят одинаково. Разница прячется в двух других колонках.

Простой отличается вдвое с лишним. 153 минуты против 70 при двенадцати заявках, 171 против 78 при пятнадцати. Это не абстракция: это два часа в день, за которые мастеру платят и в которые он ничего не делает, потому что следующая запись начнётся в 16:00, а он освободился в 15:05.

Переработка отличается в разы. При пятнадцати заявках — 17 минут против 7 в день, при восемнадцати — 110 против 29. И, что важнее среднего, меняется частота: на плотном дне равная сетка даёт переработку в 78% дней против 49%.

И самое неприятное. При восемнадцати заявках сетка B отказывает в среднем 0,9 заявки в день, а сетка A — ни одной. Со стороны бизнеса это выглядит как проигрыш: одна потерянная запись. На деле это честность: заявка, которую сетка B не приняла, в сетке A принимается и превращается в два часа переработки. Пропускную способность равномерная сетка не увеличивает: она лишь перекладывает превышение на людей.

Причём тут ночные записи

Пока запись создаёт администратор, разницы между сетками почти нет: он знает породу, знает мастера и руками ставит нужное время. Модель выше описывает мир, в котором так и происходит — с одной поправкой: у нас почти половина записей создаётся без него.

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

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

Чего модель не умеет

Раздел, ради которого стоит читать любую симуляцию.

Нет очереди с ожиданием. У нас запись, а не живая очередь: заявка либо помещается в сетку, либо не принимается. Классическая теория массового обслуживания сюда прикладывается плохо — там клиент ждёт, здесь он уходит.

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

Нет распределения заявок по времени дня. У нас поток равномерный, а в жизни он двугорбый: утро и вечер плотнее середины дня. Это скорее усиливает эффект, потому что переработка накапливается именно на вечернем горбу.

Нет привязки мастера к типу. В модели любой мастер делает любую собаку с одинаковым средним. В салоне это не так: у кого-то быстрее идут пудели, у кого-то кошки.

Нормальное распределение — допущение. Логнормальное было бы честнее: длительность не бывает отрицательной, а правый хвост у неё длиннее. Мы взяли усечённую нормаль ради читаемости кода; на порядок величин это не влияет, проверяли заменой распределения.

Код целиком

import random
import statistics
from dataclasses import dataclass

СИД = 20260917
МАСТЕРОВ = 3
СМЕНА = 12 * 60        # минут
ДНЕЙ = 2000
РАВНЫЙ_СЛОТ = 120      # «универсальная» сетка в режиме A
ОКРУГЛЕНИЕ = 15        # шаг сетки в режиме B

# тип → (среднее время визита, стандартное отклонение, доля в потоке)
ТИПЫ = {
    "ниспадающая": (120, 25, 0.30),
    "объёмная":    (150, 30, 0.14),
    "двойная":     (165, 45, 0.18),
    "жёсткая":     (150, 30, 0.06),
    "гладкая":      (45, 10, 0.14),
    "кошки":        (75, 20, 0.18),
}


@dataclass
class День:
    работа: float
    простой: float
    переработка: float
    принято: int
    отказано: int


def длительность(тип, rnd):
    среднее, разброс, _ = ТИПЫ[тип]
    v = rnd.gauss(среднее, разброс)
    return max(среднее / 3, min(среднее * 2, v))


def поток(rnd, заявок):
    типы = list(ТИПЫ)
    веса = [ТИПЫ[т][2] for т in типы]
    return rnd.choices(типы, weights=веса, k=заявок)


def слот_равный(_тип):
    return РАВНЫЙ_СЛОТ


def слот_по_типу(тип):
    среднее = ТИПЫ[тип][0]
    return -(-среднее // ОКРУГЛЕНИЕ) * ОКРУГЛЕНИЕ


def прожить_день(rnd, заявки, слот):
    план = [0] * МАСТЕРОВ
    факт = [0.0] * МАСТЕРОВ
    принято = отказано = 0

    for тип in заявки:
        нужно = слот(тип)
        i = min(range(МАСТЕРОВ), key=lambda k: план[k])
        if план[i] + нужно > СМЕНА:
            отказано += 1
            continue
        план[i] += нужно
        факт[i] += длительность(тип, rnd)
        принято += 1

    конец = [max(п, ф) for п, ф in zip(план, факт)]
    return День(
        работа=sum(факт),
        простой=sum(max(0.0, min(к, СМЕНА) - ф) for к, ф in zip(конец, факт)),
        переработка=sum(max(0.0, к - СМЕНА) for к in конец),
        принято=принято,
        отказано=отказано,
    )


def прогон(слот, заявок_в_день):
    rnd = random.Random(СИД)
    дни = [прожить_день(rnd, поток(rnd, заявок_в_день), слот) for _ in range(ДНЕЙ)]
    ёмкость = МАСТЕРОВ * СМЕНА
    return {
        "загрузка": statistics.fmean(д.работа for д in дни) / ёмкость,
        "простой": statistics.fmean(д.простой for д in дни),
        "переработка": statistics.fmean(д.переработка for д in дни),
        "принято": statistics.fmean(д.принято for д in дни),
        "отказано": statistics.fmean(д.отказано for д in дни),
        "дни_с_переработкой": statistics.fmean(д.переработка > 0 for д in дни),
    }


if __name__ == "__main__":
    for заявок in (12, 15, 18):
        for имя, слот in (("A", слот_равный), ("B", слот_по_типу)):
            р = прогон(слот, заявок)
            print(заявок, имя, {к: round(v, 2) for к, v in р.items()})

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

Что мы поменяли у себя

Три вещи, в порядке отдачи.

Длительность выводится из пары «услуга + порода» в момент записи. Клиент видит не «свободно с 14:00 до 16:00», а конкретное окно нужной длины. Это единственное изменение, которое вообще что-то дало на потоке ночных записей.

Сетка стала пятнадцатиминутной. Не потому, что кто-то записывается на 14:15, а потому что на такой сетке округление вверх стоит в среднем семь минут вместо получаса.

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

Вывод

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

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

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.