type: standard
aspect: format
title: "Стандарт стиля кода"
version: 1.0.0
date: 2026-02-19
status: active
Правила форматирования и стиля для Python, JavaScript, TypeScript, Bash.
# ✅ Правильно (читабельно)
user_count = get_active_users().count()
# ❌ Неправильно (слишком кратко)
n = db.u.a().c()
# ✅ Правильно (явно)
from datetime import datetime
now = datetime.now()
# ❌ Неправильно (неявно)
from datetime import *
now = now()
Следуем стандартам языка:
- Python → PEP 8
- JavaScript → Airbnb Style Guide
- TypeScript → TypeScript Style Guide
- Bash → Google Shell Style Guide
Отступы:
- 4 пробела (не табы)
- Никогда не смешивать табы и пробелы
Длина строки:
- Максимум 88 символов (Black formatter)
- Для docstring и комментариев: 72 символа
Пустые строки:
- 2 пустые строки между функциями верхнего уровня
- 2 пустые строки между классами
- 1 пустая строка между методами класса
Кавычки:
- Двойные " для строк (не одинарные)
- Docstring всегда тройные двойные """
Переменные и функции: snake_case
user_name = "Ivan"
order_count = 10
def get_user_by_id(user_id):
pass
Классы: PascalCase
class UserManager:
pass
class OrderProcessor:
pass
Константы: UPPER_SNAKE_CASE
MAX_RETRIES = 3
API_TIMEOUT = 30
DATABASE_URL = "postgresql://..."
Приватные: префикс _
class User:
def __init__(self):
self._password = None # приватный атрибут
def _hash_password(self): # приватный метод
pass
Магические методы: __double_underscore__
def __init__(self):
pass
def __str__(self):
pass
Порядок:
# 1. Стандартная библиотека
import os
import sys
from datetime import datetime
# 2. Сторонние библиотеки
import requests
from flask import Flask
# 3. Локальные модули
from library.connectors.api.ozon import OzonClient
from projects.pirotehnika.data import Product
Правила:
- Каждый импорт на отдельной строке
- Сортировка по алфавиту внутри группы
- Абсолютные импорты (не относительные для библиотек)
Правильно:
import os
import sys
Неправильно:
import os, sys # не на одной строке
Обязательно для всех функций:
from typing import List, Dict, Optional
def get_users(limit: int = 10) -> List[Dict[str, str]]:
"""Получить список пользователей."""
return []
def find_user(user_id: int) -> Optional[Dict]:
"""Найти пользователя по ID."""
return None
Для переменных (если тип неочевиден):
users: List[User] = []
config: Dict[str, Any] = {}
user: Optional[User] = None
Формат: Google Style
def sync_orders(
api_key: str,
date_from: str,
limit: int = 100
) -> Dict[str, int]:
"""
Синхронизировать заказы из OZON API.
Args:
api_key: API ключ OZON
date_from: Дата начала в формате YYYY-MM-DD
limit: Максимальное количество заказов (по умолчанию 100)
Returns:
Словарь со статистикой:
- total: общее количество заказов
- new: новые заказы
- updated: обновлённые заказы
Raises:
ValueError: Если date_from в неправильном формате
APIError: Если API вернул ошибку
Examples:
>>> result = sync_orders("key123", "2026-02-01")
>>> print(result['total'])
150
"""
pass
Для модулей:
"""
Модуль для работы с OZON API.
Основные компоненты:
- OzonClient: клиент для взаимодействия с API
- sync_orders: синхронизация заказов
- sync_products: синхронизация товаров
"""
Используем Black:
# Установка
pip install black
# Форматирование
black file.py
black directory/
# Проверка (без изменений)
black --check file.py
Настройка (pyproject.toml):
[tool.black]
line-length = 88
target-version = ['py39', 'py310', 'py311']
include = '\.pyi?$'
Линтер: ruff (быстрее pylint/flake8)
# Установка
pip install ruff
# Проверка
ruff check .
# Автофикс
ruff check --fix .
Настройка (.ruff.toml):
line-length = 88
target-version = "py39"
[lint]
select = ["E", "F", "W", "I", "N"]
ignore = ["E501"] # line too long (black handles)
Отступы:
- 2 пробела (не 4, не табы)
Длина строки:
- Максимум 100 символов
Точка с запятой:
- Обязательна (не полагаемся на ASI)
Кавычки:
- Одинарные ' для строк
- **Обратные ` для template strings
Переменные и функции: camelCase
const userName = 'Ivan';
const orderCount = 10;
function getUserById(userId) {
// ...
}
Классы: PascalCase
class UserManager {
// ...
}
class OrderProcessor {
// ...
}
Константы: UPPER_SNAKE_CASE
const MAX_RETRIES = 3;
const API_TIMEOUT = 30;
Приватные поля (TypeScript/ES2022): префикс #
class User {
#password;
#hashPassword() {
// ...
}
}
Используем:
// ✅ const/let (не var)
const users = [];
let count = 0;
// ✅ Arrow functions
const double = (x) => x * 2;
// ✅ Template strings
const message = `Hello, ${userName}!`;
// ✅ Destructuring
const { name, age } = user;
const [first, second] = items;
// ✅ Spread operator
const newArray = [...oldArray, newItem];
const newObject = { ...oldObject, newField: value };
// ✅ Optional chaining
const city = user?.address?.city;
// ✅ Nullish coalescing
const name = user.name ?? 'Guest';
НЕ используем:
// ❌ var
var count = 0;
// ❌ function вместо arrow (для коротких функций)
const double = function(x) { return x * 2; };
// ❌ Конкатенация строк
const message = 'Hello, ' + userName + '!';
Обязательно для всех функций:
function getUsers(limit: number = 10): User[] {
return [];
}
function findUser(userId: number): User | null {
return null;
}
async function syncOrders(apiKey: string): Promise<SyncResult> {
// ...
}
Интерфейсы вместо типов (где возможно):
// ✅ Правильно
interface User {
id: number;
name: string;
email: string;
}
// ⚠️ Использовать только для union/intersection
type Status = 'pending' | 'active' | 'completed';
Настройка (.prettierrc):
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"printWidth": 100,
"trailingComma": "es5",
"arrowParens": "always"
}
Настройка (.eslintrc.js):
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
rules: {
'no-console': 'warn',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/explicit-function-return-type': 'warn'
}
};
Отступы:
- 2 пробела (не табы)
Длина строки:
- Максимум 80 символов
- Длинные команды разбивать с \
Shebang:
#!/bin/bash
Переменные: snake_case
user_name="Ivan"
order_count=10
Константы: UPPER_SNAKE_CASE
readonly MAX_RETRIES=3
readonly API_TIMEOUT=30
Функции: snake_case
get_user_by_id() {
local user_id=$1
# ...
}
Всегда кавычки для переменных:
# ✅ Правильно
echo "User: $user_name"
cp "$source_file" "$dest_file"
# ❌ Неправильно (проблемы с пробелами)
echo User: $user_name
cp $source_file $dest_file
Двойные " vs одинарные ':
# Двойные — подстановка переменных
echo "Hello, $name" # Hello, Ivan
# Одинарные — литерал
echo 'Hello, $name' # Hello, $name
Используем [[ ]] (не [ ]):
# ✅ Правильно
if [[ -f "$file" ]]; then
echo "File exists"
fi
if [[ "$status" == "active" ]]; then
echo "Active"
fi
# ❌ Неправильно
if [ -f $file ]; then # проблемы с пробелами
echo "File exists"
fi
Объявление:
# ✅ Правильно
function backup_database() {
local db_name=$1
local backup_dir=$2
# Проверка аргументов
if [[ -z "$db_name" ]]; then
echo "Error: db_name required"
return 1
fi
# Логика бэкапа
echo "Backing up $db_name to $backup_dir"
}
# ❌ Неправильно (без local)
backup_database() {
db_name=$1 # глобальная переменная!
}
Вызов:
backup_database "mydb" "/backups"
set -e / set -u:
#!/bin/bash
set -e # остановиться при ошибке
set -u # ошибка при неопределённой переменной
set -o pipefail # ошибка в pipeline
# Альтернатива: одной строкой
set -euo pipefail
Проверка кода возврата:
# ✅ Правильно
if command; then
echo "Success"
else
echo "Failed"
exit 1
fi
# Или
command || { echo "Failed"; exit 1; }
Заголовок скрипта:
#!/bin/bash
#
# backup.sh — резервное копирование базы данных
#
# Использование:
# ./backup.sh DATABASE_NAME BACKUP_DIR
#
# Примеры:
# ./backup.sh mydb /backups
#
# Автор: architect
# Дата: 2026-02-19
Комментарии функций:
# Создать резервную копию базы данных
#
# Args:
# $1 - имя базы данных
# $2 - директория для бэкапа
#
# Returns:
# 0 если успех, 1 если ошибка
function backup_database() {
# ...
}
# Установка
apt-get install shellcheck
# Проверка
shellcheck script.sh
| Инструмент | Назначение | Команда |
|---|---|---|
| black | Форматирование | black . |
| ruff | Линтер + автофикс | ruff check --fix . |
| mypy | Проверка типов | mypy . |
| isort | Сортировка импортов | isort . |
| Инструмент | Назначение | Команда |
|---|---|---|
| prettier | Форматирование | prettier --write . |
| eslint | Линтер | eslint --fix . |
| tsc | Проверка типов (TS) | tsc --noEmit |
| Инструмент | Назначение | Команда |
|---|---|---|
| shellcheck | Линтер | shellcheck script.sh |
| shfmt | Форматирование | shfmt -w script.sh |
Автоматическая проверка перед коммитом:
.git/hooks/pre-commit:
#!/bin/bash
set -e
echo "Running code checks..."
# Python
black --check .
ruff check .
# JavaScript/TypeScript
prettier --check .
eslint .
# Bash
find . -name "*.sh" -exec shellcheck {} \;
echo "✓ All checks passed"
chmod +x .git/hooks/pre-commit
"""
Модуль для синхронизации заказов с OZON API.
Основные функции:
- sync_orders: синхронизация всех заказов
- sync_order: синхронизация одного заказа
"""
import logging
from datetime import datetime
from typing import Dict, List, Optional
import requests
from library.connectors.api.ozon import OzonClient
logger = logging.getLogger(__name__)
API_TIMEOUT = 30
MAX_RETRIES = 3
class OrderSyncError(Exception):
"""Ошибка синхронизации заказов."""
pass
def sync_orders(
api_key: str,
date_from: str,
limit: int = 100
) -> Dict[str, int]:
"""
Синхронизировать заказы из OZON API.
Args:
api_key: API ключ OZON
date_from: Дата начала в формате YYYY-MM-DD
limit: Максимальное количество заказов
Returns:
Словарь со статистикой синхронизации
Raises:
OrderSyncError: При ошибке синхронизации
"""
logger.info(f"Syncing orders from {date_from}, limit={limit}")
client = OzonClient(api_key=api_key, timeout=API_TIMEOUT)
try:
orders = client.get_orders(date_from=date_from, limit=limit)
total = len(orders)
new_count = 0
for order in orders:
if _is_new_order(order):
_save_order(order)
new_count += 1
logger.info(f"Synced {total} orders, {new_count} new")
return {
'total': total,
'new': new_count,
'updated': total - new_count
}
except requests.HTTPError as e:
logger.error(f"API error: {e}")
raise OrderSyncError(f"Failed to sync orders: {e}")
def _is_new_order(order: Dict) -> bool:
"""Проверить является ли заказ новым."""
# Логика проверки
return True
def _save_order(order: Dict) -> None:
"""Сохранить заказ в базу."""
# Логика сохранения
pass
/**
* Модуль для работы с пользователями.
*/
interface User {
id: number;
name: string;
email: string;
createdAt: Date;
}
interface CreateUserParams {
name: string;
email: string;
}
/**
* Получить пользователя по ID.
*/
async function getUser(userId: number): Promise<User | null> {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) {
return null;
}
return response.json();
}
/**
* Создать нового пользователя.
*/
async function createUser(params: CreateUserParams): Promise<User> {
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params),
});
if (!response.ok) {
throw new Error('Failed to create user');
}
return response.json();
}
export { User, getUser, createUser };
Версия: 1.0.0
Статус: active
Владелец: architect