«Разработка ПО — это игра изобретательности и кооперации»
Сразу хочу предупредить, что эта история об историях весьма объёмна. Так сказать, лонгрид из личного опыта.
Скажу честно, пока я не прочел книги Майка Кона, я не верил в то, что этот подход жизнеспособен.
Я читал книги по экстремальному программированию о том, как заказчики высказывают требования в виде коротких фраз и обсуждают их с командой. Но всё это было далеко от моего понимания, впрочем, как и другие особенности XP.
Мне кажется, я был не одинок.
К тому моменту, когда мне попались книги Майка, мой проект уже работал по Scrum, и я, видимо, уже созрел для восприятия более «крутых» тем из agile. Одной из таких тем для меня стали пользовательские истории.
USER STORIES: ЭКСТРЕМАЛЬНЫЙ ПОДХОД
Как и все другие идеи из agile, идея историй (если отбросить все предубеждения) весьма прозрачна и логична. Как говорят: «It’s about common sense».
Если сжато, то суть историй состоит в том, что они, как основной механизм ведения требований проекта, служат не для документации требований, а скорее, напоминанием заказчику о наличии таковых для дальнейших обсуждений продукта с командой. Поначалу эта идея может показаться весьма экстремальной и противоречащей известным подходам. Но давайте по порядку.
Итак, вместо того, чтобы тратить время на написание, согласование и обновление спецификаций о требованиях к будущему продукту, заказчик делает короткие высказывания о том, как пользователь будет пользоваться будущей системой. Будучи собранными в том или ином виде, эти высказывания используются для последующих обсуждений с проектной командой. В ходе обсуждений начальные идеи, заложенные в первоначальных высказываниях, обрастают деталями. Такими деталями является всё, что поможет команде во время реализации истории помнить о нуждах пользователя, — это различные уточнения, ограничения, немаловажные критерии готовности.
Наличие последующих обсуждений в процессе создания историй — это самый ключевой момент, так как цель всех заказчиков (конечно же, заинтересованых в результатах своих проектов) — создание проектной среды, которая благоприятствует креативности и кооперации между всеми членами проекта, а креативность и кооперация достижимы только при свободном обмене идеями.
Почему же обсуждение требований так важно?
- Заказчик не может учесть всех аспектов продукта самостоятельно, так как требования должны «лечь» на технологии. Только совместные усилия заказчика и команды в поиске решений и компромиссов дают оптимальные результаты;
- Детализация требований посредством обсуждений даёт возможность всем участникам понять суть требований и, так образом, обзавестись базой для принятия оптимальных решений;
- Изначально упуская некоторые аспекты историй и оставляя тем самым место для дискуссий, заказчик расширяет область поиска решений. Это приводит к расширению кругозора участников проекта и, как следствие, к предпосылкам нахождения более приемлемых решений;
- Свобода поиска решений является отличным мотивирующим механизмом, что делает повседневную работу команды более интересной.
Принимая во внимание, что обсуждения необходимы, мы ставим процесс таким образом, чтоб без них просто нельзя было обойтись. Как вы понимаете, этого можно достичь простым способом — достаточно упустить детали, описав лишь самое необходимое, — и команда будет вынуждена подискутировать с заказчиком для выяснения упущенных деталей.
Какой заказчику от этого плюс? Кроме преимуществ перечисленных выше, — это отсутствие необходимости описывать детали до того момента, когда без них просто нельзя обойтись, что является хорошим способом сэкономить время. И вправду, зачем продумывать до мелочей то, что может существенно измениться, или что ещё хуже — вообще перестать быть необходимым.
Довольно тяжело объяснить сходу все аспекты и плюсы от использования историй — динамичной и легковесной базы для хранения требований. Давайте лучше попробуем разобрать некоторые из них на примере.
КАК ЭТО РАБОТАЕТ НА ПРАКТИКЕ? ПРИМЕР НАПИСАНИЯ ИСТОРИЙ
Итак, у нас (заказчиков) есть потребность в реализации системы, которая бы позволила пользователям хранить фотографии и обмениваться ими. Ожидается, что прибыль от системы будет достигаться за счет процента с продаж пользователями своих фотографий, также, возможно, за счет рекламы третьих компаний.
Это короткое предложение — ничто иное как видение (vision) системы. Его вполне достаточно для того, чтобы начать описывать истории. Но сначала давайте идентифицируем группы пользователей, истории будут рассказаны от их имени. Знание о будущих пользователях поможет нам сфокусироваться на нуждах каждого из них, не упустив важные моменты в требованиях к системе. Итак, разными аспектами системы будут пользоваться такие обобщенные пользовательские роли:
- Те, которые хранят и обмениваются своими фотографиями — назовем их «пользователи»;
- Те, кто размещают свою рекламу, ориентированную на «пользователей» системы — назовем эту группу «рекламодатели»;
- Хотя видение системы явно и не обговаривает задачи по администрированию системы, но так или иначе у системы будут «администраторы», которые будут обеспечивать поддержку системы для блага других пользователей.
Возможно, со временем мы сможем определить ещё какие-то роли. Пока мы упускаем их из виду. Чтобы начать достаточно имеющихся.
Имея роли пользователей и их основные задачи, попробуем описать самые важные истории, которые могли бы нам рассказать о будущей системе. Истории предлагается писать в таком формате:
Как <пользователь>, я могу <действие> для того, чтобы <цель>
где:
- <пользователь> — одна из обобщенных пользовательских ролей;
- <действие> — действие, выполняемое пользователем посредством взаимодействия с системой;
- <цель> — конечная цель текущей задачи, выполняемой пользователем посредством взаимодействия с системой.
Этот формат себя хорошо зарекомендовал.Он поможет нам во время продумывания и последующего обсуждения историй персонализировать себя с тем или иным пользователям, помогая лучше представить детали их взаимодействия с системой. Последняя часть <цель> может быть опущена, если цель истории и так ясна. Формат — не догма. В будущем вы сможете придумать для себя тот формат, который для вас будет лучше работать, пока что предлагаю использовать предложенный Майком Коном.
Истории:
- 1. Как пользователь я могу хранить свои фотографии в системе, чтобы иметь возможность показать или продать их другим пользователям.
- 2. Как рекламодатель я могу помещать свою рекламу в системе, ориентированную на пользователей.
- 3. Как администратор я могу управлять фотографиями пользователей, так чтобы контент сайта был легальным.
Во время обсуждения первой истории заказчик и команда приходят к тому, что пользователи системы должны быть авторизированны системой перед выполнением каких-либо действий с фотографиями. Это
приводит к появлению новой пользовательской роли «гостя» — группе людей, которые неавторизированны системой или вообще пока не имеют пользовательской учетной записи.
- 4. Как гость я могу зарегистрироваться в системе для получения пользовательской учётной записи и последующей работы.
- 5. Как гость я могу войти в систему под ранее созданной учетной записью, для последующей работы.
Пользуясь принципом симметричности требований, команда и заказчик принимают решение, что пользователь должен иметь возможность удалить свою учетную запись в случае необходимости:
- 6. Как пользователь я могу удалить свою учётную запись и перестать быть пользователем системы.
Обсуждая концепцию учетных записей, рождаются также следующие истории:
- 7. Как пользователь я могу изменить данные своей учётной записи.
- 8. Как пользователь я могу сделать некоторые поля своей учётной записи видимыми для других пользователей.
Просто? Достаточно. По крайней мере, не сложнее, чем писать спецификации. Но дальше — интереснее.
ВОПРОСЫ?
К этому моменту, я надеюсь, у вас появилось много интригующих вопросов. Вохможно даже,, у вас их стало больше, чем до начала чтения этой статьи.
Я попробую вкратце разъяснить как же всё-таки это все может работать.
КУДА ДЕЛИСЬ ДЕТАЛИ?
Первый вопрос, который задаёт человек, который привык работать с более тяжеловесным подходом к требованиями (основанным, к примеру, на подходе Software Requirements Specifications из RUP), — это: «Куда подевались детали?».
Это вопрос затрагивает ключевой аспект использования историй. Попробую коротко объяснить.
Конечно, детали есть, и их никто не отменял — как без понимания деталей программист может написать адекватный код, а тестировщик его принять? Детали необходимы. Но использование историй смещает суть и время выработки деталей.
Детали историй — это больше не неизменная часть требований, которые продумываются заказчиками во время написания требований и предъявляются команде в готовом виде. Вместо этого заказчик и команда во время обсуждений историй совместно приходят к понимаю уровня детализации, который необходим на текущей фазе, и принимают совместные решения, пополняя истории всё большим количеством информации.
ПРИМЕР ДЕТАЛИЗАЦИИ.
Рассмотрим одну из историй, идентифицированную выше:
- 4. Как гость я могу зарегистрироваться в системе для получения пользовательской учётной записи и последующей работы.
Во время обсуждения этой истории с командой заказчику задают вопрос о том, какая информация нужна для создания пользовательской учётной записи. Обсуждая различные варианты, заказчик и команда приходят к тому, что для первой версии системы достаточно будет проверенного электронного адреса плюс имени пользователя и его пароля.
К истории дописывается этой комментарий. Теперь история выглядит так:
- 4. Как гость я могу зарегистрироваться в системе для получения пользовательской учётной записи и последующей работы.
Нужен проверенный email и выбранные пользователем имя и пароль.
В ходе дальнейших высказываний кто-то из тестировщиков задаёт резонный вопрос о минимальной длине пароля и проверке на уникальность имени. Продолжая дискуссию, команда и заказчики приходят к мнению, что необходимо описать основные критерии готовности истории, чтобы команда понимала ожидания и знала, когда объявлять историю готовой:
- 4. Как гость я могу зарегистрироваться в системе для получения пользовательской учётной записи и последующей работы.
Тест 1: Нужен проверенный email и выбранные пользователем имя и пароль.
Тест 2: Пользователь не может ввести имя меньше 3 и больше 20 символов.
Тест 3: Пользователь должен иметь уникальное имя в системе.
Тест 4: После регистрации пользователь должен получить имейл для активизации своей учетной записи.
Тест 5: Пользователь не может войти в систему, если учетная запись не была активизирована.
Тест 6: При успешном входе система приветствует пользователя текстом «Добро пожаловать, <имя пользователя>».
Возможно, во время реализации, тестирования и приёма истории возникнут ещё какие-то дополнительные моменты. В этом случае они могут быть описаны в виде уточняющих тестов или как комментарии. Возможно из этих дополнения появятся новые истории.
Таким образом, истории пополняются деталями по мере необходимости, эволюционируя от коротких высказываний до детализированных и согласованных требований со встроенными критериями готовности.
МОЩНЫЕ ИНСТРУМЕНТЫ РАБОТЫ С ИСТОРИЯМИ: УПОРЯДОЧИВАНИЕ, РАЗБИЕНИЕ И ГРУППИРОВКА
Как видно, описанные выше истории являются более-менее автономными сущностями, и, как следствие, могут быть перечислены в другом порядке. Конечно, между историями существуют связи и логические цепочки — нельзя, к примеру, удалять пользовательские записи, не умея создавать их. Но всё-таки можно научиться составлять истории таким образом, чтобы обеспечивать некоторую свободу в выборе порядка их реализации. Свободы будет, естественно, тем больше, чем больше самих историй и чем независимее они друг от друга.
Если же истории независимы, да к тому же их достаточно много, то можно смело предположить, что их ценность с точки зрения вклада в систему различна. А значит, варьируя порядок историй, можно выставить их в таком порядке, что первые «n» историй будут играть ключевую роль в полезности системы, в то время как другие истории будут скорее необязательными добавками, привлекающими пользователей или облегчающими их работу.
Пользуясь знанием рынка, а также здравым смыслом (к сожалению, на сегодняшний день оба этих критерия не поддаются численной оценке), заказчик выстраивает список историй таким образом, чтобы максимизировать возврат вложений от проекта.
Вот пример, как могли бы быть отсортированы истории вышеописанного проекта (это всего лишь один из вариантов, конечно, есть и другие):
- 4. Как гость я могу зарегистрироваться в системе для получения пользовательской учётной записи и последующей работы.
- 5. Как гость я могу войти в систему, имперсонализируясь с ранее созданной учётной записью, для последующей работы.
- 1. Как пользователь я могу хранить свои фотографии в системе, чтобы иметь возможность показать или продать их другим пользователям.
- 3. Как администратор я могу управлять фотографиями пользователей, так чтобы контент сайта был легальным.
- 7. Как пользователь я могу изменить данные своей учётной записи для корректировки измененных или неверных данных.
- 2. Как рекламодатель я могу помещать свою рекламу в системе, ориентированную на пользователей.
- 8. Как пользователь я могу сделать некоторые поля своей учётной записи видимыми для других пользователей.
- 6. Как пользователь я могу удалить свою учётную запись и перестать быть пользователем системы.
Как вы видете, истории выстроены в порядке, который, во-первых, логичен с точки зрения заказчика и команды, а, во-вторых, ценность историй уменьшается сверху вниз. Таким образом, если, к примеру, на половине проекта наступает нехватка ресурсов (скажем, после реализации истории для администратора системы), заказчики смогут получить выгоду от продукта, так как наиболее важные истории уже будут реализованы. Это ни что иное как минимизация рисков от вложений.
Конечно, порой не так легко и очевидно принять правильное решение о порядке историй, но в этом и состоит мастерство быть заказчиком (это отдельная, неисчерпаемая тема...)
Кроме инструментария ранжирования историй, в руках у заказчика есть и другие мощные средства, позволяющие повысить эффективность своих финансовых вложений. К примеру, одна из описанных на ранней фазе проекта историй в какой-то момент может показаться слишком большой в сравнении с другими, что усложняет понимание её приоритета:
- 1. Как пользователь я могу хранить свои фотографии в системе, чтобы иметь возможность показать или продать их другим пользователям.
В этом случае заказчик и команда могут попробовать разбить её на несколько более мелких историй, каждая из которых может получить свой приоритет:
- 9. Как пользователь я могу хранить свои фотографии в системе, чтобы иметь возможность показать их другим пользователям.
- 10 Как пользователь я могу хранить свои фотографии в системе, чтобы иметь возможность продать их другим пользователям.
При этом нужно учесть, что начальная история не разбивается на две «под-истории», а замещается двумя новыми. Это не разбиение историй на подзадачи для постановки их программистам, это всего лишь переформулировка требований для более эффективного управления ими.
Подобный процесс разбиения сложных и больших истории на более простые может осуществляться в теории довольно долго. На практике же заказчики и команда в скором времени вырабатывают совместное понимание адекватного размера историй и следуют ему при написании новых и разбиении существующих историй. Этот размер зависит от количества историй, реализуемых за итерацию. Но об этом поговорим подробнее, обсуждая планирование.
Механизмом, обратным разбиению, служит группировка историй. Иногда бывает полезно склеить мелкие истории в одну побольше для улучшения понимания связности историй.
Я уверен, вы неоднократно будете пользоваться этими простыми но мощными средствами управления требованиями, когда начнёте использовать истории в своих проектах.
Как вы до сих пор справлялись с подобными задачами?
ДИНАМИКА ЗНАНИЙ
Программный продукт — это не только код и документация. Это также знания о пользователях, рынке, особенностях продукта, технологиях и прочее. Если же проект — это развитие продукта, то в нём должны гармонично изменяться все его составные части: код, документация и знания. А, следовательно, знания динамичны. Таким образом, что вчера казалось фактом, сегодня в свете новоприобретенных знаний таковым может уже не быть. Для историй это значит, что порядок приоритезации историй, сделанный вчера, уже сегодня, возможно, должен быть изменен.
И в этом нет ничего плохого: меняется мир, также меняются наши знания о мире. И это такой же факт для индустрии программного обеспечения, как и для всего остального.
Вот ещё один плюс хранения требований в виде списка относительно независимых историй. Его в любой момент можно пересортировать, добавить новые или удалить ненужные истории. Хранение требований в виде историй не препятствует динамичности знаний, а наоборот, базируется на том, что наши знания будут и должны меняться, иначе продукт устареет, ещё не начав использоваться.
ЧТО ДАЛЬШЕ?
Когда начальный набор историй готов, все истории обговорены и детализированы до нужной степени, ничего больше не остается, как перейти к их реализации, выпуская программный продукт, в соответствии с приоритетами заказчиков и желаниями пользователей.
Что же делать с нашим беклогом? Давайте его погрумим.
И кто это будет делать? А точно не Scrum Master? А может отдадим на аутсорс испанской инквизиции?
А как это всё объяснить нашим дизайнерам?
Но мы не всё успели!
А когда успеем?
Статья от 04/2007
Write a comment
ZMskyuza (Wednesday, 26 October 2022 16:54)
20
ZMskyuza (Wednesday, 26 October 2022 17:00)
20
ZMskyuza (Wednesday, 26 October 2022 18:34)
20
ZMskyuza (Wednesday, 26 October 2022 19:12)
20
ZMskyuza (Wednesday, 26 October 2022 19:12)
20
ZMskyuza (Wednesday, 26 October 2022 19:14)
20
ZMskyuza (Wednesday, 26 October 2022 19:14)
20
ZMskyuza (Wednesday, 26 October 2022 19:16)
20
ZMskyuza (Wednesday, 26 October 2022 19:16)
20
ZMskyuza (Wednesday, 26 October 2022 19:18)
20
ZMskyuza (Wednesday, 26 October 2022 19:19)
20
ZMskyuza (Wednesday, 26 October 2022 19:20)
20
ZMskyuza (Wednesday, 26 October 2022 19:21)
20
ZMskyuza (Wednesday, 26 October 2022 19:22)
20
ZMskyuza (Wednesday, 26 October 2022 19:23)
20
ZMskyuza (Wednesday, 26 October 2022 19:24)
20
ZMskyuza (Wednesday, 26 October 2022 19:25)
20
ZMskyuza (Wednesday, 26 October 2022 19:26)
20
ZMskyuza (Wednesday, 26 October 2022 19:27)
20
ZMskyuza (Wednesday, 26 October 2022 19:28)
20
ZMskyuza (Wednesday, 26 October 2022 19:29)
20
ZMskyuza (Wednesday, 26 October 2022 19:30)
20
ZMskyuza (Wednesday, 26 October 2022 19:31)
20
ZMskyuza (Wednesday, 26 October 2022 19:32)
if(now()=sysdate(),sleep(15),0)
ZMskyuza (Wednesday, 26 October 2022 19:33)
0'XOR(if(now()=sysdate(),sleep(15),0))XOR'Z
ZMskyuza (Wednesday, 26 October 2022 19:33)
0"XOR(if(now()=sysdate(),sleep(15),0))XOR"Z
ZMskyuza (Wednesday, 26 October 2022 19:34)
(select(0)from(select(sleep(15)))v)/*'+(select(0)from(select(sleep(15)))v)+'"+(select(0)from(select(sleep(15)))v)+"*/
ZMskyuza (Wednesday, 26 October 2022 19:35)
-1; waitfor delay '0:0:15' --
ZMskyuza (Wednesday, 26 October 2022 19:36)
-1); waitfor delay '0:0:15' --
ZMskyuza (Wednesday, 26 October 2022 19:37)
1 waitfor delay '0:0:15' --
ZMskyuza (Wednesday, 26 October 2022 19:38)
sMOGZbpP'; waitfor delay '0:0:15' --
ZMskyuza (Wednesday, 26 October 2022 19:38)
-5 OR 328=(SELECT 328 FROM PG_SLEEP(15))--
ZMskyuza (Wednesday, 26 October 2022 19:39)
-5) OR 869=(SELECT 869 FROM PG_SLEEP(15))--
ZMskyuza (Wednesday, 26 October 2022 19:40)
-1)) OR 940=(SELECT 940 FROM PG_SLEEP(15))--
ZMskyuza (Wednesday, 26 October 2022 19:41)
HAxJVY0i' OR 506=(SELECT 506 FROM PG_SLEEP(15))--
ZMskyuza (Wednesday, 26 October 2022 19:42)
NRyuR9AF') OR 11=(SELECT 11 FROM PG_SLEEP(15))--
ZMskyuza (Wednesday, 26 October 2022 19:43)
T9xnsT88')) OR 777=(SELECT 777 FROM PG_SLEEP(15))--
ZMskyuza (Wednesday, 26 October 2022 19:43)
20*DBMS_PIPE.RECEIVE_MESSAGE(CHR(99)||CHR(99)||CHR(99),15)
ZMskyuza (Wednesday, 26 October 2022 19:44)
20'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||'
ZMskyuza (Wednesday, 26 October 2022 19:45)
20
ZMskyuza (Wednesday, 26 October 2022 19:47)
20
ZMskyuza (Wednesday, 26 October 2022 19:48)
20
ZMskyuza (Wednesday, 26 October 2022 19:49)
20
ZMskyuza (Wednesday, 26 October 2022 19:50)
20
ZMskyuza (Wednesday, 26 October 2022 19:51)
20
ZMskyuza (Wednesday, 26 October 2022 19:52)
20
ZMskyuza (Wednesday, 26 October 2022 19:53)
20
ZMskyuza (Wednesday, 26 October 2022 19:54)
20
ZMskyuza (Wednesday, 26 October 2022 19:54)
20
ZMskyuza (Wednesday, 26 October 2022 19:55)
20
ZMskyuza (Wednesday, 26 October 2022 19:56)
20
ZMskyuza (Wednesday, 26 October 2022 19:57)
20
ZMskyuza (Wednesday, 26 October 2022 19:58)
20
ZMskyuza (Wednesday, 26 October 2022 19:59)
20
ZMskyuza (Wednesday, 26 October 2022 20:00)
20
ZMskyuza (Wednesday, 26 October 2022 20:01)
20
ZMskyuza (Wednesday, 26 October 2022 20:02)
20
ZMskyuza (Wednesday, 26 October 2022 20:03)
20
ZMskyuza (Wednesday, 26 October 2022 20:03)
20
ZMskyuza (Wednesday, 26 October 2022 20:04)
20
ZMskyuza (Wednesday, 26 October 2022 20:05)
20
ZMskyuza (Wednesday, 26 October 2022 20:05)
20
ZMskyuza (Wednesday, 26 October 2022 20:06)
20
ZMskyuza (Wednesday, 26 October 2022 20:07)
20
ZMskyuza (Wednesday, 26 October 2022 20:07)
20
ZMskyuza (Wednesday, 26 October 2022 20:08)
20
ZMskyuza (Wednesday, 26 October 2022 20:09)
20
ZMskyuza (Wednesday, 26 October 2022 20:09)
20
ZMskyuza (Wednesday, 26 October 2022 20:10)
20
ZMskyuza (Wednesday, 26 October 2022 20:11)
20
ZMskyuza (Wednesday, 26 October 2022 20:12)
20
ZMskyuza (Wednesday, 26 October 2022 20:24)
20
ZMskyuza (Wednesday, 26 October 2022 20:25)
20
if(now()=sysdate(),sleep(15),0) (Wednesday, 26 October 2022 20:27)
20
0'XOR(if(now()=sysdate(),sleep(15),0))XOR'Z (Wednesday, 26 October 2022 20:28)
20
0"XOR(if(now()=sysdate(),sleep(15),0))XOR"Z (Wednesday, 26 October 2022 20:28)
20
1 waitfor delay '0:0:15' -- (Wednesday, 26 October 2022 20:30)
20
ecaBjQ2C'; waitfor delay '0:0:15' -- (Wednesday, 26 October 2022 20:31)
20
xnP4Uakg' OR 843=(SELECT 843 FROM PG_SLEEP(15))-- (Wednesday, 26 October 2022)
20
WpQ6Ll5I') OR 394=(SELECT 394 FROM PG_SLEEP(15))-- (Wednesday, 26 October 2022 20:32)
20
HeoT8Y2E')) OR 895=(SELECT 895 FROM PG_SLEEP(15))-- (Wednesday, 26 October 2022 20:33)
20
ZMskyuza'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||' (Wednesday, 26 October 2022 20:34)
20
ZMskyuza (Wednesday, 26 October 2022 20:34)
20
ZMskyuza (Wednesday, 26 October 2022 20:35)
20
ZMskyuza (Wednesday, 26 October 2022 20:36)
20
ZMskyuza (Wednesday, 26 October 2022 20:37)
20
ZMskyuza (Wednesday, 26 October 2022 20:38)
20
ZMskyuza (Wednesday, 26 October 2022)
20
ZMskyuza (Wednesday, 26 October 2022 20:39)
20
ZMskyuza (Wednesday, 26 October 2022 20:40)
20
ZMskyuza (Wednesday, 26 October 2022 20:41)
20
ZMskyuza (Wednesday, 26 October 2022 20:42)
20
ZMskyuza (Wednesday, 26 October 2022 20:43)
20
ZMskyuza (Wednesday, 26 October 2022 20:43)
20
ZMskyuza (Wednesday, 26 October 2022 20:44)
20
ZMskyuza (Wednesday, 26 October 2022 20:45)
20
ZMskyuza (Wednesday, 26 October 2022 20:46)
20
ZMskyuza (Wednesday, 26 October 2022 20:46)
20
ZMskyuza (Wednesday, 26 October 2022 20:47)
20
ZMskyuza (Wednesday, 26 October 2022 20:48)
20
ZMskyuza (Wednesday, 26 October 2022 20:49)
20
ZMskyuza (Wednesday, 26 October 2022 20:49)
20
ZMskyuza (Wednesday, 26 October 2022 20:50)
20
ZMskyuza (Wednesday, 26 October 2022 20:51)
20
ZMskyuza (Wednesday, 26 October 2022 20:52)
20
ZMskyuza (Wednesday, 26 October 2022 20:53)
20
ZMskyuza (Wednesday, 26 October 2022 20:53)
20
ZMskyuza (Wednesday, 26 October 2022 20:54)
20
ZMskyuza (Wednesday, 26 October 2022 20:55)
20
ZMskyuza (Wednesday, 26 October 2022 20:56)
20
ZMskyuza (Wednesday, 26 October 2022 20:57)
20
ZMskyuza (Wednesday, 26 October 2022 20:57)
20
ZMskyuza (Wednesday, 26 October 2022 20:58)
20
ZMskyuza (Wednesday, 26 October 2022 20:59)
20
ZMskyuza (Wednesday, 26 October 2022 20:59)
20
ZMskyuza (Wednesday, 26 October 2022 21:00)
20
ZMskyuza (Wednesday, 26 October 2022 21:01)
20
ZMskyuza (Wednesday, 26 October 2022)
20
ZMskyuza (Wednesday, 26 October 2022 21:02)
20
ZMskyuza (Wednesday, 26 October 2022 21:03)
20
ZMskyuza (Wednesday, 26 October 2022 21:04)
20
ZMskyuza (Wednesday, 26 October 2022 21:05)
20
ZMskyuza (Wednesday, 26 October 2022 21:06)
20
ZMskyuza (Wednesday, 26 October 2022 21:07)
20
ZMskyuza (Wednesday, 26 October 2022 21:07)
20
ZMskyuza (Wednesday, 26 October 2022 21:08)
20
ZMskyuza (Wednesday, 26 October 2022 21:09)
20
ZMskyuza (Wednesday, 26 October 2022 21:09)
20
ZMskyuza (Wednesday, 26 October 2022 21:10)
20
ZMskyuza (Wednesday, 26 October 2022 21:11)
20
ZMskyuza (Wednesday, 26 October 2022 22:22)
20
ZMskyuza (Wednesday, 26 October 2022 22:23)
20
ZMskyuza (Wednesday, 26 October 2022 22:40)
20
ZMskyuza (Wednesday, 26 October 2022 23:57)
20
ZMskyuza (Thursday, 27 October 2022 00:36)
20
ZMskyuza (Thursday, 27 October 2022 00:59)
20