Руководство по использованию буферов
ПРИМЕЧАНИЕ: Перезапуск игры не очистит и не удалит буфер! Но это предотвратит дальнейший доступ к ранее созданному буферу, так как ID handle будет потерян, что вызовет утечку памяти, которая в конечном итоге приведет к краху вашей игры. Поэтому, перезапуская игру, не забудьте сначала удалить все буферы.
GameMaker Studio 2 позволяет создавать четыре различных типа буферов. Причина этого заключается в том, что буферы предназначены для высоко оптимизированного временного хранения данных, и поэтому вы должны создавать буфер, соответствующий типу данных, которые вы хотите в нем хранить, иначе вы можете получить ошибки или вызвать узкое место в вашем коде. Прежде чем объяснять это дальше, давайте рассмотрим четыре доступных типа буферов (определенные как константы в GML ):
| Постоянная | описание |
|---|---|
| buffer_fixed | Буфер фиксированного размера в байтах. Размер устанавливается при создании буфера и больше не может быть изменен. |
| buffer_grow | Буфер, который будет динамически увеличиваться по мере добавления данных. Вы создаете его с начальным размером (который должен быть приблизительно равен размеру данных, которые предполагается хранить), а затем он будет расширяться, принимая данные, превышающие этот начальный размер. |
| buffer_wrap | Буфер, в который будут заворачиваться данные. Когда добавляемые данные достигнут предела размера буфера, перезапись будет помещена обратно в начало буфера, и дальнейшая запись продолжится с этого момента. |
| buffer_fast | Это специальный «урезанный» буфер, который очень быстро читается и записывается. Однако он может использоваться только с типами данных buffer_u8 и должен быть выровнен по 1 байту. (Информацию о типах данных и выравнивании байтов можно найти далее на этой странице). |
При создании буфера всегда старайтесь создавать его с размером, соответствующим типу, общее правило гласит, что он должен быть создан для максимального размера данных, которые он должен хранить, а если есть сомнения, используйте растущий буфер для предотвращения ошибок перезаписи.
Фактический код для создания буфера будет выглядеть примерно так:
player_buffer = buffer_create(16384, buffer_fixed, 2);
Это создаст фиксированный буфер размером 16384 байта с выравниванием по байтам до 2, при этом функция возвращает уникальное значение ID, которое хранится в переменной для последующего обращения к этому буферу.
При чтении и записи данных в буфер, вы делаете это «кусками» данных, определяемыми их «типом данных». Тип данных» задает количество байт, выделяемых в буфере для записываемого значения, и очень важно, чтобы это было правильно, иначе вы получите очень странные результаты (или даже ошибки) для вашего кода.
Запись в буфер (и чтение из него) происходит последовательно, то есть одна часть данных записывается за другой, причем каждая часть данных имеет определенный тип. Это означает, что в идеале вы должны постоянно знать, какие данные вы записываете в буфер. Эти типы данных определяются в GML следующими константами:
Итак, допустим, вы создали буфер и хотите записать в него информацию, тогда вы используете что-то вроде следующего кода:
buffer_write(buff, buffer_bool, global.Sound);
buffer_write(buff, buffer_bool, global.Music);
buffer_write(buff, buffer_s16, obj_Player.x);
buffer_write(buff, buffer_s16, obj_Player.y);
buffer_write(buff, buffer_string, global.Player_Name);
Рассмотрев приведенный выше пример, можно увидеть, что в буфер можно одновременно записывать различные типы данных (при использовании быстрого типа буфера вы ограничены только определенным типом данных), и эти данные будут добавляться в буфер последовательно (хотя их фактическое положение в буфере будет зависеть от их выравнивания по байтам, о чем будет сказано ниже). То же самое относится и к чтению информации из буфера, и в случае приведенного выше примера вы будете читать из буфера в том же порядке, в котором записывали данные, проверяя наличие одного и того же типа данных, например:
global.Sound = buffer_read(buff, buffer_bool);
global.Music = buffer_read(buff, buffer_bool);
obj_Player.x = buffer_read(buff, buffer_s16);
obj_Player.y = buffer_read(buff, buffer_s16);
global.Player_Name = buffer_read(buff, buffer_string);
Как вы видите, вы считываете информацию в том же порядке, в котором вы считываете ее в буфер. Для получения дополнительной информации о том, как добавлять и удалять данные из буфера, смотрите примеры, приведенные ниже.
Если вы читали эту страницу, то наверняка видели упоминания о выравнивании байтов в буфере. В основном это относится к позиции, в которой новые данные будут храниться в данном буфере. Как это работает? Для буфера с выравниванием по одному байту каждый фрагмент данных записывается в буфер последовательно, причем каждый новый фрагмент данных добавляется непосредственно после предыдущего. Однако буфер с выравниванием по 2 байтам будет записывать каждый фрагмент данных с интервалом в 2 байта, так что даже если ваша первоначальная запись составляет 1 байт данных, следующая запись будет перемещена для выравнивания по двум байтам:
Однако если вы запишете еще один фрагмент данных размером в 1 байт, а затем выполните буфер tell, вы получите смещение в 5 байт (даже если вы записали только 2 байта данных), так как выравнивание добавило данные, чтобы выровнять их с выравниванием буфера в 4 байта.
По сути, это означает, что выравнивание влияет только на то , куда записываются данные, поэтому если после записи чего-либо вы сделаете буфер tell, он вернет текущую позицию записи, которая следует сразу за данными, которые вы записали ранее. Обратите внимание, однако, что если после этого вы запишете еще один фрагмент данных, буфер с внутренней стороны переместит позицию записи на следующую кратную величину выравнивания, прежде чем записать этот фрагмент данных.
Ниже мы приводим несколько примеров использования буферов в проекте:
ПРИМЕЧАНИЕ: Эта функция очень ограничена и предназначена для новичков, чтобы быстро запустить систему контрольных точек, но более опытные пользователи могут предпочесть кодировать свою собственную систему, используя функции File, из-за того, что игра не будет сохранять динамические ресурсы, которые вы можете создавать во время выполнения, такие как структуры данных, поверхности, добавленные sprites и т.д..
Первое, что нам нужно сделать, это создать новый объект для управления сохранением и загрузкой, поэтому создайте его и дайте ему событие Create. В этом событии вы можете разместить следующий код:
SaveBuffer = buffer_create(1024, buffer_grow, 1);
StateSaved = false;
Первая строка создает растущий буфер (поскольку мы не знаем окончательного размера сохраненных данных) размером 1024 байта с выравниванием по 1 байту. Затем создается переменная для проверки, была ли игра сохранена или нет (она будет использоваться для загрузки).
Далее мы добавим событие нажатия клавиш (например, Keypress Event ), в котором мы сохраним текущее состояние игры в созданный буфер:
StateSaved = true;
buffer_seek(SaveBuffer, buffer_seek_start, 0);
game_save_buffer(SaveBuffer);
Теперь мы сохранили текущее состояние игры в буфер. Следующим шагом будет разработка кода для его загрузки, возможно, в другом событии Keypress Event:
if StateSaved
<
buffer_seek(SaveBuffer, buffer_seek_start, 0);
game_load_buffer(SaveBuffer);
>
Игра будет загружена в конце события, в котором вы разместите приведенный выше код.
ПРИМЕЧАНИЕ: Это только для использования в одной комнате, а не для создания полных сохраненных игр после закрытия или перезапуска игры!
Теперь этот объект можно поместить в комнату и по нажатию клавиши сохранить и загрузить состояние комнаты из буфера.
При работе с сетевыми функциями GameMaker Studio 2 необходимо использовать буферы для создания пакета данных, который передается по сетевому соединению. Данный пример призван показать, как это делается, но в связи с широкими возможностями сетевых функций, он предназначен только для демонстрации использования самих буферов, а не всей сетевой системы.
Первое, что мы покажем, это создание и использование буфера для клиентской стороны сетевого соединения. Этот буфер будет использоваться для создания небольших пакетов данных, которые затем могут быть отправлены на сервер, поэтому в событии Create экземпляра мы назначим буфер следующим образом:
send_buff = buffer_create(256, buffer_grow, 1);
Теперь предположим, что мы хотим, чтобы наш клиент отправлял данные на сервер. Для этого нам нужно создать буферный «пакет», и в этом примере мы собираемся отправить событие нажатия клавиши, например, когда игрок нажимает стрелку влево для перемещения по игре. Для этого мы сначала запишем необходимые данные в буфер, а затем отправим их:
buffer_seek(buff, buffer_seek_start, 0);
buffer_write(buff, buffer_u8, 1);
buffer_write(buff, buffer_s16, vk_left);
buffer_write(buff, buffer_bool, true);
network_send_packet(client, buff, buffer_tell(buff));
Перед записью в буфер мы установили «tell» в начало буфера, так как networking всегда берет данные из начала буфера. Затем мы записываем контрольное значение (оно будет использоваться сервером для определения типа обрабатываемого события), затем используемую клавишу, а затем состояние клавиши (в данном случае true для нажатой). Этот буфер затем отправляется сетевой функцией в виде пакета данных. Обратите внимание, что мы не отправляем весь буфер! Мы отправляем только записанные данные, используя функцию buffer_tell для возврата текущей позиции чтения/записи в буфере (помните, что запись в буфер перемещает «tell» в конец того, что было записано). Это делается просто для того, чтобы избежать отправки большего количества байт, чем необходимо.
А как насчет получения данных на сервере? Полученный пакет данных должен быть записан в буфер на сервере и затем использован для обновления игры. Для этого мы будем использовать асинхронное событие Networking в объекте сетевого контроллера сервера, как показано в этом упрощенном коде ниже:
var buff = ds_map_find_value(async_load, «buffer»);
if cmd == buffer_read(buff, buffer_u8);
<
key = buffer_read(buff, buffer_s16);
key_state = buffer_read(buff, buffer_bool);
>
Термин: Буферизация потоков данных
При разработке программ, работающих с потоками данных АЦП и ЦАП, возникает задача обеспечить обработку данных с достаточной скоростью.
Скорость потока данных определяется частотой дискретизации и не регулируется программой: физический процесс не может ждать. Если потерять часть отсчётов, то сигнал будет испорчен.
При этом компьютер, исполняющий программу, обычно работает не в реальном времени, т.е. если один шаг программы следует «сразу» за другим, то это «сразу» следует понимать как последовательность выполнения операций, а не как реальное время. Некоторые операции (например, запись на диск) могут выполняться относительно долго. Также в многозадачной операционной системе есть много процессов, прерывающих друг друга, так что программа может «застопориваться» в случайные для неё моменты времени (иногда довольно надолго – на десятки, даже сотни миллисекунд).
Кроме того, при программировании бывает необходимо обрабатывать данные блоками (порциями), а не по одному отсчету, иначе накладные расходы сведут на нет быстродействие даже современного компьютера.
Для решения этой задачи применяется буферизация.
Буфер – это массив в памяти с быстрым доступом, в котором накапливаются поступающие данные (если это поток ввода, АЦП) или из которого они отправляются с заданной скоростью (если это поток вывода, ЦАП).
При вводе данных процесс начинается с пустым буфером. При выводе буфер должен быть предварительно заполнен, иначе в начале работы может сразу произойти опустошение буфера.
Производительность обработки данных компьютером должна быть больше скорости потока (с запасом), а вот мгновенная скорость может падать, лишь бы буфер ввода не переполнился, а буфер вывода не опустел. Запас по скорости нужен, чтобы разбирать данные, накопившиеся в буфере из-за паузы (а при выводе – чтобы снова наполнить буфер).
Образно можно представить себе буфер ввода как бак, в который из трубы с постоянной скоростью поступает вода. Мы зачерпываем эту воду ведром, относим потребителю и возвращаемся; чем больше бак, тем больше времени у нас есть на непредвиденные задержки по дороге. В идеале в баке должно быть не больше ведра воды, тогда, уходя, мы оставляем его пустым и имеем максимальный запас времени. Если же случилась задержка и набралось много воды, мы начинаем торопиться, чтобы побыстрее вычерпать её.
С буфером вывода всё то же самое, только вода уходит из бака с постоянной скоростью (и прерывать подачу нельзя, это авария), а мы наливаем вёдрами. Соответственно максимальную защиту от задержек обеспечивает полный бак, а если уровень упал – его надо побыстрее восполнить.
На практике такая схема может быть реализована в виде кольцевого буфера или списка блоков меньшего размера («вёдер»), которые ставятся в очередь. По мере готовности они обрабатываются, освободившиеся блоки-вёдра ставятся в конец очереди.
Простейший вариант – это схема с двумя буферами (двумя половинами большого буфера): когда готова одна половина, она обрабатывается, в это время данные собираются во второй половине, и за время ее заполнения должна завершиться обработка первой, потом половины «меняются ролями». Если продолжать аналогию с вёдрами, то здесь нет бака, зато есть два ведра: набрав полное ведро, мы сразу подставляем пустое и относим полное на грядку. Это очень простая и эффективная схема, но в ней размер порции обработки данных (и связанная с ним задержка) увязывается с размером буфера, что иногда неудобно.
Для использованной выше бытовой аналогии буфера и ведра сделаем важную оговорку, что под буфером (в системах сбора данных и управления) подразумевается последовательная структура, в которой данные не теряются (ведро не дырявое) и последовательность данных не изменяется. Другими словами, попавший в буфер отсчёт данных не может обогнать ранее пришедший отсчёт.
Также отметим, что реализация буфера может быть не только программная, но и аппаратная, например в FPGA, по типу линейной очереди заданного максимального размера «первым вошёл – первым вышел» (FIFO – First In, First Out).
Если термин «буферизация» рассматривать шире, то буферизация может быть и без сохранения естественного порядка следования данных, например, LIFO «последним вошёл – первым вышел» (LIFO – Last In, First Out). Другое известное название буфера LIFO – это стек (Stack), который широко применяется в программировании.
При сравнении характеристик систем сбора данных важен не просто байтовый объём буфера в системе, а расчётное максимальное время буферизации сигнала при данной скорости ввода данных (для АЦП) или вывода данных (ЦАП). Для расчёта времени буферизации следует учитывать необходимую скорость сбора данных (отсчётов в секунду) и размер слова данных, занимаемый одним отсчётом (типично: 2 или 4 байта). В слове, кроме отсчёта данных, может находиться вспомогательная индексная информация, маркирующая поток данных для разных вспомогательных задач при работе с данными на верхнем программном уровне в ПК.
При рассмотрении термина «буферизация» применительно к реальной работе систем сбора данных следует отметить, что в данном случае процесс буферизации данных будет носить многоуровневый характер: буферизация будет происходить как в устройстве, так и в компьютере, часто не только в ПО верхнего уровня, но и на уровне драйвера используемого интерфейса (например, драйвера USB). Особенно в случае использования операционной системы компьютера, не относящейся к системам «реального времени», типично может наблюдаться значительное непостоянство времени буферизации сигнала при неизменной скорости ввода-вывода данных.
С данной темой связаны следующие статьи:
Пример использования термина
Терминология, связанная с буферизацией потоков данных, широко используется в руководствах на различные системы сбора данных (LTR, E-502, L-502, E14-x40 и т.д.) при описании их функциональных схем и программных интерфейсов.
Измерительная система LTR
АЦП: 16 бит; 16/32 каналов;
±0,2 В…10 В; 2 МГц
ЦАП: 16 бит; 2 канала; ±5 В; 1 МГц
Цифровые входы/выходы:
17/16, ТТЛ 5 В
Интерфейс: USB 2.0 (high-speed), Ethernet (100 Мбит)
Гальваническая развязка.
Модуль АЦП/ЦАП
16/32 каналов, 16 бит, 2 МГц, USB, Ethernet
E-502
АЦП: 16 бит; 16/32 каналов;
±0,2 В…10 В; 2 МГц
ЦАП: 16 бит; 2 канала; ±5 В; 1 МГц
Цифровые входы/выходы:
18/16 TTL 5 В
Интерфейс: PCI Express
Плата АЦП/ЦАП
16/32 каналов, 16 бит, 2 МГц, PCI Express
L-502
АЦП: 14 бит; 4 канала;
±0,3 В…3 В; 10 МГц
ЦАП: 12 бит; 2 канала; ±5 В; 8 мкс
Цифровые входы/выходы:
16/16 ТТЛ, 5 В
Интерфейс: USB 2.0 (high-speed).
Модуль АЦП/ЦАП
4 канала, 14 бит, 10 МГц, USB
E20-10
АЦП: 14 бит; 16/32 каналов;
±0,15 В…10 В; 200 кГц
ЦАП: 16 бит; 2 канала; ±5 В; 200 кГц
Цифровые входы/выходы:
16/16 TTL 5 В
Интерфейс: USB 2.0
Модуль АЦП/ЦАП
16/32 каналов, 14 бит, 200 кГц, USB
E14-140M
АЦП: 14 бит; 16/32 каналов;
±0,156 В…10 В; 400 кГц
ЦАП: 12 бит; 2 канала; ±5 В; 8 мкс
Цифровые входы/выходы:
16/16 TTL 5 В
Интерфейс: USB 2.0
Модуль АЦП/ЦАП
16/32 каналов, 14 бит, 400 кГц, USB
БУФЕРЫ
При выполнении данной программы (любой из двух ее версий) вводимый символ в одних вычислительных системах немедленно появляется на экране («эхо-печать»), в других же ничего не происходит до тех пор, пока вы не нажмете клавишу [ввод]. Первый случай относится к так называемому «небуферизованному» («прямому») вводу, означающему, что вводимый символ оказывается немедленно доступным ожидающей программе. Второй случай служит примером «буферизованного» ввода, когда вводимые символы собираются и помешаются в некоторую область временной памяти, называемую «буфером». Нажатие клавиши [ввод] приводит к тому, что блок символов (или один символ) становится доступным программе. В нашей программе применяется только первый символ, поскольку функция getchar( ) вызывается в ней один раз. Например, работа нашей программы в системе, использующей буферизованный ввод, будет выглядеть следующим образом:
Вот длинная входная строка. [ввод] В
В системе с небуферизованным вводом отображение на экране символа В произойдет сразу, как только вы нажмете соответствующую клавишу. Результат ввода-вывода при этом может выглядеть, например, так:
ВВот длинная входная строка
РИС. 6.2. Схема буферизованного и небуферизованного ввода
Зачем нужны буферы? Во-первых, оказывается, что передачу нескольких символов в виде одного блока можно осуществить гораздо быстрее, чем передавать их последовательно по одному. Во-вторых, если при вводе символов допущена ошибка, вы можете воспользоваться корректирующими средствами терминала, чтобы ее исправить. И когда в конце концов вы нажмете клавишу [ввод], будет произведена передача откорректированной строки.
Однако для некоторых диалоговых программ небуферизованный ввод может оказаться приемлемым. Например, в программах обработки текстов было бы желательно, чтобы каждая команда вводилась, как только вы нажимаете соответствующую клавишу. Поэтому как буферизованный, так и небуферизированный ввод имеет свои достоинства.
Читайте также
Буферы и заголовки буферов
Буферы и заголовки буферов Когда блок хранится в памяти (скажем, после считывания или в ожидании записи), то он хранится в структуре данных, называемой буфером (buffer). Каждый буфер связан строго с одним блоком. Буфер играет роль объекта, который представляет блок в
1.6 Драйверы и буферы ввода-вывода
1.6 Драйверы и буферы ввода-вывода В этом разделе рассматриваются буферы ввода-вывода, которые уже упоминались ранее в главе. Драйверы используют буферы для осуществления ввода-вывода и управления им (IOCTL). Для этого драйверы посредством соответствующего объекта
Немного неудобно, но хочу поговорить о буферах
Просто статья о буферах. Вы наверняка думаете, что знаете о буферах всё. Возможно, так оно и есть. Но мне кажется, вы всё равно найдёте для себя что-то новое. Просто потому, что тема – неисчерпаемая. О буферах всегда есть что сказать.
Это не чушь, и не шутка. Статья действительно о буферах. И она не про буфер обмена. Речь пойдёт о буферах, которые помогают работать лучше.
Не знаю, кто первый придумал использовать буферы в организации работы, но прям использовал это слово и описал, как принцип и кейс – Голдратт в Теории Ограничений.
Еще в первой книге («Цель»), которая написана в жанре бизнес-романа (т.е. это худлит) герои, познав ТОС и влияние буферов, приходят к выводу, что они «ничего такого не делали» — просто работали в соответствии со здравым смыслом. Точнее, прекратили работать как попало, и включили здравый смысл.
Идея использования ограничения и буфера, его защищающего, когда она понята и использована на практике, ничем иным, кроме здравого смысла, уже не кажется.
На самом деле, все мы используем буферы, постоянно. Но делаем это неосознанно. Что интересно – в личной жизни мы пользуемся буферами чаще, чем в работе. Надеюсь, после прочтения статьи вы попробуете перестроить свою деятельность, зная больше о буферах.
Для начала кратко расскажу о трёх видах буферов, которые предлагал сам Голдратт.
Буфер в производстве
Это вообще классика. Представьте, что у вас производство – станки, которые последовательно обрабатывают деталь, пока она не станет готовой продукцией. Один из станков в цепочке является ограничением – бутылочным горлышком, звеном цепи с самой низкой производительностью. Производительность всей линии определяется производительностью этого ограничения.
На самом деле, производительность линии обычно ниже, чем может фигачить ограничение. Потому что ограничение не защищено, и не работает на своей максимальной мощности, по одной простой причине – ограничением управляют так же, как всеми остальными станками. И проблемы у него те же – например, простои по вине предыдущих этапов цепи.
Решение предлагается простое, как дрова – создать перед ограничением буфер. Перестроить линию так, чтобы ограничению всегда было, чем заняться, и оно не простаивало.
У этого буфера будет забавный способ измерения, но его важно понять. Потому что их два – количество и время. С одной стороны, это может быть сто заготовок. С другой стороны, сто заготовок – это четыре часа работы станка-ограничения.
Время – более универсальная характеристика, т.к. она понятна без знания производительности. Можно просто, без изысков и с полным здравым смыслом сказать: ограничение защищено на четыре часа. Или – у него буфер времени в четыре часа.
Что бы там ни случилось до ограничения, есть четыре часа на исправление – и за это время производительность линии не снизится.
Буфер в снабжении
Примерно то же самое, только ещё проще. Вообще, буферы в снабжении были любимой темой Голдратта в собственной практике, он внедрял их в рознице. Говорил, что там минимум усилий и максимум результата. А его компания брала процент от увеличения выручки после внедрения ТОС.
Так вот, буфер в снабжении – это держать на складе столько единиц товара, чтобы хватило до следующей поставки. Логично до противного.
И чувствуете – сразу в формулировке буфера заложено две единицы измерения? И количество единиц, и время – до следующей поставки. Хочешь уменьшить буфер – увеличивай частоту поставки. Ну и привози ровно столько, чтобы свой буфер пополнить.
Буфер в данном случае тупо защищает от дефицита – отсутствия товара в тот момент, когда он необходим – неважно кому, собственному цеху завода или очередному покупателю пива.
Буфер в проектах
В проектах Голдратт ставит простую цель – уложиться в срок без снижения качества и увеличения стоимости. Прям как в рекламном буклете.
Что защищать в проекте? Недолго думая, Голдратт предлагает защищать критический путь – цепочку этапов или задач, которая определяет конечный срок выполнения проекта. Если учились в ВУЗе достаточно давно, то помните – нас всех заставляли этот критический путь рассчитывать.
Голдратт чуть расширил понятие критического пути, назвав его (а заодно и книгу) критической цепью. Углубляться в детали не буду, если захотите – почитаете, но цепь отличается от пути динамическим перестроением, т.е. ключевая последовательность этапов может меняться в ходе выполнения проекта.
Где тут воткнуть буфер? Примерно этим вопросом задавались герои книги – они вроде уже знали ТОС, но не понимали, как его применить в проектах. Потом догадались – буфер уже сидит во всех оценках времени исполнения этапов и задач. Каждый программист, аналитик, менеджер, оценивая свои этапы, заложил туда буфер.
Если память не изменяет, Голдратт утверждал, что все, как один, заложили буфер размером процентов в 90%. Но никто не хотел в этом признаваться, потому что оценки выполнения проектов не поддаются регламентации, и делаются «по опыту», который у всех обычно трудный.
На реальное выполнение каждого этапа проекта нужно примерно 10% времени, которое на него заложено. Это время, когда прям что-то делается, а не планируется или анализируется. А дальше просто – никто же толком не умеет укладываться в сроки и планировать свою работу. Имея запас времени, десятикратно превосходящий трудозатраты, всё равно все опаздывают, потому что начинают не вовремя (в книге это названо «синдром студента»).
Ну Голдратт и говорит – парни, хорош. Давайте мы все ваши буферы вытащим из оценок, суммируем и поместим в конец проекта. Никаких локальных буферов, только один общий – на весь проект. Точнее, на его критическую цепь.
Прям все буферы ему, конечно, не отдали, но в 2-3 раза свои оценки урезали. Заодно и срок проекта в 2-3 раза сократился, потому что в общий буфер пошла не вся сумма, а её разумная и объяснимая часть – начальство не согласилось на очень уж большой запас времени.
Всем парням сказали – не ориентируйтесь на сроки, просто делайте. Как можно скорее, но без увеличения стоимости или снижения качества. По сути, сказал ориентироваться не на плановую дату завершения, а на дату начала. Ну и всё заколосилось.
В критической цепи буфер защищает срок выполнения проекта.
От чего защищает буфер?
Если обобщить, то – от необходимости срочно вмешиваться и что-то мудрить. Голдратт это называл «внимание руководства», и рисовал график, который говорил – если буфер времени слишком короткий или слишком длинный, то внимания потребуется много.
А что есть внимание руководства? Зависит от ситуации, но этим руководством вполне можете быть вы. Например, если будете покупать продукты на приготовление только одного обеда – вам придётся бегать в магазин трижды в день. А если накупите на год вперёд, то намучаетесь с хранением и инвентаризацией сроков годности. В обоих случаях такой простой процесс, как продукты, будет занимать намного больше вашего времени, чем хотелось бы.
На работе типичный пример – ручное управление задачами. Это когда есть начальник, который целыми днями только и делает, что раздаёт поручения, контролирует их исполнение, запрашивает информацию и т.д. Если все его задачи срочные и важные, со сроком исполнения 1 час, то он будет буквально стоять над душой. Если сроки измеряются в месяцах или годах, то всё время уйдёт на освежение памяти подчиненных – кто всю эту чушь долгоиграющую запомнит?
Посмотрим на более приземленные примеры буферов.
Буфер недельных закупок
Простой пример из жизни – закупки на неделю вперед. Наверное, большинство из нас пользуется таким буфером. Опять же, заметьте – тут и количество, и время. Мы покупаем ровно столько еды, сколько нам надо на неделю.
Если купим меньше, то придётся часто бегать в магазин – потратим время и деньги, т.к. в магазине около дома цены несколько выше. Если купим больше, то половину выбросим, или придётся купить второй холодильник.
Буфер недельных закупок защищает нас от геморроя. Можно всю неделю жить, не переживая о питании, а внимание к этому процессу требуется на понятный отрезок времени в один из выходных дней.
Буфер – техподдержка
Вам это может показаться диким, но техподдержка, да еще и разделенная на несколько линий, существует далеко не везде. В России полно компаний, где несчастные программисты занимаются всем подряд – и разработкой, и тестированием, и архитектурой, и при этом висят полдня на телефоне, а то и бегают с задним местом в мыле.
Я раньше работал на заводах и, пока штат ИТ был маленький, проблему отсутствия буфера особо не ощущал. Ну, мешают мне звонки и сообщения в скайпе – я просто не брал трубку и не отвечал. Кому сильно надо – прибежит. И услышит, что я занят.
А когда штат вырос, продолжал действовать по инерции, никак не деля роли в команде. В результате рваная, непонятная, непредсказуемая нагрузка была у всех без исключения. Тут только допёрло, что буфер нужен – отдельный человек, который занимается только поддержкой. И всё, геморрой как ветром сдуло. А заодно – и требование к моему вниманию, чтобы постоянно разруливать срочные задачи, перемешанные с нормальной разработкой.
Человек на техподдержке стал буфером, защищающим развитие ИТ-систем.
Буфер – поменьше говорить
Для меня это прям актуально, т.к. слишком много говорю. В голове постоянно рождаются какие-то идеи, и я, по тупости, раньше их сразу высказывал вслух или письменно. Руководству идеи нравились, и они, как положено начальству, сразу требовали внести их в какой-нибудь план и реализовывать. Мне самому, разумеется.
А я идею сказал и забыл. Через час – передумал. Через два придумал другую идею, противоположную первой. Ну или развивающую первую. В общем, ничего я реализовывать не хочу.
Но начальство настаивает, потому что я «базаром писанулся». В результате таких ошибок я несколько раз попадал на реализацию проектов, которые сам считал бессмысленными. Ну и выработал простое правило – молчать.
Молчание стало буфером, защищающим меня от самого себя. Если обсуждается проблема не моя, а чья-нибудь, или какая-то общая, то можно высказывать всё, что угодно. Если же речь о работе моей или моего подразделения, то говорить можно и нужно лишь о том, что уже сделано, или находится в процессе реализации.
Хочешь что-то изменить – измени. Но не надо никому об этом рассказывать, пока не сделал. Такой примерно буфер. Защищает прям сильно.
Буфер коммуникаций
С одной стороны, электронные способы коммуникации, вроде, призваны ускорить процесс. Поднял трубку, набрал номер, и можешь тут же поговорить с человеком на другом краю Земли. Или написал сообщение, и тут же получил ответ.
Но сейчас тренд другой – пешком быстрее. Электронные коммуникации, особенно почта, стали реальным таким буфером, ограждающим от слишком назойливых любителей получить ответ сию минуту (привет, менеджеры). Трубку можно не брать, на письмо не отвечать, только гадкие мессенджеры рисуют свои две галочки.
Мне нравятся эти буферы. Они позволяют не тратить моё «внимание руководства», которого и так мало. А кому сильно надо – всё равно найдёт, как связаться.
Бюрократический буфер
Это прям классика из классик. Особенно, если речь про чиновников. Все регламенты работы, написанные бюрократами – это буферы, смягчающие удары и, собственно, от них защищающие.
В каждом приличном регламенте есть вход, какие-то действия, ответственные за их выполнение и, главное, срок исполнения. То самое время, в котором и измеряется буфер. Благодаря этому буферу можно, и нужно не подпрыгивать на каждое обращение, а чинно, спокойно, по всей форме ответить на обращение. Если ответ не устроит – будет второй буфер на второй ответ. И так далее, до бесконечности.
Бюрократические буферы создаются системами для самозащиты. От кого? От нас или от вас, смотря с какой стороны вы находитесь.
Буфер ценностей
Одна из разновидностей бюрократии, обычно скрывающаяся под соусом ценностей, моральных принципов, корпоративной культуры и любви к клиентам. Чаще всего встречается у туповатых менеджеров.
Проявляется обычно в ситуациях, которые выходят за рамки типовых, знакомых, отработанных. В таких случаях, увы, надо думать, искать необычное решение, иногда творческое, работать с конфликтами. Это сложнее, чем выставлять счета на оплату или согласовывать служебки.
Поэтому человек не делает то, чего требует ситуация, но надо же как-то объяснить свою позицию. На помощь и приходят фразы из буфера, который есть в большинстве более или менее крупных компаний.
Например, прикрывается модной клиентоориентированностью, когда клиент сел на шею и хочет услуг на миллион, заплатив тысячу. Менеджер обычно процент с продаж получает, и по соотношению усилия-результат тысяча намного лучше миллиона. Тем более, что процент заплатят только после подписания акта. Наверняка, в этой ситуации менеджер и синицу в руках упомянет.
Любят буфер ценностей и высшие менеджеры. Например, про лояльность компании. Особенно, когда надо поработать в выходные, или зарплату уменьшить, ибо кризис, а на чём же ещё экономить, если не на зарплате сотрудников.
Правда, в кризис не упоминается буфер, который те же высшие менеджеры создать забыли – например, для выплаты зарплаты, портфель проектов или, на крайний случай, несколько постоянных лояльных клиентов.
Но это уже немного другая история – буферы, про которые мы не думали. Хотя, последние месяцы наглядно показали, кто думал о защите, а кто – об удобных ценностях.
Буфер ценностей защищает тех, кто не готов действовать по обстановке. Как говорил неизвестный источник в книге Детмера, «Средних менеджеров волнует «делалось ли так раньше» и «что подумают люди». Для хороших важно, чтобы проблема была решена».
Теперь, поняв принцип, хочу почитать ваши варианты буферов. Если они будут про программистов или их менеджеров – прям вообще хорошо будет. Заранее спасибо.








