← Назад к вопросам
Что делаешь чтобы не допускать ошибок?
1.0 Junior🔥 121 комментариев
#Soft skills и опыт работы#Тестирование
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI30 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Стратегии предотвращения ошибок в production
Это один из самых важных вопросов. Я использую многоуровневый подход — нет одного серебристого пули, но совокупность практик снижает количество bagов на 95%+.
1. Статический анализ кода
Улавливаю ошибки ДО запуска кода.
// .eslintrc.json
{
"extends": "eslint:recommended",
"rules": {
"no-console": "error", // Нет console.log в production
"no-unused-vars": "error", // Мусор в коде
"prefer-const": "error", // let -> const где возможно
"eqeqeq": "error", // === вместо ==
"no-implicit-globals": "error", // Защита от глобальных переменных
"no-eval": "error" // Никогда eval
}
}
// TypeScript strict mode
// tsconfig.json
{
"compilerOptions": {
"strict": true, // Всё: strictNullChecks, noImplicitAny, etc.
"noImplicitAny": true, // Тип ДОЛЖЕН быть явным
"noImplicitThis": true, // this должно быть типизировано
"alwaysStrict": true, // use strict
"noUnusedLocals": true, // Удаляем мусор
"noUnusedParameters": true, // Параметры которые не используются
"noImplicitReturns": true, // Все пути возвращают значение
"noFallthroughCasesInSwitch": true // Забытые breaks в switch
}
}
2. Тестирование (TDD)
Пишу тесты ДО кода.
// Пример: TDD подход
// 1. RED — тест падает
describe('PaymentService', () => {
it('should reject payment if amount is negative', async () => {
const service = new PaymentService();
// Этот тест падает, потому что функция ещё не проверяет
expect(async () => {
await service.process(-100);
}).rejects.toThrow('Amount must be positive');
});
it('should process payment with valid amount', async () => {
const service = new PaymentService();
const result = await service.process(100);
expect(result.status).toBe('success');
});
it('should save transaction to database', async () => {
const mockDB = { save: jest.fn() };
const service = new PaymentService(mockDB);
await service.process(100);
expect(mockDB.save).toHaveBeenCalledWith(
expect.objectContaining({
amount: 100,
status: 'completed'
})
);
});
});
// 2. GREEN — минимальный код для прохождения тестов
class PaymentService {
async process(amount) {
// Валидация (из теста #1)
if (amount <= 0) {
throw new Error('Amount must be positive');
}
// Логика обработки платежа
const result = await this.gateway.authorize(amount);
// Сохранение в БД (из теста #3)
if (result.approved) {
await this.db.save({
amount,
status: 'completed',
timestamp: new Date()
});
}
return { status: result.approved ? 'success' : 'failed' };
}
}
// 3. REFACTOR — улучшение кода, тесты остаются зелёными
3. Типизация (TypeScript)
Ослабляю класс багов на компиляции.
// ❌ Без типов — опасно
const createUser = (email, password) => {
// Что если email не строка? Что если password null?
return db.query('INSERT INTO users...');
};
// ✅ С типами — safe
interface CreateUserRequest {
email: string;
password: string;
}
interface User {
id: number;
email: string;
password: string; // hashed
createdAt: Date;
}
const createUser = async (req: CreateUserRequest): Promise<User> => {
if (!isValidEmail(req.email)) {
throw new ValidationError('Invalid email');
}
if (req.password.length < 8) {
throw new ValidationError('Password too short');
}
const hashed = await bcrypt.hash(req.password, 12);
return await db.query('INSERT INTO users...', [req.email, hashed]);
};
// Типизация функций
type AsyncHandler = (req: Request, res: Response) => Promise<void>;
type Middleware = (req: Request, res: Response, next: NextFunction) => void;
// Даже простые утилиты
const sleep = (ms: number): Promise<void> => {
return new Promise(resolve => setTimeout(resolve, ms));
};
4. Лinting на CI/CD
Улавливаю ошибки в pull request.
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm ci
- run: npm run lint # ESLint + Prettier
- run: npm run type-check # TypeScript compiler
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm ci
- run: npm run test:coverage
- uses: codecov/codecov-action@v2 # Coverage report
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm audit # Проверка уязвимостей
- run: npm run security-scan
5. Code Review
Другие люди находят то, что я упустил.
// Пример плохого код review
const comment = `
Высь, большие изменения, сложновато.
`;
// Пример хорошего code review
const comment = `
Проблемы:
1. **Race condition в findOpponent()**: Если два пользователя найдут друг друга одновременно, можно обновить статус дважды.
Решение: SELECT FOR UPDATE SKIP LOCKED
Пример: PR #1423
2. **Memory leak**: Redis ключи не имеют TTL, будут расти бесконечно
Решение: setEx вместо set
3. **Missing error handling**: Если gateway.authorize() отклонит, payment остаётся в неопределённом состоянии
Решение: Транзакция в БД
Плюсы:
+ Отличная архитектура
+ Хорошие тесты (95% coverage)
+ Документацияясная
`;
6. Интеграционное и E2E тестирование
Тестирую целые сценарии.
// Интеграционный тест
describe('Payment Flow', () => {
let app, db, redis;
beforeAll(async () => {
// Реальные сервисы (или mock)
db = await connectToTestDB();
redis = await connectToTestRedis();
app = createApp(db, redis);
});
it('should process complete payment flow', async () => {
// 1. Создаём пользователя
const { body: user } = await request(app)
.post('/users')
.send({ email: 'test@example.com', password: 'Password123' });
// 2. Логинимся
const { body: auth } = await request(app)
.post('/auth/login')
.send({ email: 'test@example.com', password: 'Password123' });
// 3. Создаём платёж
const { body: payment } = await request(app)
.post('/payments')
.set('Authorization', `Bearer ${auth.token}`)
.send({ amount: 100 });
// 4. Проверяем в БД
const savedPayment = await db.query(
'SELECT * FROM payments WHERE id = $1',
[payment.id]
);
expect(savedPayment.status).toBe('completed');
// 5. Проверяем в Redis (кеш)
const cached = await redis.get(`payment:${payment.id}`);
expect(cached).toBeDefined();
});
});
7. Мониторинг в Production
Улавливаю проблемы ЧТО они начинаются.
// Логирование с контекстом
const logger = createLogger();
app.use((req, res, next) => {
const startTime = Date.now();
res.on('finish', () => {
const duration = Date.now() - startTime;
logger.info('HTTP request', {
method: req.method,
path: req.path,
status: res.statusCode,
duration,
userId: req.user?.id,
// Предупреждаем если медленный запрос
level: duration > 1000 ? 'warn' : 'info'
});
// Отправляем в Sentry/DataDog
if (res.statusCode >= 500) {
Sentry.captureException(new Error(`HTTP ${res.statusCode}`));
}
});
next();
});
// Алерты на критичные ошибки
const alertingMiddleware = (error, req, res, next) => {
logger.error('Unhandled error', {
error: error.message,
stack: error.stack,
path: req.path
});
// КРИТИЧНЫЙ ERROR — отправляем алерт в Slack
if (error.message.includes('DATABASE_CONNECTION_FAILED')) {
notifier.sendToSlack(`CRITICAL: DB connection failed!
${error.message}\n<@oncall>`);
}
res.status(500).json({ error: 'Internal error' });
};
8. Валидация входных данных
Никогда не доверяю клиентам.
// Класс для валидации
class ValidationError extends Error {
constructor(message, field) {
super(message);
this.field = field;
}
}
const validateUserInput = (req) => {
const { email, password, age } = req.body;
// Email
if (!email || typeof email !== 'string') {
throw new ValidationError('Email required', 'email');
}
if (!isValidEmail(email)) {
throw new ValidationError('Invalid email format', 'email');
}
// Password
if (!password || typeof password !== 'string') {
throw new ValidationError('Password required', 'password');
}
if (password.length < 8) {
throw new ValidationError('Password too short (min 8)', 'password');
}
// Age
if (age !== undefined) {
if (typeof age !== 'number' || age < 18) {
throw new ValidationError('Must be 18+', 'age');
}
}
return { email, password, age };
};
// Используем с middleware
app.post('/users', (req, res, next) => {
try {
const data = validateUserInput(req);
res.json(createUser(data));
} catch (error) {
if (error instanceof ValidationError) {
res.status(400).json({
field: error.field,
message: error.message
});
} else {
next(error);
}
}
});
9. Дефенсивное программирование
Пишу код как будто он сломается.
// Пример: обработка external API
const getExchangeRate = async (from, to) => {
try {
const response = await fetch(
`https://api.exchange.com/rate/${from}/${to}`,
{ timeout: 5000 }
);
if (!response.ok) {
logger.warn(`Exchange API returned ${response.status}`);
// Fallback на кеширован значение
return await getCachedRate(from, to);
}
const data = await response.json();
// Валидация ответа
if (!data.rate || typeof data.rate !== 'number') {
logger.error('Invalid exchange API response', { data });
return await getCachedRate(from, to);
}
// Сохраняем в кеш
await cache.set(`rate:${from}:${to}`, data.rate, 3600);
return data.rate;
} catch (error) {
logger.error('Exchange API error', { error });
// Fallback
return await getCachedRate(from, to);
}
};
Заключение
Мой подход: многоуровневая защита
- Статический анализ (ESLint, TypeScript)
- Модульные тесты (TDD, jest)
- Интеграционные тесты
- Code review
- CI/CD pipeline
- Мониторинг в production
- Валидация входных данных
- Дефенсивное программирование
Ни один из этих методов не является панацеей, но вместе они создают fortress из качества.