Заметки пишутся для усвоения и запоминания. Запоминание держится на связях: изолированный факт стирается, факт, встроенный в причинную структуру, остаётся. Читатель строит ментальную модель предложение за предложением, и каждое предложение либо продвигает модель, либо тратит внимание впустую — а потраченное впустую внимание не ноль, а минус.
Этот файл — не шаблон и не чек-лист. Он фиксирует шесть вопросов, которые методист держит в голове перед любым обучающим текстом, и рабочий цикл, внутри которого эти вопросы задаются. Каждая глава отвечает на один вопрос: называет методическую рамку и показывает, как она приземляется на техническую заметку.
- §1 Результат — куда ведёшь читателя?
- §2 Читатель — откуда он начинает?
- §3 Дуга — зачем идти и по какому пути?
- §4 Нагрузка — на какой глубине держаться?
- §5 Серия — как заметка живёт среди соседей?
- §6 Проверка — как увидеть текст глазами читателя?
Готовая заметка не должна выглядеть так, будто этот файл существовал. Если читатель чувствует структуру инструкции сквозь текст — инструкция протекла.
Правила адресованы объясняющим заметкам: тем, что вводят концепцию, раскрывают механизм или продолжают линию изучения. Обзорные и справочные материалы могут отступать от норм §3 и §4, если сохраняют контракт предпосылок (§2), причинную корректность и чистый язык (§0.3).
Документ общий: он ничего не знает о конкретном репозитории и не ссылается на него. Имена и пути файлов, формат объявления предпосылок, навигация, ссылки, callouts, таблицы — зона гайда-адаптера репозитория. Зависимость односторонняя: адаптер опирается на этот файл, этот файл на адаптер не ссылается.
Текст, написанный «сразу», наследует чужой порядок — порядок официальной документации или порядок припоминания автора. Решения остальных глав в таком тексте принимаются задним числом: дуга не ведёт письмо, а подыскивается под уже написанное и превращается в рационализацию. Поэтому цикл — обязательная часть правил, а не пожелание.
Шаг 0 — контекст. Прочитать одну-две соседние заметки той же серии или слоя, как минимум предыдущую. Это решает две задачи: перенос стиля корпуса — целые тексты задают форму сильнее любого списка правил — и вариативность (§5): приёмы соседей в новой заметке не повторяются.
Шаг 1 — план. Приватный рабочий артефакт; в готовый материал из него не попадает ничего — ни пункты, ни структура, ни формулировки. План отвечает на восемь вопросов:
- Сдвиг-результат одним предложением (§1). Не помещается в одно — это две заметки.
- Целевой читатель (§1).
- Инвентарь схем: что объявляется предпосылкой, какие термины вводит сама заметка (§2).
- Наивная модель, с которой придёт читатель, и источник разрыва (§2, §3).
- Тип сценария и сквозная ситуация (§3).
- Дуга: цепочка «ситуация → вопрос → ответ → новый вопрос» без технических деталей (§3).
- Карта деталей: каждая команда, структура и число привязаны к конкретному шагу дуги; деталь без шага — кандидат на удаление или вынос (§3, §4).
- Место в серии: каким приёмом входили соседние заметки, какие схемы из предыдущих будут работать здесь в новой роли (§5).
Валидация плана до письма: дуга без технических деталей читается как связная история; вход начинается с ситуации, а не с термина; порядок шагов не совпадает с порядком документации.
Парадокс шаблона. План обязан быть шаблонным: одни и те же восемь вопросов для каждой заметки. Текст из плана выводится, но его не повторяет — секции диктуются темой, а не пунктами плана. Шаблон живёт в плане и умирает вместе с ним.
Шаг 2 — текст. Письмо по дуге из плана.
Шаг 3 — финальный проход (§6). Обязателен: заметка без него не готова. Длинная инструкция при длинной работе частично выпадает из внимания; короткий проход по ядру в конце страхует инварианты.
Правила не равны по весу. Когда два требования тянут в разные стороны, работает уровень:
- Инварианты. Нарушение = текст не обучает. Контракт предпосылок (§2), чистый язык (§0.3), причинно-следственная корректность.
- Дуга. Нарушение = текст читается, но не ведёт. Мотивация и сценарий перед механикой, детали по потребности сценария, мостики (§3); на уровне серии — вариативность приёмов и снятие лесов (§5).
- Полнота. Нарушение = текст понятен, но неполон. Жизненный цикл сущности, «как работает» и «почему», три стороны эффекта (§1), этимология непрозрачных имён (§2), межзаметочный возврат схем (§5).
- Форма. Нарушение = текст удобнее или неудобнее. Проза против списков, длина кодовых блоков, таблицы, диаграммы (§4).
Пример конфликта. Этимология при первом вводе термина (уровень 3) требует дополнительного предложения в первом абзаце — но ограничение «не больше 1–2 новых сущностей во входе» (уровень 2) сдерживает нагрузку. Решение: этимология уходит во второй абзац или даётся inline в скобках. Второй уровень важнее третьего.
Готовый текст говорит о предмете — не о себе, не о процессе своего написания и не о плане, по которому его писали. Четыре вида протечки, заметные при внимательном чтении.
Метатермины инструкции. «Нарратив», «мостик», «дуга», «леса», «послойное раскрытие», «слой абстракции» (в смысле организации заметок), «наивная модель» (в значении модели читателя), «конечный эффект» (как концепция инструкции) — нужны автору для проектирования; для читателя, изучающего предмет, они мусор. Предметные омонимы остаются: «уровень абстракции» в техническом смысле (абстрактный/конкретный слой системы), «эффект» как наблюдаемый результат механизма, «слой» в TCP/IP stack, «наивная реализация» алгоритма.
Самореферентные обороты. «В этой части мы разобрали», «перейдём к следующему куску пазла», «выше мы дали определение» — переключают внимание с темы на документ. Заменяй предметной причинностью: «выше видели, как X замедляет Y», «когда X перестаёт работать, нужен Z».
Промпт, переписка, план. Инструменты подготовки, не следы в тексте. Никаких «как вы просили», «в этой сессии»; ни один пункт плана не цитируется в тексте. Если фраза не появилась бы без текущего разговора или без плана — это протечка.
Структура, повторяющая инструкцию. Секции «Мотивация», «Сценарий», «Эффект» — главы этого файла, а не темы заметки. Заголовки отражают предметное содержание, не тип задачи и не роль раздела: не «Business Description», а «Платформа управления заказами».
Тест для пограничного случая: сказуемое описывает предмет темы или сам документ? «Регистры, кеши и RAM объединяет одно — volatile» — о предмете, ок. «Здесь мы прошли по цепочке компромиссов» — о документе, нарушение.
Первый вопрос автора — не «с чего начать», а «чем заканчивается». Сначала формулируется сдвиг, который должен произойти в голове читателя. Из этого сдвига выводится всё остальное — границы темы, сценарий, глубина, форма. Без такого ответа тема распадается на бесконечное количество деталей, и нет способа решить, какие из них двигают читателя, а какие — шум.
Методисты называют этот подход backward design (Wiggins & McTighe): обучение проектируется от результата, а не от материала. Формулируется просто, применяется плохо — автор инстинктивно начинает с темы («нужно написать про B-tree»), а не со сдвига («читатель должен понять, почему БД выбирает B-tree, а не хеш-таблицу, для индекса по диапазону»).
Сравни две формулировки одной и той же заметки:
❌ «Эта заметка о B-tree.» ✅ «После заметки читатель понимает, почему реляционная БД выбирает B-tree, а не хеш-таблицу, когда нужен индекс по диапазону.»
Вторая формулировка сразу даёт четыре решения, которые у первой зависают в воздухе: границы (хеш-таблица появится для контраста, байтовый layout узла — нет), сценарий (поиск по диапазону), наивную модель, которую придётся ломать («хеш быстрее, возьмём его»), и критерий готовности (читатель сможет ответить на этот конкретный вопрос).
Формулировка сдвига заодно даёт критерий деления материала. Если сдвиг не помещается в одно предложение и получается перечисление — «читатель понимает X, а также умеет Y» — это два результата, и им нужны две заметки: у каждой свой вход, своя дуга, свой эффект. Критерий работает и в обратную сторону: два кандидата в заметки с одним и тем же сдвигом — одна заметка. Механика разбиения существующего материала — зона адаптера.
Результат задаёт направление (куда ведут читателя). Мотивация даёт силу идти (зачем туда идти). Знать, куда ведут, — ещё не значит хотеть туда идти. Сформулированный результат сам по себе интерес не создаёт, и легко впасть в ошибку «я поставил цель → читатель включится». Мотивация — отдельный рычаг, она строится в §3: через разрыв в модели читателя, через незакрытый вопрос, через наблюдаемую странность, на которую нужен ответ.
У хорошего результата три стороны. Они не проговариваются явно в каждом абзаце, но должны быть очевидны, когда читатель закрывает заметку.
Что закроется в голове читателя — конкретный вопрос, не «я знаю термин X».
❌ «Теперь читатель знает, что такое индекс.» ✅ «Теперь понятно, как база находит строку за логарифмическое время вместо полного сканирования.»
Что это означает в наблюдаемом поведении системы — явление, а не тавтология.
❌ «STW-пауза проявляется как подвисание.» (подвисание и есть пауза) ✅ «STW проявляется как пики задержек: интерфейс замирает на время GC.» ✅ «Фрагментация: память процесса не уменьшается после удаления объектов, потому что страницу нельзя вернуть ОС, пока на ней есть хоть один живой объект.»
Когда концепция становится правильным инструментом — конкретный момент в сценарии, не абстрактное сравнение.
❌ «Новый механизм лучше, потому что поддерживает подтверждение.» ✅ «Простая очередь работает, пока допустима потеря сообщений. Когда появляется требование «ни один заказ не теряется» — простая очередь перестаёт подходить.»
Сдвиг задаёт не только внешние границы, но и обязательный минимум внутри них — три нормы, без которых модель остаётся с дырами.
Жизненный цикл. Для каждой ключевой сущности заметки читатель в итоге знает, откуда она берётся, как используется и когда исчезает. Части цикла могут быть разнесены по тексту, но пробелов нет. Заметка, которая вводит блокировку и не говорит, когда та снимается, оставляет дыру — и дыра обнаружится, когда читатель попробует рассуждать о дедлоке.
«Как работает», не только «что». Если введён процесс или алгоритм, после определения идёт прогон: мини-пример, пошаговый walkthrough или компактный псевдокод. Определение без прогона даёт слова вместо модели.
«Почему», не только «что». У механизма называется причина существования. Факт без причины запоминается как догма и стирается первым.
❌ «PostgreSQL хранит старые версии строк.» ✅ «PostgreSQL хранит старые версии строк, потому что читающая транзакция могла начаться до обновления — версию можно удалить, только когда ни один активный снимок её больше не увидит.»
Одна концепция — абзац в одной заметке, целый файл в другой. Глубина определяется ролью концепции в текущем документе, а не её полнотой как темы.
LSM-tree в заметке «Профили нагрузки на хранилище» — инструмент выбора: «оптимизирован для записи (sequential I/O), цена — медленнее чтение и write amplification 10–30×». Ни memtable, ни compaction там не появляются: они не двигают результат этой заметки. В отдельной заметке «LSM-tree» та же концепция — предмет изучения: memtable, SSTable, compaction, уровни, Bloom-фильтры.
Тест: убери внутреннее устройство, оставь «что делает + цена». Потеряет ли текст смысл для своего результата? Если нет — детали ниже пола заметки, их место в другом документе.
Результат зависит не только от темы, но и от того, кому текст адресован. Новичок в теме и эксперт из соседней области получают разные заметки из одной концепции. Автор фиксирует целевого читателя в плане прежде, чем начнёт выводить границы; в сам текст целевой читатель не попадает (никаких «эта заметка для…») — он живёт как фильтр, через который проходят все последующие решения.
Когда результат сформулирован, следующий вопрос — где находится читатель. Обучающий текст не просто сообщает информацию — он прикрепляет новое к тому, что уже есть у читателя в голове. Если прикрепить не к чему, новое не удержится: останется набором слов, которые завтра стираются.
Методисты называют эти внутренние опоры схемами (schema theory, Anderson & Rumelhart): организованные ментальные структуры, к которым крепится новое знание. Знать читателя = знать его инвентарь схем. Автор решает не «что сказать», а «к каким уже существующим структурам прицепить».
Контракт знания двухуровневый, и нижний уровень фиксируется один раз для всего корпуса. Нулевой уровень — то, что любая заметка считает данным без объявления: связный текст, бытовая причинность, школьная арифметика, тривиальная нотация — «шаг 1 → шаг 2», присваивание, сравнение, простое ветвление в псевдокоде. Нулевой уровень не включает предметные формы: SQL, shell-команды, указатели, структуры с полями, concurrency-примитивы, регулярные выражения, любой DSL. Всё это — либо объявленная предпосылка, либо вводится самим текстом.
Граница проведена жёстко, потому что именно здесь автор чаще всего ошибается «в свою пользу»: то, что он пишет ежедневно, кажется ему частью общей грамотности. Однострочный SELECT для автора — арифметика; для читателя без SQL — иероглиф.
Привычный взгляд на предпосылки: формальный контракт, список материалов для прочтения. Это узкий взгляд. Более точный: предпосылки перечисляют схемы, к которым прицепится новое. Пункт списка — не «обязательная литература», а обещание: «когда я скажу MVCC, ты вспомнишь snapshot; когда скажу B-tree — увидишь отсортированное дерево с указателями».
Меняется и практика выбора. Решая, что объявить предпосылкой, автор проверяет не «нужен ли этот материал для полноты темы», а «на какую схему я буду опираться, и есть ли она у читателя».
Контракт жёсткий: всё техническое, что не объявлено предпосылкой, текст обязан ввести сам. Термин появляется только если (1) уже объяснён выше, (2) объясняется прямо сейчас, (3) объявлен в предпосылках. Правило работает для любого появления термина, не только ключевого. Одноразовое упоминание непонятного термина хуже его отсутствия: оно создаёт вопрос, на который текст не отвечает.
Контракт описывает знание, а не наличие материалов: предпосылкой может быть тема, заметки для которой ещё не существует. Объявить её всё равно обязательно — ненаписанность соседнего материала не делает знание «очевидным» и не разрешает использовать термин без опоры.
Побочные упоминания — мягкое исключение. Если концепция упомянута для контекста (побочный эффект, предупреждение о последствии), но рассуждение на ней не строится, достаточно inline-расшифровки и ссылки. В предпосылки попадает только то, без чего читатель не усвоит основной материал.
Читатель никогда не приходит к теме пустым. У него уже есть представление — часто неявное, часто неточное. Conceptual change (Posner & Strike) говорит: пока эта наивная модель не названа и не показана как несостоятельная, новая не приживается. Они начинают сосуществовать, и в голове чаще остаётся старая — она привычнее.
Для автора практическое следствие: до введения нового механизма нужно увидеть модель, с которой читатель придёт. «Кажется, что данные просто лежат в памяти — но почему тогда одни обращения в 100 раз быстрее других?» Наивная модель («данные просто лежат») тут названа и сразу показана как неполная. После этого читатель готов принять иерархию памяти как исправление, а не как «ещё один факт на полке».
Источники разрыва, из которых рождается мотивация, разбираются в §3 — здесь важно, что работа с наивной моделью начинается на этапе плана: автор выясняет, что читатель принесёт с собой, даже если вход заметки в итоге построится на другом источнике.
Особый случай conceptual change — концепции, которые не просто корректируют модель, а переформатируют весь домен. Meyer и Land называют их threshold concepts: пока не перейти через порог, ничто дальше не собирается в картину; перешёл — весь домен перестраивается.
В CS это MVCC, указатели и уровни косвенности, когерентность кешей, монады, замыкания, single-threaded event loop. Признак: тема «не понимается» не по частям, а сразу или никак. Обычное объяснение в лоб не работает — читатель проходит по словам, но модель не собирается.
Такие темы требуют другой дуги. Её нельзя подать списком фактов. Дуга строится вокруг самого перехода: создать ситуацию, в которой старая модель перестаёт работать; провести через момент, когда новая становится неизбежной; показать, как знакомые вещи начинают выглядеть по-другому после перехода.
Распознать threshold-концепцию — отдельная работа. Признак: автор сам не может объяснить тему «в двух словах без подготовки». Если короткое объяснение даёт только правильные слова, но не передаёт понимания — это порог, и заметка должна проводить через него, а не описывать со стороны.
Основной источник ошибок автора — curse of knowledge: то, что автор понимает, кажется ему очевидным, и он неосознанно пропускает шаги, без которых читатель застревает. Полностью устранить нельзя — можно заметить и компенсировать.
Первый частый симптом — декоративная точность: технически корректный, но непонятный читателю термин вставлен ради «глубины». «GIN строит B-tree по элементам» — если B-tree не объяснён и не в предпосылках. «DRAM хранит данные в конденсаторах ёмкостью ~30 фФ» — 30 фФ не помогает понять, почему DRAM медленнее кеша. Тест: убери термин или число. Если предложение не теряет смысл для читателя — оно лишнее.
Второй — имена без опоры. Непрозрачные термины (LATERAL, WAL, Heartbeat) и кодовые имена из реализации (task_struct, vm_area_struct) брошены как данность. Каждому при первом вводе нужна опора. Для концепта — короткая этимология или functional gloss: «LATERAL — «смотрящий вбок»: подзапрос обращается к текущей строке внешней таблицы»; «WAL = write-ahead log: журнал, который пишется заранее, до изменённых страниц». Выбирай не самый буквальный перевод, а самый полезный для запоминания. Для кодового имени — привязка «что + где + зачем»: «task_struct — дескриптор процесса; лежит в списке задач ядра; нужен, чтобы понять, как планировщик выбирает следующий процесс».
К опоре примыкает нормализация имён. Если термин текста расходится с термином кода или официальной документации, соответствие фиксируется при первом появлении: «в тексте — журнал упреждающей записи, в документации — WAL». Омонимы разводятся явно в момент столкновения: «страница» в разговоре о буферном кеше — страница данных, не страница виртуальной памяти ОС; если в заметке работают обе, каждое употребление однозначно.
Третий симптом, и самый глубокий, — пропущенные шаги. Автор переходит от A к C, потому что для него B очевиден. Читатель видит разрыв. Ловится только симуляцией наивного читателя; этому посвящена §6.
Предпосылки почти всегда смотрят в тот же слой знания или вниз — к более фундаментальным темам. Если заметка не может быть понята без знания более высокого слоя, в ней скрытая предпосылка.
Ссылки вверх допустимы как мотивация («false sharing позже проявится в многопоточном коде») или контекст («потеря сообщения — частный случай проблемы гарантий доставки»), но обязательной базы не создают. Тест: удали ссылку вверх — сохраняется ли понимание? Если нет — это скрытая предпосылка: либо объясни на месте, либо объяви предпосылкой, либо поменяй дугу, чтобы она не требовала верхнего слоя.
У автора есть направление (§1) и карта читательского багажа (§2). Теперь нужно провести читателя из состояния «ещё не знаю» в состояние «уже понимаю». Это путь — дуга. Главное свойство пути: каждый следующий шаг создаётся предыдущим. Не порядок тем документации, не алфавит, не произвольная группировка — причинная связность, в которой конец предыдущего абзаца создаёт потребность в следующем. Методисты называют это narrative coherence: когда оно работает, читатель не удерживает в голове план заметки — его ведёт сам вопрос.
Мотивация не украшает вход и не говорит «это важно». Это разрыв между тем, что читатель знает, и тем, что он чувствует, что мог бы знать (information gap theory, Loewenstein). Разрыв должен быть ощутимым, но переходимым: слишком маленький — скучно, слишком большой — страх. Обучающий текст работает в этой узкой полосе.
Четыре источника рабочего разрыва:
- Ломающаяся наивная модель. Простое объяснение читателя перестаёт работать. «Кажется, что данные просто лежат в памяти, но почему тогда одни обращения в 100 раз быстрее других?»
- Недостающее звено. Читатель знает действие, но не видит, кто его обеспечивает. «Программа запускается, и что-то превращает её команды в шаги вычисления — но эта часть машины ещё не названа».
- Наблюдаемая странность. Эффект, который без новой темы выглядит магией. «Два потока пишут в разные переменные — почему программа замедляется вдвое?»
- Мост вверх по слоям. Без текущей темы позже останется слепая зона. «Без когерентности кеша трудно понять false sharing».
Источник выбирается по природе темы, а не по «силе» приёма. Ломающаяся модель требует, чтобы наивная модель у читателя действительно была — а её нет, когда тема целиком новая: нечего ломать у того, кто впервые слышит о брокере сообщений. Недостающее звено — естественный вход фундаментальных тем, где читатель видит работу, но не исполнителя. Странность — когда есть наблюдаемый эффект против ожиданий. Мост вверх — когда тема сама вопросов не вызывает, но без неё не соберётся следующая. Выбор фиксируется в плане, и в серии соседние заметки не открываются одним источником подряд (§5).
Антипаттерны мотивации: «это важно» без разрыва; сравнение «X быстрее Y», когда ни X, ни Y ещё не встроены в картину; искусственная загадка без опоры на предпосылки; далёкое обещание вместо локального вопроса.
Мотивация создаёт движение, вход предъявляет первый объект. Опасная ошибка здесь — начать с имени термина, прежде чем читатель увидел, в какой ситуации он нужен.
❌ «Хеш-таблица хранит пары ключ-значение…» — если читатель ещё не понял, зачем нужен быстрый поиск по ключу. ✅ «Когда элементов тысячи, перебирать массив на каждый поиск слишком дорого. Нужна структура, которая находит элемент за одну-две операции вместо тысячи. Такая структура называется хеш-таблицей.»
Порядок: наблюдаемая ситуация → недостающая роль или работа → название сущности → внутреннее устройство. Это применение concreteness fading (Bruner): сначала конкретное, потом имя, потом абстрактное устройство. Правило обязательно для фундаментальных тем и для первых заметок серий; внутри серии оно смягчается (как именно — §5). Ограничение первого абзаца: не больше 1–2 новых сущностей, никаких сравнений производительности до того, как объект стал видимым.
Для заметок внутри последовательности первые абзацы показывают ситуацию, где решение предыдущей заметки становится недостаточным.
❌ Объявленные предпосылки — и сразу определение нового механизма, без моста из предыдущей заметки. ✅ «Простая очередь работает, пока обработчик стабилен. Но после извлечения элемент исчезает — если обработчик упал, сообщение потеряно. Для потока платежей это недопустимо.» → механизм подтверждений.
Если заметка открывает новую ветку, нарративный вход из предыдущей не нужен: вместо него самодостаточный нулевой вход, где общая сцена из предпосылок и недостающая часть картины отвечают на вопрос «какую работу выполняет новая сущность».
Заметка — не описание возможностей, а история о том, как конкретная ситуация создаёт потребность в новой сущности. Сценарий — форма, в которой эта потребность предъявляется. Он не обязан быть бизнес-кейсом с QPS и деградацией: для низкоуровневых тем сценарий чаще строится вокруг базовой работы системы. Числа уместны там, где действительно создают следующую проблему.
Три типа по природе темы:
- Сценарий роли — для фундаментальных тем. Какая работа должна быть выполнена? «Программа не выполняется сама → нужна часть компьютера для вычислений → процессор».
- Сценарий ограничения — для механизмов и trade-offs. Где известное решение перестаёт работать? «Один сервер держит 2000 QPS, но в пике приходит 10000 → нужно распределить нагрузку».
- Сценарий применения — для технологических и прикладных заметок. Какая задача заставляет выбрать инструмент? «Нужно подсчитать уникальных посетителей за месяц при 50M событий/день — точный подсчёт требует гигабайты памяти → нужна вероятностная структура → HyperLogLog».
Тест: убери все технические детали и оставь только сценарий. Остаётся ли связная история с вопросом, ограничением и ответом? Если остаётся только список тем — сценарий декоративный, он не несёт дугу. Основной сценарий проходит сквозь всю заметку, хотя отдельные секции могут использовать мини-примеры: главное — сквозная ситуация, к которой текст возвращается.
После мотивации, входа и сценария нужна сквозная стратегия, на которую вешаются факты. Типичные нити: цель → проблема → решение → результат; цепочка компромиссов (боль → оптимизация → новый компромисс); жизненный цикл сущности (создание → жизнь → завершение); путь запроса или данных; слои системы (API → модель → структура → алгоритм). Нити комбинируются. Факт, который не привязывается к выбранной нити, стоит не там или не нужен в основном тексте.
Мостики между разделами отвечают на вопрос «зачем мы сейчас туда идём» внутри темы. Заголовок мостом не считается: он помогает ориентироваться, но не объясняет причинность.
❌ «Дальше пройдём по структуре разделов…» ✅ «Задержку мы уменьшили — но что это стоило по пропускной способности?»
Частый источник «внезапности» — решение без симптома: оптимизация появляется, а читатель не видел, какая операция делает её необходимой.
❌ «Система поддерживает кеширование, шардирование и репликацию…» ✅ «Один сервер перестаёт справляться с 10000 QPS → нужно распределить нагрузку…»
Детали подчинены сценарию, а не порядку документации. Техническая деталь вводится в момент, когда сценарий создаёт для неё необходимость — не раньше. Детали без сценарной привязки (edge cases, альтернативные параметры) выносятся в конец заметки с обозначением контекста.
❌ «Модуль поддерживает 12 операций: создание, чтение, обновление, удаление…» ✅ Сценарий → нужно добавлять → нужно читать → обработчик не справляется → нужно распараллелить → обработчик упал → нужен механизм подтверждения.
Для читателя, который ещё не освоил тему, полностью решённый пример с видимым рассуждением учит эффективнее, чем задача, которую нужно решить самому (worked example effect, Sweller). Из этого принципа — несколько рабочих микропаттернов.
Ошибка → осознание. Ошибки — сильный момент для обучения, но только если ошибка тут же объясняется. Попробуем X → результат неожиданный → причина. Ошибка и объяснение не разделяются.
✅ «Попробуем WHERE annual_salary > 500000 — ошибка: столбец не найден. Причина: WHERE выполняется до SELECT, псевдоним ещё не существует.»
Сворачиваемый блок самопроверки (конкретная разметка — у адаптера) полезен для типичных контринтуитивных ошибок: читатель может попробовать сам, потом раскрывает ошибку и правильный ответ. Блок идёт после основного объяснения, не вместо него: worked example требует, чтобы путь сперва был показан.
Через дефицит текущего: контраст, боль, прожитая попытка. Когда документ вводит инструмент, упрощающий задачу, читатель быстрее принимает новое, если сначала почувствует неудобство старого. Работает на трёх уровнях интенсивности.
Показанный старый способ. Рабочий код «как делали раньше», потом — новый. Один контраст при введении, не при каждом использовании. Старый способ должен быть рабочим, не псевдокодом «можно было бы через X». Если он нереалистично громоздкий (30+ строк) — достаточно одного предложения с объяснением, почему он не подходит.
✅ Показать GROUP BY + JOIN перед оконной функцией, затем: «FIRST_VALUE делает то же одним проходом».
Прожитая боль. Читатель сам пробует старый способ прежде, чем увидеть новый. Текст ведёт его: «попробуем решить через X» — читатель пишет решение в голове — и только потом текст показывает, что есть Y. Это сильнее простого показа: читатель не наблюдает разницу, а обнаруживает её. Методисты называют это productive failure (Kapur): контролируемое страдание с существующими средствами делает последующее решение глубже осмысленным.
Отсылка к известной боли. Если читатель знает старый способ из опыта, достаточно короткой отсылки: «все, кто писал рекурсивные CTE руками, помнят, сколько шагов занимает…». Это не показ и не проживание — активация уже имеющейся боли.
Важное ограничение прожитой боли: она работает только тогда, когда у читателя достаточно базы, чтобы самому попробовать. Если старый способ требует знаний, которых ещё нет, — читатель застрянет во фрустрации. Тест: может ли читатель, имея только объявленные предпосылки, написать старое решение? Если нет — используй показ, не проживание.
Прослеживание сценария. Конкретный пример (запрос, пакет, транзакция) проводится через все этапы после того, как компоненты введены. «Пакет приходит на порт 443. Шаг 1: TLS handshake — 1.5 RTT. Шаг 2…»
Возврат в новом контексте. Тема появляется снова с другого угла. При возврате — одно предложение-напоминание: «Журнал, который мы видели как механизм восстановления, используется и для репликации…» Напоминание экономит переключение без повтора объяснения.
Все предыдущие решения — куда ведём, откуда идём, по какому пути — работают только при условии, что читатель успевает обрабатывать то, что ему дают. У рабочей памяти ограниченная ёмкость: слишком много одновременно — и даже правильно выстроенная дуга не обучает (cognitive load theory, Sweller). В тексте это проявляется в двух решениях: какой уровень деталей держать и в каком виде его подать.
Принцип дисциплины — убирать всё, что не двигает цель обучения (coherence principle, Mayer). Декоративный факт, красивая деталь, лишний уровень глубины — не нейтральный шум, а помеха: читатель тратит на них ограниченный ресурс, которого потом не хватит на главное.
Операционная форма принципа — тест на уровне предложения: убери предложение — следующий шаг рассуждения по-прежнему понятен и обоснован? Если да и у предложения нет другой видимой работы (создать разрыв, закрепить схему, перекинуть мостик) — оно не платит за место. Декоративное предложение не ноль, а минус.
Каждая заметка строит модель на определённом уровне абстракции. У уровня две границы. Потолок — то, что выше: когда тема из более высокого слоя появляется, она даётся как короткий контекст плюс ссылка, не объясняется в тексте. Пол — то, что ниже: деталь из более глубокого уровня появляется только тогда, когда объясняет наблюдаемый эффект текущего уровня.
Спуск ниже пола — самая частая ошибка. Автор знает, как устроен механизм глубже, и добавляет деталь ради точности. Но читатель не может её использовать — она не работает на цель заметки.
❌ «Регистры — это триггерные схемы на кристалле кремния» в заметке про иерархию памяти. Читатель не знает, что такое триггерная схема; термин не нужен, чтобы понять, почему регистры быстрые. ✅ «Регистры — внутри ядра, доступ за доли наносекунды» — наблюдаемый эффект без лишней глубины.
Выход выше потолка — реже, но тоже встречается: заметка начинает объяснять концепцию, которая принадлежит другому слою и должна была прийти из предпосылок или по ссылке.
Этот вопрос смыкается с §1 «результат управляет глубиной»: там тест — потеряет ли текст смысл, если убрать внутреннее устройство; здесь — не перегружает ли эта деталь читателя, не двигая цель. Обе проверки должны давать согласованный ответ.
Внутри заметки объяснение идёт от крупного масштаба к мелкому: назначение системы → части → устройство частей → поля и флаги. Пропуски масштаба ломают восприятие — читатель не понимает, куда его забрасывают.
❌ Сразу page->free_list без объяснения, что такое page.
❌ Оптимизация алгоритма до базового алгоритма.
✅ Сначала: «GC обходит граф живых объектов (mark) и освобождает остальные (sweep)». Потом: «mark использует tri-color…». Потом — структура данных для хранения состояния.
Одна секция — один шаг масштаба. Смешивание масштабов в одной секции — типичный источник перегрузки.
Некоторые темы нельзя объяснить за один линейный проход. Если 3+ компонентов ссылаются друг на друга, нужны несколько слоёв. Пример: версионность в БД = метки версий + журнал статусов + snapshot. Нельзя объяснить одно без других — но и показать одновременно все нельзя.
Слой 0 — ментальная модель. Компактное описание целиком: из чего состоит, как части связаны. Без деталей реализации. Часто диаграмма или мини-карта. Не вводит новых имён — закрепляет уже объяснённые элементы.
Слой 1 — как работает. Каждый компонент подробно. Порядок — по зависимостям: сначала тот, от которого зависят остальные.
Слой 2 (если нужен) — edge cases и оптимизации. Только после того, как основной механизм понятен.
Правило: слой 0 порождает вопросы для слоя 1; слой 1 — для слоя 2. Каждый слой — самодостаточная модель. Если зависимости линейны (A → B → C), послойное раскрытие не нужно — достаточно обычного нарратива.
Если у темы есть общая теория и конкретная реализация — разделять. Читатель сначала понимает концепцию абстрактно, потом видит конкретное воплощение. Реализация ссылается на теорию, не дублирует её.
✅ Сначала общая концепция (версионирование, видимость), потом реализация в конкретной системе (поля версий, журнал статусов, формат хранения). ❌ Смешивать абстрактные принципы и кодовые детали конкретной реализации в одном потоке.
Тест принадлежности утверждения: верно для класса систем → общая теория; верно для одной реализации → материал этой реализации; описывает интеграцию инструментов в задаче или стеке → прикладной материал. Физическая раскладка слоёв — зона адаптера.
Проза по умолчанию — она лучше держит причинно-следственную линию. Списки — для стабильных перечислений и чек-листов. Таблицы — когда 3+ вариантов сравниваются по одним и тем же атрибутам. Диаграммы полезны, когда помогают удержать структуру механизма, а не дублируют абзац.
Код для CS-заметок — центральный инструмент объяснения, но он тяжёлый для рабочей памяти. Правила компактности:
- Код минимален: ровно столько строк, сколько нужно для текущего шага. Длинные примеры (20+ строк) оправданы только для сквозных walkthrough'ов — и тогда разбиваются на шаги с пояснениями между ними.
- Реальный код (SQL, Go, Ruby) — когда важен синтаксис технологии или читатель должен скопировать и запустить. Псевдокод — для алгоритма, не привязанного к языку. Не смешивай в одном блоке.
- Комментарии внутри кода объясняют что делает эта строка. «Почему» и «какой эффект» — в прозе до или после блока. Не дублируй прозу комментариями.
- Эволюция: показать версию 1, объяснить проблему, показать версию 2. Не финальная версия с пометками «здесь мы изменили X».
Конкретика вместо абстрактных меток: если сущностей две, называть их по смыслу. ❌ «объект X ссылается на объект Y» ✅ «старый объект ссылается на молодой».
Аббревиатуры: если понятие встречается один раз — лучше словами.
Главы выше — про отдельную заметку. Но отдельной она почти не бывает: заметка продолжает линию, опирается на соседей и готовит следующие. У серии собственные режимы отказа, не видимые изнутри одной заметки: однообразие приёмов, леса, которые никто не снял, знание, которое ввели и больше ни разу не использовали.
Любой приём этого файла, повторённый в десяти заметках подряд, превращается в шаблон — и читатель начинает видеть инструкцию сквозь текст. Невидимость инструкции — свойство не только заметки, но и серии: одинаковые «ломающиеся модели» в каждом входе выдают её так же верно, как метатермин в абзаце.
Поэтому источник разрыва, приём входа, нить и форма мостиков в соседних заметках различаются. Для этого в цикле существует шаг «контекст» (§0.1): вход предыдущей заметки перечитан — его приём в текущей не повторяется. Тема при этом главнее разнообразия: если природа темы требует того же источника, что у соседа, меняется хотя бы форма — другая ситуация, другой масштаб, другой способ предъявить разрыв.
Развёрнутая мотивация, полный цикл «ситуация → роль → имя», контраст со старым способом, прожитая боль — строительные леса для читателя без схем. К середине серии читатель приходит с багажом всех предыдущих заметок, и те же леса превращаются в шум: он уже мотивирован, уже видел старый способ, уже держит модель. Методисты называют это expertise reversal effect (Kalyuga): приёмы, ускоряющие новичка, тормозят подготовленного.
Практика: глубина входа убывает вдоль серии. Поздняя заметка может открываться коротким причинным мостом из предыдущей — «решение X упирается в Y» — без полного цикла «роль раньше имени». Контраст «до/после» — для действительно нового класса инструментов, не для каждого варианта уже знакомого. Прожитая боль требует достаточной базы для попытки (§3) — и теряет смысл, когда читатель уже знает ответ.
Понимание, которое построили один раз и больше не трогали, стирается — независимо от качества объяснения. Извлечение из памяти укрепляет след сильнее перечитывания (testing effect, Roediger & Karpicke), а извлечение с интервалом — сильнее немедленного (spacing effect). Для серии это даёт норму: новая заметка заставляет одну-две схемы из предыдущих работать в новой роли. Не пересказ («напомним: WAL — это журнал…»), а работа: журнал, который читатель знает как механизм восстановления, оказывается источником для репликации — схему приходится достать из памяти и повернуть.
«Возврат в новом контексте» из §3 — внутризаметочная форма того же механизма; серия делает его межзаметочным и добавляет интервал. Работает и обратный сигнал: если концепции заметки ни разу не понадобились дальше по серии — либо заметка стоит не на своём месте, либо серия теряет связность.
Когда серия собирает одну модель по частям — pipeline запроса, layout памяти процесса, путь пакета — действуют три правила. Модель вводится при первом поводе, а не заранее «на вырост». Каждое расширение — новый шаг плюс его следствие, а не перерисовка всей схемы. Когда модель собрана целиком, она фиксируется один раз в полном виде; этот снимок становится опорой для ссылок из следующих заметок. Антипаттерн: «обновлённая схема» в каждой заметке с минимальными отличиями — читатель перестаёт видеть, что изменилось и зачем.
Главы §1–§5 — решения, которые принимает автор. Все они правильны в его голове, но его голова — это не голова читателя. Проклятие знания (§2) никуда не делось: то, что автор понимает, остаётся для него очевидным, и проверка текста самим автором всегда слабее, чем нужна. Главный принцип этой главы — formative assessment: не дожидаться финального результата («понял или не понял»), а встроить проверку в сам процесс письма и чтения.
Сильнейшая форма такой проверки — self-explanation effect (Chi): материал усваивается глубже, когда он провоцирует читателя предсказать следующий шаг, объяснить причину или восстановить связь самому. Это меняет критерий качества: текст работает не тогда, когда он назвал все термины и дал все ответы, а когда он подводит читателя к ответу, который тот может дать сам, — и тем самым вписывает этот ответ в собственную модель.
Симуляция — обязательный финал цикла (§0.1), не рекомендация. Перечитать текст, делая вид, что в голове только объявленные предпосылки и нулевой уровень (§2). Читать буквально по 5 строк за раз, после каждого блока спрашивая: что я теперь понимаю, чего не понимал раньше? есть ли термины без опоры? какой вопрос блок оставил открытым?
Эта проверка ловит то, чего автор механически не видит: декоративную точность, пропущенные шаги, имена без опоры, моменты перегрузки. Её нельзя заменить чтением «на связность» — связность читается автором через его модель, а пробелы заметны только симулированному читателю.
Полная симуляция — лучший инструмент, но у прохода есть минимальное ядро, которое проверяется всегда, даже когда внимание на исходе. Ядро — инварианты плюс самые частые протечки:
- Каждый технический термин объяснён выше, объясняется на месте или объявлен предпосылкой; висящих нет.
- Ни метатерминов, ни самореферентных оборотов, ни следов переписки и плана (§0.3).
- Вход: ситуация раньше имени; есть разрыв; не больше двух новых сущностей в первом абзаце.
- У каждого решения и оптимизации — показанный симптом.
- Каждая деталь привязана к шагу дуги; непривязанные удалены или вынесены с пометкой контекста.
- Мостики различаются по форме; определения не штампованы.
- Жизненные циклы ключевых сущностей закрыты; у механизмов есть «почему» и «как работает».
- Заголовки отражают предметное содержание, не тип задачи.
- Для заметки в серии: приём входа не повторяет соседей; хотя бы одна схема из предыдущих работает в новой роли.
Самые сильные обучающие моменты — те, где текст заставляет читателя что-то сделать, прежде чем дать ему ответ. «Попробуем X — ошибка — причина» из §3 работает именно потому, что читатель сначала предсказал результат, а потом увидел разрыв между предсказанием и реальностью. Сворачиваемый блок самопроверки — тот же механизм: читатель решает сам, потом видит правильный ответ.
Отсюда критерий: в заметке должны быть 1–2 места, где читатель может остановиться и предсказать. Обычно — перед введением ключевого механизма (читатель пытается объяснить наблюдение до того, как ему дают инструмент) и после его работы (читатель пробует применить инструмент к новому случаю). Это та же механика, что в межзаметочном возврате (§5): предсказание — извлечение уже имеющейся модели, и извлечение укрепляет её сильнее, чем повторный показ. Избыток таких мест утомляет; полное их отсутствие превращает заметку в справку.
Отдельный класс сигналов, что текст «ещё не дописан» до читателя, — следы процесса его создания. Метатермины и структурные следы из §0.3 — самый очевидный; менее явные — секции, повторяющие главы этого файла (параграф «мотивация», параграф «сценарий»), заголовки, повторяющие типы задач, «как вы просили», «в этой сессии». Заголовок должен отражать предметное содержание, а не роль раздела в инструкции или в разговоре автора с кем-то. Если фраза не появилась бы без текущей инструкции, плана или переписки — это протечка, а не объяснение.
Несколько паттернов, по которым проблему можно опознать, не проводя полной симуляции:
- Формульные мостики. Все секции заканчиваются одной конструкцией («X решило Y. Но Z.»). Сигнал: переходы формируются механически, а не содержанием. Перечитай все мостики в заметке как единый текст — если они звучат одинаково, разнообразь форму.
- Шаблонные определения. Каждое понятие введено через одну и ту же конструкцию («X — это Y, которое Z»). Нормально для одного-двух случаев, тревожно при десятке.
- Решения без симптома. Раздел начинается с новой оптимизации, но в предыдущем ничего не ломалось. Признак утраты дуги.
- Избыточное «мы». «Мы научились», «мы разобрались» — учитель за руку. Замени предметной причинностью: «выше видели, как X замедляет Y».
Эти паттерны не всегда ошибочны — в коротких текстах и в справочных разделах они бывают уместны. Но если они встречаются в объясняющей заметке подряд и часто, это сигнал: автор писал не для читателя, а для формы.
Правила выше дают рубрику; вот как она применяется к живому фрагменту. Вход заметки «Пул соединений»; предпосылка заметки — клиент-серверная модель PostgreSQL (один процесс на соединение).
Фрагмент до правки:
Пул соединений — это механизм переиспользования открытых соединений с базой данных. Он критически важен для производительности высоконагруженных приложений. PgBouncer поддерживает три режима пулинга: session, transaction и statement. В session-режиме соединение закрепляется за клиентом до отключения, в transaction-режиме возвращается в пул после каждой транзакции, в statement-режиме — после каждого оператора.
Диагноз:
- «Пул соединений — это механизм…» — имя раньше роли (§3): определение выдано до ситуации, в которой пул нужен.
- «Критически важен для производительности» — мотивация-заклинание без разрыва (§3): что именно ломается без пула — не показано. Тест предложения (§4): убирается без потери следующего шага.
- PgBouncer — имя без опоры (§2): не в предпосылках и не введён; читатель получает продукт раньше задачи.
- Три режима перечислены порядком документации (§3): решение без симптома — читатель не видел проблему, которую session-режим создаёт, а transaction-режим решает.
После правки:
Каждое новое соединение с PostgreSQL — это рождение отдельного процесса на сервере: fork, выделение памяти, аутентификация. Для одного подключения это единицы миллисекунд — незаметно. Но веб-приложение открывает соединение на каждый HTTP-запрос, и при тысяче запросов в секунду сервер тратит на создание и разрушение процессов больше ресурсов, чем на сами запросы.
Соединение дорого создать и дёшево держать открытым. Значит, создавать его нужно редко, а использовать — многократно. Компонент, который держит набор готовых соединений и выдаёт их запросам по очереди, называется пулом соединений.
Режимы пулинга в правке не исчезли — они переехали туда, где сценарий создаст для них симптом: соединение, закреплённое за молчащим клиентом, простаивает → нужен режим, возвращающий его в пул раньше.