Раз в несколько лет возвращаюсь к задаче создания алгоритма для наиболее вероятного прогноза на основании ошибок предыдущих прогнозов. В этот раз попробую обойтись минимумом текста (ссылка на демо в конце).
Ссылка на оригинал статьи с объяснением принципа Доказательного Планирования (в оригинале Evidence Based Scheduling) - советую ознакомиться, чтоб быть в контексте: Joel Spolsky Evidence Based Scheduling / Перевод на русский
Для меня лично эта задача имеет небольшую историю:
Версия 1.0 - При желании, можно ознакомиться с первым вариантом увлекательного процесса поиска истины
Версия 2.0 [Вы здесь]
? Версия 1.0: Первый блин в коме (2019)
Как я видел решение этой задачи 5 лет назад (здесь очевидная ошибка): Берем самый худший вариант из предыдущего опыта и проецируем на текущую задачу - это и будет мой прогноз для Продукт Менеджера.
? Версия 2.0: Кажется, это успех (2024)
К примеру, у разработчика (исполнителя) есть несколько решенных задач с параметрами:
Дата начала выполнения задачи (start)
Дата его оценки финиша (estimation)
Дата реального финиша (finish)
Итак, добавлена новая задача, получен estimation от разраба. Теперь вопрос - насколько он ошибся в этот раз?
Алгоритм расчета наиболее худшего сценария: Берем скорость самой неудачной задачи этого разработчика и вычисляем дату окончания текущей задачи.
? Алгоритм поиска наиболее вероятного сценария: Думаю, всем очевидно, что скорость "среднюю по больнице" брать - это неточно. Поэтому логика следующая: Человек работает, как правило, [плюс-минус] с одной комфортной скоростью - алгоритм должен ее "ощутить". Как именно: если среди возможных вариантов скоростей его работы встречаются два с минимальным отклонением (Δ) - это повод искать ещё варианты с примерно таким же отклонением. В итоге, найденные варианты образуют "скопления", среднее значение которых можно учитывать как наиболее вероятное (поправьте в комментариях, если я неправ):
// Код чисто для понимания,
// так что на императивщину не смотрите,
// чуть позже перепишу на ООП
// NOTE: 1. Отсортированный список скоростей выполнения задач
const sortedSpeeds: { v: number }[] = speeds.sort((e1, e2) => e1.v - e2.v)
// NOTE: 2. Список отклонений между этими скоростями
const deltas: {
speed: number | null;
delta: number | null;
prev: number | null;
next: number | null;
isSensed: boolean; // Это тот самый показатель "чувствительности"
}[] = []
let minDelta = 1000000
let maxDelta = 0
for (let i = 0, max = sortedSpeeds.length; i < max; i++) {
const prevValue = !!sortedSpeeds[i - 1]
? sortedSpeeds[i - 1]
: null
const nextValue = !!sortedSpeeds[i + 1]
? sortedSpeeds[i + 1]
: null
const currentValue = sortedSpeeds[i]
const delta = typeof prevValue?.v === 'number'
? currentValue.v - (prevValue.v)
: null
deltas.push({
speed: sortedSpeeds[i].v,
delta, next: nextValue?.v || null,
prev: prevValue?.v || null,
isSensed: false, // By default
})
if (typeof delta === 'number') {
if (minDelta >= delta) minDelta = delta
if (maxDelta <= delta) maxDelta = delta
}
}
// NOTE: 3. Оставим только скорости с минимальным отклонением друг от друга
// Коэфф sensibility нужен для большего охвата задач, когда их немного (я беру 4)
// По мере роста задач коэфф. sensibility можно уменьшать до значения 1-2
const sensed: {
counter: number;
speedValues: number[];
averageSpeed: number;
} = {
counter: 0,
speedValues: [],
averageSpeed: 0,
}
for (let i = 0, max = deltas.length; i< max; i++) {
if ((deltas[i].delta as number) <= sensibility * minDelta) {
deltas[i].isSensed = true
if (typeof deltas[i].speed === 'number') {
sensed.counter += 1
sensed.speedValues.push((deltas[i].speed as number))
}
}
else
deltas[i].isSensed = false
}
// NOTE: 4. Все! Теперь наиболее вероятная дата финиша
// может быть расчитана в соответствии с наиболее вероятной скоростью:
sensed.averageSpeed = getArithmeticalMean(sensed.speedValues)
Где тут Теория вероятностей? [спросите Вы]
Существует понятие Функция распределения вероятностей. Закон распределения вероятностей получил свое название из-за его способности разбросать вероятность между значениями случайной величины чтобы в итоге она составила единицу.
Используя библиотеку react-google-charts, я получил (в грубом виде) кривую (в данном случае она прямая, но это не важно) распределения вероятностей, основанную на данных предыдущих опытов:
Итак, мой вывод в двух тезисах:
В точке X та самая скорость, которую нужно считать наиболее вероятной (она же идеально комфортная для данного исполнителя)
Приблизиться к ней можно, сделав N опытов, уменьшая погрешность с каждым новым опытом
В споре рождается истина. Спорьте со мной в комментах )
Комментарии (5)
Silen07
17.01.2025 09:29А где тут теория вероятностей?
Я то думал будет что-то в духе опросили 100500 разработчиков, результаты показали что ..., мы разделили разработчиков на несколько кластеров, те кто работают и тех кто балду пинает, и выяснили что в среднем для первых можно время умножать на 10% а для вторых от 5 до 35%.
pravosleva Автор
17.01.2025 09:29Попробую объяснить проще:
Существует такое понятие как функция распределения вероятностей (в приложении он также строится под названием "Timing distribution according to previous experience") - так вот, в точке x на графике изменение скорости ("Δ" в контексте статьи) стремится к нулю - про расчет этой наиболее вероятной скорости реализации фичи идёт речь в статье. А ту статистику про которую говорите Вы - можно собрать самому, используя этот расчет.
Но спасибо за фидбек, я добавлю пояснения в статью.
Ndochp
17.01.2025 09:29Кажется здесь стоит вспомнить эксельку от Дорофеева https://cartmendum.livejournal.com/tag/scrum
S-type
Статью не дописали и случайно опубликовали?
pravosleva Автор
В поисках баланса между "изложить полезное и интересное", "поменьше текста" и "хотя бы немного кода" пришел к результату в виде коммента на который сейчас отвечаю. Спасибо за фидбек ) периодически возвращаюсь к редактированию.
Вот предыдущий вариант статьи. В этот раз думал сделать компактнее (изучаю метрику читателей для корректировок)