Пример документа проектирования
Самый частый вопрос о design doc — где найти хороший пример. Никогда не встречал опубликованный design doc, который я считал бы высокого качества. Все мои документы остаются в компаниях, которые мне за них платили.
Поэтому написал design doc с нуля, основываясь на принципах из этого материала. Он описывает дизайн реального веб-приложения, которое разрабатывается.
Документ был создан до написания любого кода, и реализация следует этому дизайну.
Design doc получился более подробным, чем обычно пишется для персональных хоби-проектов. Но это примерно такой же объем и глубина документа, который создается при координации работы нескольких человек на профессиональном проекте.
Когда писать design doc?
Чем сложнее или рискованнее проект, тем ценнее написать документ проектирования.
Рассмотрите эти вопросы:
- Будут ли несколько человек координировать работу над реализацией дизайна?
- Займет ли проект более трех месяцев полной разработки?
- Будет ли реализация работать в production несколько лет?
- Вовлекает ли проект сотрудничество между командами?
- Цели и требования проекта размыты?
- Есть ли катастрофические риски, которые можно предотвратить на этапе проектирования (например, уязвимости в безопасности, юридические риски)?
Если вы ответили «да» на любой из этих вопросов, то, вероятно, стоит писать design doc. Если ответили «да» на два или больше — документ почти наверняка будет полезен.
Сколько времени инвестировать в design doc?
Design doc может быть простой однострочной страницей или 50-страничным документом, требующим согласования пяти команд. Нужно решить, сколько деталей имеет смысл включить.
Нет универсального правила, сколько времени уходит на design doc, как нет правила, сколько тестировать код. Правильный объем инвестиций зависит от целей команды, рисков, сроков и культуры. Иногда правильный объем инвестиций — ноль.
Что должно быть в design doc?
Если указать каждую возможную деталь в design doc, то получится реализация, написанная во время фазы проектирования. Это бы полностью исказило смысл документа.
Как практическое правило, можно задать простой вопрос, чтобы решить, входит ли решение в design doc: какой штраф за ошибку?
Какова стоимость ошибки?
Не все проектные решения одинаково важны. Некоторые выборы более постоянны, чем другие.
Например, если построить веб-приложение на C++ и через 200 тысяч строк кода осознать, что Ruby on Rails был лучшим выбором, вы в ловушке. Переписывание никогда не сработает, и даже если удастся писать новый код на Rails, все равно придется поддерживать код на двух совершенно разных языках.
Другие проектные решения тривиальны. Например, если приложение показывает список из 100 статей, должны ли они все появиться сразу? Или пользователь видит 25 статей и может нажать «Загрузить еще» для следующих 25?
Это не важно.
Кнопка «Загрузить еще» — не проектное решение. Если выбрать одно решение, а отзывы пользователей покажут ошибку, можно исправить за несколько часов. Не нужно документировать весь процесс размышлений в design doc, и уж точно не стоит тратить циклы обзора на спор об этом.
Компоненты design doc
Ниже представлены типичные разделы для включения в design doc. Обычно не нужен каждый раздел для каждого документа. Выбирайте подмножество, которое имеет смысл для вас.
Название
Первое, что нужно проекту, — это название. Так люди будут называть проект в разговоре, поэтому выбирайте что-то короткое, отличительное и выразительное.
Например, если добавляете слой кеширования между сервером приложений и базой данных, RecencyBank будет хорошим названием. Его легко произносить, и оно описывает цель проекта. Плохое название — «Project Flying Silver Horse», потому что оно многословно и бессмысленно.
Метаданные
Скучно, но полезно. Метаданные помогают читателю понять базовый контекст документа:
- Кто автор? (имя + адрес электронной почты)
- Когда создан документ?
- Какой авторитетный URL?
- Особенно если организация использует редиректы shortlink вроде
http://go/recency-bank
- Особенно если организация использует редиректы shortlink вроде
- Кто одобрил документ и когда?
- В случаях, когда документ требует одобрения от коллег или партнеров.
Метаданные
- URL: http://go/recency-bank-design
- Автор: Michael Lynch (michael@refactoringenglish.com)
- Создан: 2026-06-22
- Статус: Одобрен
- alan@ одобрил, 2026-07-14
- betty@ одобрила, 2026-07-15
Цель
Цель — это однострочное объяснение назначения проекта. Должна появиться на первой странице документа простым языком, который поймет любой заинтересованный участник.
Цель
Улучшить производительность приложения, добавив слой кеширования между веб-сервером Trogdor и базой данных Postgres.
Предпосылки
Раздел предпосылок объясняет контекст и мотивацию проекта. Должен ответить на эти вопросы:
- Почему команда берется за этот проект?
- Какую проблему решает проект?
- Были ли попытки решить эту проблему раньше?
Предпосылки
Когда запустили веб-приложение Trogdor в 2023 году, страницы обычно загружались за 100 мс или меньше. Через три года медианное время загрузки страницы выросло до 600 мс, что заставляет пользователей воспринимать приложение как медленное.
Исследовали замедление и обнаружили, что запросы к базе данных составляют 80% времени загрузки страницы. По мере роста хранилища запросы замедляются.
Также обнаружили, что 95% запросов к базе касаются одних и тех же 3% строк. Такой паттерн использования отлично подходит для кеширования в памяти. Кэш будет предоставлять часто используемые данные быстрее и снизит нагрузку на базу для других запросов.
Имеет ли смысл design doc без внешнего контекста?
Представьте, что бы сказали коллеге или команде-партнеру перед тем, как они прочитают документ.
Теперь поймите, что некоторые читатели увидят документ до объяснения от вас, поэтому то, что им нужно понять, должно быть на первой странице.
Связанные документы
Если проект связан с другими документами, облегчите читателю их поиск.
Добавьте ссылки на:
- Документы от менеджера программы или тестировщиков по этому проекту (например, планы тестирования, функциональные спецификации)
- Design doc связанных систем
- Design doc предыдущих итераций этого проекта
Связанные документы
- План тестирования: http://go/recency-bank-test-plan
- Отчет производительности Trogdor: http://go/trogdor-perf-2026
Цели
Раздел целей описывает высокоуровневые цели проекта. Должен логически связываться с разделом предпосылок и объяснять, как выглядит мир после завершения реализации.
Избегайте ставить цели в терминах деталей реализации. Цели должны показать, как проект приносит пользу пользователям, команде или компании.
Плохо: ставить цели в терминах внутренних деталей реализации
- Добавить Kubernetes в нашу инфраструктуру.
Хорошо: ставить цели в терминах влияния
- Минимизировать сбои, связанные с развертыванием новых версий приложения.
Цели
- Увеличить воспринимаемую отзывчивость веб-приложения Trogdor для пользователя.
- Снизить нагрузку на сервер базы данных.
Не-цели
Пока цели определяют то, что входит в область проекта, раздел не-целей ограничивает то, что выходит за рамки.
Есть ли цели, которые читатели могут неправильно предположить, что они в области проекта? Если да, добавьте их как явные не-цели.
Не-цели
- Создать универсальную, переиспользуемую систему кеширования
- Слой кеширования, который мы добавим к веб-приложению Trogdor, сделает оптимизации, специфичные для приложения. Переиспользование этого кэша на других системах выходит за рамки.
- Кеширование с учетом местоположения
- В будущем может быть полезно поддерживать кэши, расположенные географически близко к конечному пользователю для снижения задержки, но это выходит за рамки v1.
Сценарии
Если цель — что-то вроде «Добавить кнопку 'Поделиться как URL' к диаграммам», читатель может не понять, как это выглядит на практике.
Раздел сценариев позволяет нарисовать для читателя картину того, как работает готовая система в реальном мире.
Сценарий: поделиться отчетом по URL
- Bob создает пользовательский отчет на панели управления KeyMetrics.
- Bob переходит в меню и нажимает «Поделиться > по URL».
- Bob отправляет URL коллеге Charlie.
- Charlie нажимает ссылку и видит точную копию отчета Bob в режиме только для чтения.
Диаграммы
Диаграммы чрезвычайно ценны, хотя это может быть не очевидно.
Как автор дизайна, интуитивно понимаете, как части плана складываются вместе. Видите архитектуру в голове. Рецензенты не имеют этой ментальной картины, поэтому самый быстрый способ показать им — нарисовать картинку.
Пример диаграммы, показывающей архитектуру простого веб-приложения.
Если не знаете, что должно быть на диаграмме, подумайте о этих вопросах:
- Как данные проходят через систему?
- Как разные компоненты системы складываются вместе?
- Как система взаимодействует со своими зависимостями и downstream-клиентами?
- Какие протоколы коммуникации определяет система?
Выбирайте инструмент диаграмирования, который гибкий в редактировании. Видели разработчиков, которые создавали красивую диаграмму на доске и фотографировали для design doc. Первый вариант выглядит потрясающе, но потом они застревают с этой диаграммой навсегда, потому что не могут отредактировать фото без полного переделывания.
Excalidraw, draw.io и Google Drawings — популярные инструменты диаграмирования, которые облегчают правки. Есть также языки вроде Mermaid, D2 и Graphviz, которые позволяют генерировать диаграммы программно. Хорошо работает использование LLM для создания кода диаграмирования. Помните, ссылаться на исходный рисунок или код, чтобы товарищи могли воспроизвести диаграмму.
Словарь
Словарь определяет термины, которые читатели могут не узнать.
Тщательно подумайте о потенциальных читателях документа, особенно новичках в команде и людях за пределами вашей ближайшей команды. Поймут ли эти читатели названия внутренних инструментов или систем, на которые ссылается документ?
Когда возможно, используйте термины, которые аудитория узнает без обращения к словарю. Определение термина в словаре лучше, чем вообще не определять, но лучшее решение — использовать узнаваемые термины или определять их встроенно, чтобы читатель не прыгал по документу.
Словарь
- Apposaurus: внутренний инструмент нагрузочного тестирования команды. Используется для симуляции всплеска посетителей к веб-приложению Trogdor, чтобы проверить, что приложение продолжает работать при ожидаемых нагрузках.
- Baba-o-styley: внутренний линтер кода, который следит за соблюдением стиля кода компании.
Ограничения
Если есть серьезные ограничения, наложенные на дизайн бюджетом, клиентами, инфраструктурой или зависимостями, объясните их, чтобы читатель понял контекст решений дизайна.
Ограничения
Все наши серверы на RISC-V, поэтому весь код и зависимости должны работать на архитектуре RISC-V.
Целевые показатели уровня обслуживания (SLO)
SLO создает измеримый, объективный показатель производительности системы. Вероятно, слышали о соглашениях об уровне обслуживания (SLA). SLA — это просто SLO плюс финансовые штрафы за несоответствие.
В компании обычно не штрафуют коллег финансово за ошибки (хотя это было бы забавно, не так ли?). Поэтому design doc определяют SLO вместо SLA.
Менеджер может сказать, что приложение должно быть «отзывчивым на мобильных», но это неточно. Идея менеджера о «отзывчивом» может быть <2 мс задержки, и не хочется ждать до конца разработки, чтобы узнать. Хорошо определенный SLO предотвращает двусмысленность, выражая цели в конкретных, объективных терминах.
Типичные элементы SLO:
- Доступность/uptime: какой процент времени система будет доступна?
- Задержка: как быстро сервис завершит запросы?
- Масштаб: какой объем работы может выдержать система?
Целевые показатели уровня обслуживания
- 50-й процентиль задержки для user-facing HTTP-запросов Trogdor: <=200 мс
- 50-й процентиль задержки запроса Postgres: <= 80 мс
Мониторинг / алерты
Как только определите SLO (см. выше), пора подумать, как их измерять в production.
Самый простой способ проверить, достигли ли SLO — ручная проверка. По мере развития организации нужно автоматизировать мониторинг, чтобы обнаруживать отказы SLO немедленно.
При определении стратегии мониторинга задайте себе вопросы:
- Если сервис отключится, как вы узнаете?
- Если производительность упадет в 100 раз, как вы поймете?
- Какие другие события должны вызвать алерт?
- Например, скачок использования CPU, отказы аутентификации, системные ошибки
Мониторинг
Следующие события вызовут page для инженера, ответственного за систему:
- 95-й процентиль задержки для user-facing HTTP-запросов Trogdor: >= 3 сек
- Среднее использование CPU серверов Postgres в течение последних 2 минут: >= 90%
График
Раздел графика разбивает проект на вехи. Указывает, когда будут переданы результаты заинтересованным участникам.
Выбирайте вехи, которые создают полезные артефакты для заинтересованных участников. Например, начните с UI, который показывает поддельные данные, и покажите это клиентам первым. Если выяснится, что неправильно понимали требования клиента, поддельные данные позволят узнать рано, а не после того, как уже реализована вся логика, чтобы заполнить UI данными из production.
Если не знаете, как оценивать графики проектов, настоятельно рекомендую статью Joel Spolsky «Painless Software Schedules». Статье 25 лет, но она остается моей любимой стратегией оценки программного обеспечения.
График
- Веха 1 (2026-07-01): RecencyBank live в тестовом окружении с зафиксированным подмножеством кэшированных данных (не читает из Postgres).
- Веха 2 (2026-07-17): RecencyBank live в тестовом окружении и кэширует реальные данные из Postgres.
- Веха 3 (2026-08-03): RecencyBank live в тестовом окружении и навязывает правила вытеснения кэша и жизненного цикла.
- Веха 4 (2026-08-22): RecencyBank полностью реализован и развернут в production.
Интерфейсы
Проект существует, чтобы служить людям или другим системам, поэтому как выглядят эти взаимодействия?
- Для графических систем, каков пользовательский интерфейс?
- Просто простые эскизы; не увязайте в точных выборах UI.
- Для программных интерфейсов, каковы семантика API или CLI?
- Для файловых интерфейсов, какой формат файла?
Интерфейсы
Struct
Serverв Trogdor сейчас напрямую зависит от Go structPostgresDBвот так:type Server struct { db PostgresDB }
PostgresDBимеет следующие экспортированные методы:GetUser(id UserID) (User, error) ListUsers() ([]User, error) ...Создадим Go
interfacetype с тем же API surface какPostgresDB:type Store interface { GetUser(id UserID) (User, error) ListUsers() ([]User, error) }Реализуем тип кеширования RecencyBank, который реализует тот же
interfaceи оборачивает backend structPostgresDB. Реализация RecencyBank будет кэшировать чтение из Postgres и пересылать запросы Postgres, когда они меняют состояние или зависят от данных, которых нет в кэше.Единственное изменение в реализации
Server— замена типа одного члена на новыйinterface:type Server struct { db store.Store }
Зависимости / инфраструктура
Раздел зависимостей должен ответить на вопросы вроде:
- На каких языках программирования вы будете писать?
- На каком железе или сервисе запускается код?
- Где будут жить постоянные данные?
Легко пропустить этот раздел, но решения о языке, библиотеках и инфраструктуре имеют большое влияние на сложность и долгосрочные затраты на обслуживание системы.
Глубоко подумайте о том, какие зависимости будет сложно менять после реализации. Не беспокойтесь столько о тех, которые легко заменить. Сложно менять языки или backends хранилища, но если недовольны сторонним сервисом для отправки писем, можно заменить за день.
Зависимости
- Язык: Go
- Уже широко используем Go, и это подходящий язык для обслуживания очень параллельных workflow.
- Сторонние пакеты
- bbolt: это широко используемая реализация key-value store, которая реализует множество функций, которые нам нужны для RecencyBank.
Безопасность
Чтобы строить безопасное программное обеспечение, разработчики должны интегрировать безопасность во весь жизненный цикл, начиная с этапа проектирования.
Раздел безопасности должен ответить на вопросы вроде:
- Какие угрозы были рассмотрены?
- Например, что происходит, если атакующий пробует каждый возможный пароль? Что если пользователь загружает PDF, зараженный вредоносом ПО?
- Какова поверхность атаки этой системы?
- То есть, где она обрабатывает потенциально вредоносные данные?
- Каковы границы доверия?
- В какой точке данные переходят из менее привилегированной системы в более привилегированную?
- Например, в веб-приложении запросы из браузера пользователя пересекают границу доверия, так как веб-сервер не должен предполагать, что input из браузера безопасен.
Даже если думаете, что угрозы безопасности маловероятны или неуместны в системе, все равно полезно документировать обоснование. Объяснение может подсказать рецензентам об угрозах, которые пропустили.
Безопасность
RecencyBank не должен принимать прямые запросы из публичного Интернета, так как не навязывает никакой контроль доступа.
RecencyBank будет работать на изолированной сети, где принимает входящие запросы только от веб-сервера Trogdor и может делать исходящие запросы только к пулу серверов Postgres.
Приватность
Раздел приватности — это возможность подумать о чувствительных данных, которые обрабатывает система, и какие гарантии нужны, чтобы их защитить. Должен ответить на вопросы:
- Какие чувствительные данные обрабатывает система?
- Как долго их хранить?
- Кто получит доступ?
- Как их защитить?
- Например, будут ли данные зашифрованы at rest и in transit?
Приватность
RecencyBank содержит те же чувствительные данные пользователя, что и база данных Postgres, поэтому наследует политику приватности систем Postgres. В частности, инженеры могут получить доступ к системам RecencyBank в production только с ассоциированным номером багов. Инженеры должны минимизировать доступ к данным пользователя, только к тому, что строго необходимо для расследования бага.
Юридические соображения
Если система работает в строго регулируемом домене, как финансы или здравоохранение, раздел юридических соображений помогает соответствовать соответствующим законам.
Даже вне регулируемых доменов подумайте, может ли система нарушить закон, если что-то пойдет не так. Объясните, как вы избежите нарушения закона, которое может поставить под угрозу компанию или клиентов.
Если публикуете код под open-source лицензией, определите, какую лицензию выбрали и почему.
Соответствие контрактам FizzleCorp
Наш контракт с FizzleCorp строго ограничивает нашу возможность создавать новые копии их собственных биометрических данных пользователя FizzlePerfect™.
К счастью, наша юридическая команда просмотрела формулировку контракта и подтвердила, что слой кеширования подходит в существующем определении «storage layer», поэтому мы можем кэшировать данные FizzlePerfect™ в RecencyBank без переговоров по контракту.
Логирование
Логи могут быть чрезвычайно полезны при исследовании бага, проблемы производительности или инцидента безопасности. Если спроектировать эффективное логирование, упростится долгосрочное обслуживание системы.
При обдумывании логирования рассмотрите эти вопросы:
- Какие критические события логирует сервис?
- Есть ли разные уровни логирования?
- Например, информационный, предупреждение, ошибка, критический
- Где система хранит свои логи?
- Как долго храните логи?
- Кто имеет доступ к логам?
- Есть ли чувствительные данные, которые нужно исключить из логов?
Логирование
RecencyBank логирует следующие события:
- При инициализации логирует параметры, используемые для инициализации RecencyBank, а также емкость RAM и использование на хосте.
- Сохранение значения в памяти не удается.
- Инвалидация кэша не удается.
Открытые вопросы
Когда пишете design doc, вероятно встретитесь с одной из следующих ситуаций:
- В дизайне есть отклонение, но не уверены, как его решить.
- В дизайне есть пробел, но нужно собрать больше информации, чтобы его закрыть.
- Терзаетесь между несколькими решениями.
Создайте приложение в design doc под названием «Открытые вопросы», которое документирует ваши нерешенные вопросы.
Каждая запись в разделе открытых вопросов должна объяснить:
- Какая проблема требует дополнительной работы?
- Какие варианты видите для решения вопроса?
- Каков ближайший следующий шаг для решения вопроса?
Открытый вопрос: выбор размера RAM для кэша
Нужно решить, сколько RAM назначить слою кеширования. Добавление RAM увеличивает производительность, но RAM дорогая, и есть убывающие возвраты при добавлении дополнительного RAM.
Существует некоторое оптимальное количество RAM, которое минимизирует инфраструктурные затраты между системой кеширования и базой данных. Теоретически можно обнаружить это оптимальное значение, установив тестовое окружение и запустив несколько симуляций, но запуск этих симуляций стоит нам dev time.
Оцениваю, что стоимость создания тестового окружения и запуска одной симуляции — 3,0 dev дня. Как только инфраструктура будет готова, дополнительные симуляции займут примерно 0,75 dev дня каждая.
Предложенное решение: выбрать 128 GB RAM без тестирования. Вероятно, близко к оптимальному, и dev time значительно дороже, чем RAM.
Следующий шаг: попросить feedback у tech lead.
Решенные вопросы
Когда решите открытый вопрос, суммируйте решение и переместите его из «Открытые вопросы» в раздел «Решенные вопросы» в design doc. Сохраняйте полное обсуждение для потомства.
Решенный вопрос: выбор размера RAM для кэша
Решение: предоставить 128 GB RAM слою кеширования. Если не будут выполнены цели производительности и RAM — ограничение, можно добавить больше RAM на этом этапе. Стоимость dev для запуска тестов, чтобы обнаружить идеальный размер RAM, намного превышает стоимость дополнительного RAM.
Нужно решить… [остальная часть исходного открытого вопроса идет сюда]
Рассмотренные альтернативы
Если предвидите, что читатели спросят, «Почему вы не сделали X?», помогает ответить на это заранее в разделе «Рассмотренные альтернативы». Это также место, где объяснить варианты, которые отклонили, особенно если они первоначально казались привлекательными или исследовались обширно.
Знаю некоторых разработчиков, которые тратят часы на детальное документирование каждой отклоненной идеи дизайна, но думаю, это перебор. Как читатель и автор, всё, что нужно в разделе альтернатив — несколько строк, описывающих сильные альтернативы и почему они не сработали.
Рассмотренные альтернативы
- Google Cloud Firestore (постоянное хранилище)
- Долговечность и надежность были привлекательны, но не нравилась блокировка платформы и сложность локального тестирования.
Пропуск design doc через обзор
После завершения design doc следующий шаг — поделиться им с командой и собрать обратную связь.
Следующий раздел охватывает техники для получения полезной обратной связи по дизайну, которая продвигает проект вперед, вместо того чтобы застопорить его спорами и смятением: