Руководство программиста по ГОСТ 19.504-79
Руководство программиста
Руководство программиста описывает, как программа устроена изнутри - модули, классы, публичные интерфейсы, форматы данных, алгоритмы, точки расширения. Здесь уже не "как установить" (это к системному программисту), и не "как нажимать кнопки" (это к оператору). Пишут, как под капотом и как стыковаться с программой через код.
Нужно для разработчиков, которые будут сопровождать, дорабатывать или интегрировать программу.
1. Стандарт и его роль
1.1 Общая характеристика ГОСТ 19.504-79
- Наименование документа: Руководство программиста
- Статус: Государственный стандарт СССР, действует по сей день в РФ как межгосударственный стандарт (соответствует СТ СЭВ 2095-80).
- Дата введения: 1 января 1980 г.
- Утверждён: Постановлением Госстандарта СССР от 12.01.1979 № 74.
- Область применения:
- Разработка и сопровождение программного обеспечения (ПО) в рамках Единой системы программной документации (ЕСПД).
- Обязателен к применению в организациях, работающих по ГОСТ 19.100–19.701 (ЕСПД), особенно в госсекторе, ОПК, энергетике, транспорте и других регулируемых отраслях.
💡 Примечание: Стандарт не отменён и часто используется в контексте требований к документации по ГОСТ Р ИСО/МЭК 12207 и 15288. В современной практике его требования адаптируются под agile, но базовая структура остаётся актуальной при составлении внутренней технической документации.
1.2 Назначение Руководства программиста
Руководство программиста — документ, предназначенный для разработчиков, включающий техническую информацию, необходимую для:
- интеграции программы в состав комплекса ПО;
- сопровождения и модификации;
- отладки и тестирования;
- обеспечения сопряжения с другими программами и системами.
Он не дублирует Руководство оператора (ГОСТ 19.505) и не заменяет Техническое задание (ГОСТ 19.201). Это — документ инженерного уровня, ориентированный на реализацию.
1.3 Общая структура документа по ГОСТ
| Раздел | Обязательность | Краткое содержание |
|---|---|---|
| Титульный лист / реквизиты | Да | Назначение документа, наименование ПО, номер версии, дата, ответственные |
| Аннотация (информационная часть) | Да | Краткая характеристика, назначение, применимость |
| Содержание | Да | Оглавление с нумерацией разделов |
| 1. Назначение и условия применения программ | Обязательный | Цель, функции, требования к среде выполнения |
| 2. Характеристика программы | Обязательный | Режимы работы, временные/ресурсные характеристики, надёжность |
| 3. Обращение к программе | Обязательный | Способы вызова, интерфейсы, передача управления и параметров |
| 4. Входные и выходные данные | Обязательный | Форматы, структуры, кодировки, примеры |
| 5. Сообщения | Обязательный | Типы сообщений, тексты, действия при их возникновении |
| Приложения | Опционально | Доп. схемы, примеры кода, таблицы, протоколы |
📌 Важно: Структура оформляется в соответствии с ГОСТ 19.105-78 — требования к оформлению программных документов (шрифты, поля, нумерация, ссылки и т.п.).
2. Пошаговое руководство по составлению Руководства программиста
Ниже — детализированный порядок составления документа. Каждый шаг включает что писать и как, с акцентом на техническую точность и воспроизводимость.
Шаг 1. Подготовительный этап
- Определите полный состав программных модулей, к которым будет относиться документ:
- Это может быть один модуль, подсистема или целая система (если она атомарна по функционалу).
- Убедитесь, что у вас есть актуальные:
- Архитектурная схема (в том числе API-контракты);
- Техническое задание (ГОСТ 19.201);
- Документация по использованным технологиям (SDK, runtime, библиотеки);
- Спецификация данных (ERD / JSON Schema / XSD).
- Назначьте ответственных:
- Разработчик — поставляет технические данные;
- Архитектор — утверждает интерфейсы и режимы;
- Техписатель — формирует и редактирует документ.
Шаг 2. Раздел «Назначение и условия применения программ»
Что включать:
-
Назначение:
«Программа
auth-serviceпредназначена для централизованной аутентификации и авторизации пользователей в распределённой системеX-Core. Реализует протоколы OAuth2.0 и OpenID Connect 1.0.» -
Функции: перечислить только программные функции, реализованные внутри модуля («осуществляет JWT-валидацию токенов», «реализует эндпоинты
/token,/userinfo,/revoke»). -
Условия применения (строго по категориям):
- Аппаратные требования:
- Минимальный объём RAM: 512 МБ
- Процессор: x86-64, 2 ядра
- Наличие TPM-2.0 (если требуется)
- Программные требования:
- ОС: Linux (Ubuntu 20.04+, AlmaLinux 8+)
- Среда: OpenJDK 17+, Node.js 18.x
- Зависимости: PostgreSQL 14+, Redis 6.2+, Vault 1.12+
- Сетевые требования:
- Доступ к порту 5432 (PostgreSQL), 6379 (Redis), 8200 (Vault)
- Возможность TLS-терминации на уровне ingress
- Аппаратные требования:
✅ Рекомендация: оформлять в виде таблиц.
❌ Ошибка: смешивать требования к системе и требования к разработке (например, «требуется опыт в Spring Безопасность» — это требование к персоналу).
Пример оформления:
### 1. Назначение и условия применения программ
#### 1.1 Назначение
Модуль `calc-engine` реализует ядро расчёта финансовых показателей (IRR, NPV, DPP) для инвестиционных проектов в системе `X-Core`. Предоставляет REST API для клиентских сервисов.
#### 1.2 Функции
- Приём JSON-описания денежного потока;
- Расчёт IRR методом Ньютона–Рафсона (с итерационным уточнением);
- Валидация входных параметров (чек-лист: не пустой поток, не более 100 периодов, ставка в [0;1]);
- Логирование ошибок расчёта (коды 4xx/5xx).
#### 1.3 Условия применения
| Категория | Требование |
|-----------|------------|
| Аппаратное обеспечение | RAM ≥ 1 ГБ, CPU ≥ 2 vCPU |
| Операционная система | Linux (ядро ≥ 5.4) |
| Среда выполнения | Python 3.10+, `numpy==1.24.3`, `scipy==1.10.1` |
| Сетевые возможности | Доступ к `redis.internal:6379`, `logger.service:9000/udp` |
| Прочие ограничения | Не поддерживает Windows; требует `libgomp1` в системе |
Шаг 3. Раздел «Характеристика программы»
Это — «паспорт» поведения программы под нагрузкой и в штатных/нештатных режимах.
Обязательные подразделы (по смыслу ГОСТ):
-
Режим работы
- Пакетный / интерактивный / фоновый / реального времени
- Поддержка многопоточности, кластеризации, горизонтального масштабирования
- Ограничения на параллельные запросы (например,
max_concurrent_calculations = 50)
-
Временные характеристики
- Среднее/максимальное время выполнения операции (в ms)
- Зависимость от объёма входных данных
- Пример: «Обработка потока из 10 периодов: ≤ 15 мс (P95); из 100 периодов: ≤ 210 мс (P95)»
-
Средства контроля и самовосстановления
- Логирование: уровни, категории, формат (JSON, RFC5424)
- Метрики: экспортируемые через Prometheus (
calc_duration_seconds,calc_error_total) - Механизмы graceful degradation:
- fallback на упрощённый алгоритм при timeout > 500 мс
- circuit breaker после 5 ошибок подряд
- Health-check: эндпоинт
/healthz, возвращает{ "status": "ok", "deps": { "redis": true } }
✅ Рекомендация: приводить измеренные данные (benchmark-результаты), а не оценочные.
❌ Ошибка: использовать расплывчатые формулировки вроде «высокая производительность» без метрик.
Пример:
### 2. Характеристика программы
#### 2.1 Режим работы
- Интерактивный (запрос–ответ по HTTP/1.1 и HTTP/2);
- Поддержка до 200 одновременных соединений (ограничено `gunicorn --workers=4 --threads=50`);
- Stateless: все сессии хранятся в Redis.
#### 2.2 Временные характеристики (на стенде: 2 vCPU, 4 ГБ RAM, SSD)
| Размер входа | Среднее время, мс | P95, мс | P99, мс |
|--------------|-------------------|---------|---------|
| 10 периодов | 8.2 | 14.1 | 19.7 |
| 50 периодов | 42.6 | 88.3 | 120.4 |
| 100 периодов | 163.9 | 211.5 | 302.8 |
> 📊 Замеры выполнены с помощью `k6` (1000 VUs, 30s ramp-up).
#### 2.3 Средства контроля и самовосстановления
- **Логирование**:
- Уровень `INFO` — старт/стоп запроса, `ERROR` — исключения, `DEBUG` — детали расчёта (опционально).
- Формат: JSON, поля: `ts`, `level`, `req_id`, `module`, `msg`, `duration_ms`.
- **Метрики (Prometheus)**:
promql
calc_duration_seconds{quantile="0.95"}
calc_error_total{type="input_validation", method="POST"}
- **Health-check**:
http
GET /healthz
→ 200 OK
{
"status": "ok",
"version": "2.3.1",
"deps": {
"redis": true,
"vault": true
}
}
- **Self-healing**:
При недоступности Redis > 3 с — переключение на in-memory LRU-кэш (ёмкость 1000 записей), с логированием предупреждения `WARN cache.fallback redis_unavailable`.
Шаг 4. Раздел «Обращение к программе»
Этот раздел — интерфейсная спецификация. Должен позволить другому разработчику интегрировать модуль без доступа к исходному коду.
Что включать:
-
Способы вызова:
- REST API (методы, пути, заголовки)
- CLI (команды, флаги)
- Библиотечный интерфейс (публичные классы/функции)
- Сообщения (AMQP, Kafka, gRPC)
-
Передача управления и параметров:
- Как передаётся контекст (например,
X-Request-ID, JWT вAuthorization: Bearer …) - Формат тела запроса/ответа
- Правила маршалинга/демаршалинга
- Поведение при ошибках (статус-коды, структура
error)
- Как передаётся контекст (например,
✅ Рекомендация: использовать OpenAPI/Swagger-подобные фрагменты.
❌ Ошибка: описывать внутреннюю логику вместо контракта («функция сначала проверяет…» — не надо!).
Пример:
### 3. Обращение к программе
#### 3.1 REST API (`/api/v1/calc`)
| Метод | Путь | Описание |
|-------|------|----------|
| POST | `/irr` | Расчёт внутренней нормы доходности |
##### Запрос
http
POST /api/v1/calc/irr HTTP/1.1
Host: calc-engine.x-core.internal
Content-Type: application/json
X-Request-ID: a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8
Authorization: Bearer <JWT>
{
"cashflow": [
{"period": 0, "amount": -1000000},
{"period": 1, "amount": 300000},
{"period": 2, "amount": 400000},
{"period": 3, "amount": 500000}
],
"guess": 0.1
}
- `cashflow`: обязательный массив объектов:
- `period` (int ≥ 0, уникальный)
- `amount` (float, может быть отрицательным)
- `guess`: необязательный (float ∈ [0; 1]), стартовое приближение.
##### Ответ (успех, 200 OK)
json
{
"irr": 0.1278,
"iterations": 7,
"converged": true
}
##### Ответ (ошибка валидации, 400 Bad Request)
json
{
"error": "INVALID_INPUT",
"detail": "cashflow[1].period must be `> cashflow[0].period"
}
##### Коды ответов
| Код | Причина |
|-----|---------|
| 200 | Успешный расчёт |
| 400 | Ошибка валидации входных данных |
| 401 | Отсутствует/некорректный JWT |
| 429 | Превышен лимит запросов (100/сек/IP) |
| 500 | Внутренняя ошибка сервера (см. логи по `X-Request-ID`) |
| 503 | Сервис недоступен (Redis down, fallback active) |
Шаг 5. Раздел «Входные и выходные данные»
🔍 Смысл раздела (по ГОСТ 19.504-79, п. 2.4):
«Описание организации используемой входной и выходной информации и, при необходимости, её кодирования».
Этот раздел — техническая спецификация форматов данных. Критически важен для сопряжения, тестирования, генерации моков и документирования API-контрактов.
Что включать (по смыслу и практике ЕСПД):
| Элемент | Требования |
|---|---|
| Источники входных данных | Откуда поступают данные: API, файл, stdin, шина сообщений, БД-запрос, CLI-аргументы и т.п. |
| Структура входных данных | Структуры (JSON Schema, XSD, protobuf), поля, типы, ограничения (длина, диапазон, regexp), обязательность |
| Кодировки | UTF-8, CP1251, Base64, Hex — указывать явно, если не по умолчанию |
| Форматы файлов (если применимо) | CSV (разделитель, кавычки, escape), XML (DTD), JSON (RFC 8259), binary (endianness) |
| Выходные данные | Аналогично — структура, типы, кодировки, форматы |
| Изменения состояния | Какие ресурсы изменяются: запись в БД, кэш, файл, отправка события — с указанием ключей/идентификаторов |
✅ Рекомендация: прикладывать валидные примеры и невалидные (для пояснения ограничений).
❌ Типичная ошибка: описывать бизнес-смысл полей («amount— объём инвестиций»), тогда как нужно: «amount: float64, диапазон [-1e12; 1e12], 2 знака после запятой, обязательное».
Пример оформления:
### 4. Входные и выходные данные
#### 4.1 Источники входных данных
- HTTP-запрос (POST) к эндпоинту `/api/v1/calc/irr` (см. раздел 3);
- Входные данные передаются в теле запроса в формате JSON (RFC 8259);
- Кодировка: UTF-8 без BOM.
#### 4.2 Структура входных данных (JSON Schema Draft-07)
json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": ["cashflow"],
"properties": {
"cashflow": {
"type": "array",
"minItems": 1,
"maxItems": 100,
"items": {
"type": "object",
"required": ["period", "amount"],
"properties": {
"period": {
"type": "integer",
"minimum": 0,
"maximum": 1000
},
"amount": {
"type": "number",
"minimum": -1e12,
"maximum": 1e12,
"multipleOf": 0.01
}
},
"additionalProperties": false
}
},
"guess": {
"type": "number",
"minimum": 0.0,
"maximum": 1.0
}
},
"additionalProperties": false
}
#### 4.3 Примеры
##### Валидный запрос:
json
{
"cashflow": [
{"period": 0, "amount": -500000.00},
{"period": 1, "amount": 200000.00},
{"period": 2, "amount": 350000.00}
],
"guess": 0.15
}
##### Невалидный запрос (ошибка: неуникальный period):
json
{
"cashflow": [
{"period": 0, "amount": -100000},
{"period": 1, "amount": 50000},
{"period": 1, "amount": 60000} ← дубликат
]
}
→ Возвращается код 400 с ошибкой "DUPLICATE_PERIOD".
#### 4.4 Выходные данные
| Поле | Тип | Описание | Ограничения |
|------|-----|-----------|--------------|
| `irr` | number | Рассчитанное значение IRR | ∈ [–1; 1], 4 знака после запятой |
| `iterations` | integer | Число итераций метода Ньютона | ≥ 1, ≤ 1000 |
| `converged` | boolean | Сходимость достигнута | `true`/`false` |
| `warning` | string | (опционально) предупреждение | max 256 символов, UTF-8 |
> ⚠ Примечание: при `converged: false` поле `irr` содержит последнее приближение (не гарантируется корректность).
#### 4.5 Изменения состояния
- Логирование операции в `calc_log` (таблица в PostgreSQL):
- `req_id UUID NOT NULL`
- `user_id TEXT` (из JWT.claims.sub)
- `duration_ns BIGINT`
- `status TEXT` (`ok`, `input_error`, `timeout`, `diverge`)
- При `status = 'diverge'` — инкремент счётчика `diverge_counter` в Redis (`INCR calc:diverge:2025-11`).
Шаг 6. Раздел «Сообщения»
🔍 Смысл раздела (п. 2.5 ГОСТ):
«Тексты сообщений, выдаваемых программисту или оператору в ходе выполнения программы, описание их содержания и действий, которые необходимо предпринять по этим сообщениям».
⚠ Важно:
- «программисту или оператору» означает — любые диагностические сообщения, включая логи, HTTP-ошибки, CLI-вывод, алерты.
- Нужно разделять:
- Информационные (
INFO,DEBUG) - Предупреждения (
WARN) - Ошибки (
ERROR,FATAL)
- Информационные (
Для каждой категории — указать:
- Код/идентификатор (рекомендуется)
- Текст (точный, включая параметры в шаблоне)
- Условие возникновения
- Рекомендуемое действие
Пример оформления:
### 5. Сообщения
| Код | Уровень | Текст | Условие | Действие |
|-----|---------|-------|---------|----------|
| `CALC-001` | INFO | `Request {req_id} started. user={user_id}, cashflow_len={len}` | Начало обработки запроса | — |
| `CALC-002` | DEBUG | `Newton iteration {i}: x={x:.6f}, f(x)={fx:.3e}` | Включён `log_level=DEBUG` | Только для отладки; не в проде |
| `CALC-003` | WARN | `Fallback to in-memory cache: Redis unavailable (err={err})` | Таймаут подключения к Redis > 3 с | Проверить сетевую доступность Redis; кэш ограничен — возможна деградация |
| `CALC-004` | ERROR | `Input validation failed: {detail}` | Нарушение условий JSON Schema | Исправить клиентский запрос; проверить `X-Request-ID` в логах |
| `CALC-005` | ERROR | `Divergence after {n} iterations. guess={g}, last_irr={irr}` | Метод не сошёлся за 1000 итераций | Увеличить `guess` ближе к ожидаемому значению; или использовать `npv=0` для подбора вручную |
| `CALC-006` | FATAL | `Critical: Vault token expired. Cannot fetch decryption key.` | Vault возвращает 403 на `/transit/decrypt` | Перезапустить sidecar `vault-agent`; проверить lease duration |
> 📌 Все сообщения экспортируются в JSON-лог с полем `"msg_code": "CALC-004"`.
> 📌 Коды используют префикс `CALC-` + трёхзначный номер → легко фильтровать в SIEM.
4. Пример вымышленной системы: X-Core — Финансовый калькулятор
Ниже — фрагменты Руководства программиста для модуля calc-engine, оформленные строго по ГОСТ 19.504-79, без «воды», с фокусом на техническую реализуемость.
💡 Обратите внимание: в реальной практике такой документ может занимать 15–30 страниц. Приведены ключевые разделы — то, что реально используют при интеграции.
📄 Руководство программиста
Модуль: calc-engine (версия 2.3.1)
Система: X-Core
Дата: 11.11.2025
Разработчик: Тагиров Т.В.
Утверждено: Архитектурный комитет, протокол № 47 от 05.11.2025
1. Назначение и условия применения программ
1.1 Назначение
Программа calc-engine реализует численные методы расчёта финансовых показателей (IRR, NPV) для инвестиционных проектов. Предоставляет stateless REST API для сервисов user-portal и reporting.
1.2 Условия применения
| Категория | Требование |
|---|---|
| ОЗУ | ≥ 1 ГБ (реком.: 2 ГБ) |
| CPU | 2 ядра x86-64 (частота ≥ 2.4 ГГц) |
| ОС | Linux (ядра ≥ 5.4); не поддерживает Windows/macOS |
| Среда | Python 3.10+, numpy==1.24.3, scipy==1.10.1, gunicorn==21.2.0 |
| Зависимости | PostgreSQL 14+ (calc_log), Redis 6.2+ (cache), Vault 1.12+ (keys) |
| Сеть | Доступ к redis:6379, vault:8200, pg:5432; outbound HTTPS для метрик |
2. Характеристика программы
2.1 Режим работы
- Интерактивный, запрос–ответ;
- Поддержка до 200 concurrent-соединений (
gunicorn --workers=4 --threads=50); - Horizontally scalable: stateless → можно деплоить N реплик.
2.2 Временные характеристики
| Размер потока | P50 (мс) | P95 (мс) | P99 (мс) |
|---|---|---|---|
| 10 периодов | 8.2 | 14.1 | 19.7 |
| 50 периодов | 42.6 | 88.3 | 120.4 |
| 100 периодов | 163.9 | 211.5 | 302.8 |
📊 Замеры:
k6(1000 VUs, 30s), сервер: 4 vCPU, 8 ГБ RAM, NVMe. Алгоритм: Ньютон–Рафсон с fallback на бисекцию.
2.3 Средства контроля
- Health-check:
GET /healthz→{ "status": "ok", "deps": { "redis": true } } - Метрики:
calc_duration_seconds,calc_error_total{code}(экспорт в Prometheus) - Логи: JSON,
ts,level,req_id,msg_code,duration_ms - Circuit breaker: после 5 ошибок
CALC-005подряд — возврат 503 на 30 с.
3. Обращение к программе
3.1 REST API (/api/v1/calc)
| Эндпоинт | Метод | Описание |
|---|---|---|
/irr | POST | Расчёт IRR |
/npv | POST | Расчёт NPV при заданной ставке |
Заголовки:
- Обязательно:
Content-Type: application/json,Authorization: Bearer <JWT> - Рекомендуется:
X-Request-ID(генерируется клиентом)
См. полную OpenAPI-спецификацию в docs/openapi/calc-engine.v2.yaml.
4. Входные и выходные данные — см. пример выше (раздел 4).
5. Сообщения — см. таблицу выше (раздел 5).
5. Чек-лист: Проверка Руководства программиста перед утверждением
Используйте этот список при ревью. Достаточно одного «Нет» — документ требует доработки.
| № | Критерий | Да / Нет | Комментарий |
|---|---|---|---|
| 1 | Есть аннотация (назначение, версия, ответственные)? | ||
| 2 | Есть содержание с правильной нумерацией? | ||
| 3 | Раздел 1: указаны точные требования к среде («RAM ≥ 1 ГБ»)? | ||
| 4 | Раздел 2: есть измеренные временные характеристики (не «быстро»)? | ||
| 5 | Раздел 3: есть полный контракт вызова (метод, заголовки, тело, коды ответа)? | ||
| 6 | Раздел 4: есть валидный пример входных/выходных данных? | ||
| 7 | Раздел 4: указаны ограничения на поля (диапазон, длина, формат)? | ||
| 8 | Раздел 5: каждое сообщение имеет код, точный текст, условие, действие? | ||
| 9 | Все примеры воспроизводимы (можно скопировать в Postman и получить ответ)? | ||
| 10 | Нет упоминаний внутренней реализации («функция сначала проверяет…»)? | ||
| 11 | Нет расплывчатых формулировок («высокая надёжность», «гибкая настройка»)? | ||
| 12 | Документ соответствует ГОСТ 19.105-78 по оформлению (шрифты, поля, заголовки)? |
📌 Рекомендуется: прогонять документ через peer review с участием как минимум одного разработчика и одного техписателя.
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Техническое письмо - это когда мы объясняем сложную штуку (кнопки, код, болты, законы) так, чтобы другой человек понял её с первого раза и не накосячил. Документация — это совокупность документов, созданных для описания, объяснения, сопровождения или управления продуктом, системой, процессом или проектом. Её целью является обеспечение понимания,… В традиционной инженерной практике (особенно в машиностроении, энергетике, оборонке) эксплуатационная документация — это часть конструкторской документации, регламентированная стандартами, такими как… В крупных корпорациях и регулируемых отраслях (финансы, здравоохранение, энергетика) документация — это требование compliance. Аудиторы, регуляторы, внутренние контролёры требуют полной… Хорошая документация — это та, которую не нужно объяснять устно. Если команда постоянно уточняет — А в документе это имеется в виду так-то? — значит, документация недостаточно ясна. Архитектура документации — это целенаправленное проектирование структуры, содержания, форматов, потоков и взаимосвязей всех документов, сопровождающих продукт или систему на всех этапах её жизненного… Markdown Extra — используется в некоторых генераторах (например, в MkDocs) для расширенных возможностей. Паттерны стиля возникают как реакция на хаос. В отсутствие общих ориентиров коммуникация распадается — одни разработчики пишут код с магическими числами и без комментариев, другие — с избыточной… Техническое задание (ТЗ) — это документ, в котором заказчик и исполнитель договорились о правилах игры до того, как кто-то начал что-то делать. Спецификация - это список всех деталей и инструкций к ним, которые входят в поставку программы. Опись того, за что платят и что получают. ПМИ - это документ, в котором написано, как будут проверять, работает ли программа так, как надо. 📌 Если используется open-source компонент — указать — название, версия, - лицензия (MIT, Apache 2.0, GPL-3 и т.п.), - источник (GitHub URL, релиз).Техническое письмо
Документация
Виды документации
Технический писатель
Качество документации
Архитектура документации
Экосистема технического письма
Стилевые паттерны технической документации
Техническое задание по ГОСТ
Спецификация по ГОСТ
ПМИ по ГОСТ
ПЗ по ГОСТ