mirror of
https://github.com/goldbergyoni/nodebestpractices.git
synced 2025-10-30 00:57:04 +08:00
Merge pull request #649 from vladthelittleone/master
fix russian translation typos
This commit is contained in:
@ -90,9 +90,9 @@
|
||||
|
||||
## ![✔] 1.4 Разделяйте Express "приложение" и "сервер"
|
||||
|
||||
**TL;DR:** Избегайте неприятной привычки определять все приложение [Express] (https://expressjs.com/) в одном огромном файле -- разделите определение "Экспресс" как минимум на два файла: декларация API (app.js) и сетевые задачи (www). Для еще лучшей структуры локализуйте объявление API в компонентах.
|
||||
**TL;DR:** Избегайте неприятной привычки определять все приложение [Express](https://expressjs.com/) в одном огромном файле -- разделите определение "Экспресс" как минимум на два файла: декларация API (app.js) и сетевые задачи (www). Для еще лучшей структуры локализуйте объявление API в компонентах.
|
||||
|
||||
**Иначе:** Ваш API будет доступен для тестирования только через HTTP-вызовы (медленнее и намного сложнее создавать отчеты о покрытии). Скорее всего, не составит большого труда хранить сотни строк кода в одном файле.
|
||||
**Иначе:** Ваш API будет доступен для тестирования только через HTTP-вызовы (медленнее и намного сложнее создавать отчеты о покрытии). Скорее всего, вы не будете испытывать огромное удовольствие, если будете хранить сотни строк кода в одном файле.
|
||||
|
||||
🔗 [**Подробнее: Разделяйте Express "приложение" и "сервер"**](/sections/projectstructre/separateexpress.russian.md)
|
||||
|
||||
@ -102,7 +102,7 @@
|
||||
|
||||
**TL;DR:** Идеальная и безупречная конфигурация должна обеспечивать (а) считывание ключей из файла И из переменной среды, (б) хранение секретов вне основной кодовой базы, (в) иерархическую структуру для облегчения поиска. Есть несколько пакетов, которые могут помочь поставить галочку в большинстве таких полей, как [rc](https://www.npmjs.com/package/rc), [nconf](https://www.npmjs.com/package/nconf), [config](https://www.npmjs.com/package/config), and [convict](https://www.npmjs.com/package/convict)
|
||||
|
||||
**Иначе:** Невыполнение каких-либо требований к конфигурации приведет к срывам в работе разработчиков или devops командой. Вероятно, и тех и других.
|
||||
**Иначе:** Невыполнение каких-либо требований к конфигурации приведет к срывам в работе разработчиков или devops-команды. А вероятно, и тех и других.
|
||||
|
||||
🔗 [**Подробнее: Используйте конфигурацию с учетом среды, безопасную и иерархическую конфигурацию**](/sections/projectstructre/configguide.russian.md)
|
||||
|
||||
@ -116,7 +116,7 @@
|
||||
|
||||
**TL;DR:** Обработка асинхронных ошибок в стиле обратного вызова, вероятно, является самым быстрым путем в ад (еще говорят "Callback Hell" или "The Pyramid of Doom"). Лучший подарок, который вы можете сделать своему коду, -- это использовать надежную библиотеку обещаний или async-await, что позволяет использовать более компактный и знакомый синтаксис кода, такой как try-catch.
|
||||
|
||||
**Иначе:** Стиль обратного вызова Node.js, функция (err, response), является многообещающим способом создания непригодного для использования кода из-за сочетания обработки ошибок со случайным кодом, чрезмерных вложений и слабых шаблонов кодирования.
|
||||
**Иначе:** Callback-стиль Node.js, function(err, response), является многообещающим способом создания непригодного для использования кода из-за сочетания таких проблем, как обработка ошибок со случайным кодом, чрезмерные вложения и неудобные шаблоны проектирования.
|
||||
|
||||
🔗 [**Подробнее: Используйте Async-Await или обещания для асинхронной обработки ошибок**](/sections/errorhandling/asyncerrorhandling.russian.md)
|
||||
|
||||
@ -132,21 +132,21 @@
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 2.3 Различайте ошибки в работе и программировании
|
||||
## ![✔] 2.3 Различайте операционные ошибки и ошибки программиста
|
||||
|
||||
**TL;DR:** Операционные ошибки (например, API получил неверный ввод) относятся к известным случаям, когда влияние ошибки полностью осознается и может быть обработано вдумчиво. С другой стороны, ошибка программиста (например, попытка прочитать неопределенную переменную) относится к неизвестным ошибкам кода, которые требуют изящного перезапуска приложения.
|
||||
**TL;DR:** Операционные ошибки (например, API получил неверный ввод) относятся к таким случаям, когда влияние ошибки полностью осознается и может быть обработано вдумчиво. Ошибка программиста (например, попытка прочитать undefined-переменную) относится к неизвестным ошибкам, которые требуют безопасного перезапуска приложения.
|
||||
|
||||
**Иначе:** Вы всегда можете перезапустить приложение, когда появляется ошибка, но зачем подводить ~5000 онлайн-пользователей из-за незначительной, прогнозируемой, операционной ошибки? Обратное также не идеально -- поддержание приложения в том случае, если возникла неизвестная проблема (ошибка программиста), может привести к непредсказуемому поведению. Разграничение между ними позволяет действовать тактично и применять сбалансированный подход, основанный на данном контексте.
|
||||
**Иначе:** Вы всегда можете перезапустить приложение, когда появляется ошибка, но зачем подводить ~5000 онлайн-пользователей из-за незначительной и прогнозируемой операционной ошибки? Обратное также не является идеальным -- отсутствие перезапуска приложения в случае, если возникла неизвестная проблема (ошибка программиста), может привести к непредсказуемому поведению. Понимание типа ошибки позволит действовать тактично и применять сбалансированный подход, основанный на предоставленном контексте.
|
||||
|
||||
🔗 [**Подробнее: Различайте операционные и программистские ошибки**](/sections/errorhandling/operationalvsprogrammererror.russian.md)
|
||||
🔗 [**Подробнее: Различайте операционные ошибки и ошибки программиста**](/sections/errorhandling/operationalvsprogrammererror.russian.md)
|
||||
|
||||
<br/><br/>
|
||||
|
||||
## ![✔] 2.4 Обрабатывате ошибки централизованно, а не в промежуточном слое Express
|
||||
## ![✔] 2.4 Обрабатывате ошибки централизованно, а не в промежуточных обработчиках Express
|
||||
|
||||
**TL;DR:** Логика обработки ошибок, такая как уведомление по почте администратора или ведение журнала, должна быть заключена в выделенный и централизованный объект, который вызывается всеми конечными точками (например, промежуточные слои Express, задания cron, модульное тестирование) при возникновении ошибки.
|
||||
**TL;DR:** Логика обработки ошибок, например, как уведомление по почте администратора или ведение журнала, должна быть инкапсулирована в выделенный и централизованный объект, который вызывается всеми точками входа (обработчиками Express, cron-задачами, юнит-тестами) при возникновении ошибки.
|
||||
|
||||
**Иначе:** Необработка ошибок в одном месте приведет к дублированию кода и, возможно, к ошибкам, обработанным неправильно.
|
||||
**Иначе:** Отсутствие обработки ошибок в едином месте приведет к дублированию кода и, возможно, к неверной обработке ошибок.
|
||||
|
||||
🔗 [**Подробнее: Обрабатывайте ошибки централизованно. Не в промежуточных слоях**](/sections/errorhandling/centralizedhandling.russian.md)
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
### Объяснение в один абзац
|
||||
|
||||
Обратные вызовы плохо масштабируются, так как большинство программистов не знакомы с ними. Они заставляют проверять ошибки повсюду, имеют дело с неприятным вложением кода и затрудняют анализ потока кода. Библиотеки Promise, такие как BlueBird, async и Q, упаковывают стандартный стиль кода, используя RETURN и THROW для управления потоком программы. В частности, они поддерживают любимый стиль обработки ошибок try-catch, который позволяет освободить путь к основному коду от ошибок в каждой функции
|
||||
Обратные вызовы плохо масштабируются, так как большинство программистов не знакомы с ними. Они заставляют проверять ошибки повсюду, иметь дело с неприятной вложенностью кода и затрудняют анализ потока кода. Библиотеки обещаний (promise), такие как BlueBird, async и Q, упаковывают стандартный стиль кода, используя RETURN и THROW для управления потоком программы. В частности, они поддерживают наилучший стиль обработки ошибок try-catch, который позволяет освободить основной код от обработки ошибок в каждой функции.
|
||||
|
||||
### Пример кода – использование обещаний для отлова ошибок
|
||||
|
||||
@ -15,7 +15,6 @@ return functionA()
|
||||
.then(alwaysExecuteThisFunction)
|
||||
```
|
||||
|
||||
|
||||
### Пример кода - использование async/await для отлова ошибок
|
||||
|
||||
```javascript
|
||||
@ -34,7 +33,7 @@ async function executeAsyncTask () {
|
||||
}
|
||||
```
|
||||
|
||||
### Антипаттерн. Обработка ошибок в стиле обратного вызова
|
||||
### Антипаттерн. Обработка ошибок в callback-стиле
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
@ -42,14 +41,14 @@ async function executeAsyncTask () {
|
||||
```javascript
|
||||
getData(someParameter, function(err, result) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
// вызываем коллбек функцию и передаем ошибку
|
||||
getMoreData(a, function(err, result) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
// вызываем коллбек функцию и передаем ошибку
|
||||
getMoreData(b, function(c) {
|
||||
getMoreData(d, function(e) {
|
||||
if(err !== null ) {
|
||||
// you get the idea?
|
||||
// вы поняли идею?
|
||||
}
|
||||
})
|
||||
});
|
||||
@ -66,14 +65,14 @@ getData(someParameter, function(err, result) {
|
||||
```typescript
|
||||
getData(someParameter, function(err: Error | null, resultA: ResultA) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
// вызываем коллбек функцию и передаем ошибку
|
||||
getMoreData(resultA, function(err: Error | null, resultB: ResultB) {
|
||||
if(err !== null) {
|
||||
// do something like calling the given callback function and pass the error
|
||||
// вызываем коллбек функцию и передаем ошибку
|
||||
getMoreData(resultB, function(resultC: ResultC) {
|
||||
getMoreData(resultC, function(err: Error | null, d: ResultD) {
|
||||
if(err !== null) {
|
||||
// you get the idea?
|
||||
// вы поняли идею?
|
||||
}
|
||||
})
|
||||
});
|
||||
@ -90,20 +89,20 @@ getData(someParameter, function(err: Error | null, resultA: ResultA) {
|
||||
|
||||
> … На самом деле, обратные вызовы делают что-то еще более зловещее: они лишают нас стека, что мы обычно принимаем как должное в языках программирования. Написание кода без стека очень похоже на вождение автомобиля без педали тормоза: вы не понимаете, насколько сильно оно вам нужно, пока не дойдете до него, а его там нет. Весь смысл обещаний состоит в том, чтобы вернуть нам языковые основы, которые мы потеряли при асинхронности: возврат, выброс и стек. Но вы должны знать, как правильно использовать обещания, чтобы воспользоваться ими.
|
||||
|
||||
### Цитата блога: "Метод обещаний гораздо более компактен"
|
||||
### Цитата блога: "Подход с обещаниями гораздо более компактен"
|
||||
|
||||
Из блога gosquared.com
|
||||
|
||||
> … Метод обещаний гораздо компактнее, понятнее и быстрее для написания. Если ошибка или исключение происходят в любом из операций, они обрабатываются одним обработчиком .catch(). Наличие единого места для обработки всех ошибок означает, что вам не нужно писать проверку ошибок для каждого этапа работы.
|
||||
> … Подход с обещаниями гораздо компактнее, понятнее и быстрее для написания. Если ошибка или исключение происходят в любой из операций, они обрабатываются одним обработчиком .catch(). Наличие единого места для обработки всех ошибок означает, что вам не нужно писать проверку ошибок для каждого этапа работы.
|
||||
|
||||
### Цитата блога: "Обещания являются родными ES6, могут использоваться с генераторами"
|
||||
### Цитата блога: "Обещания являются нативными в ES6, могут использоваться с генераторами"
|
||||
|
||||
Из блога StrongLoop
|
||||
|
||||
> … Обратные вызовы имеют паршивую историю обработки ошибок. Обещания лучше. Объедините встроенную обработку ошибок в Express с обещаниями и значительно снизьте вероятность возникновения необработанного исключения. Обещания являются родными ES6, могут использоваться с генераторами, а предложения ES7, такие как async/await, через компиляторы, такие как Babel.
|
||||
> … Обратные вызовы имеют паршивую историю обработки ошибок. Обещания лучше. Объедините встроенную обработку ошибок в Express с обещаниями и значительно снизьте вероятность возникновения необработанного исключения. Обещания являются нативными в ES6, могут использоваться с генераторами, а proposals из ES7, такие как async/await, могут использоваться через компиляторы, такие как Babel.
|
||||
|
||||
### Цитата из блога: "Все те обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены"
|
||||
|
||||
Из блога Бенно
|
||||
|
||||
> … Одно из лучших преимуществ асинхронного программирования на основе обратного вызова состоит в том, что в основном все эти обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены. Тем не менее, я считаю, что больше всего разрушения коснулись обработки исключений. Javascript предоставляет довольно знакомую конструкцию try…catch для работы с исключениями. Проблема с исключениями состоит в том, что они обеспечивают отличный способ сокращения ошибок в стеке вызовов, но в конечном итоге оказываются совершенно бесполезными, если ошибка происходит в другом стеке…
|
||||
> … Одно из лучших преимуществ асинхронного программирования на основе обратного вызова состоит в том, что в основном все эти обычные конструкции управления потоком, к которым вы привыкли, полностью разрушены. Тем не менее, я считаю, что больше всего разрушения коснулась обработка исключений. Javascript предоставляет довольно знакомую конструкцию try…catch для работы с исключениями. Проблема с исключениями состоит в том, что они обеспечивают отличный способ сокращения ошибок в стеке вызовов, но в конечном итоге оказываются совершенно бесполезными, если ошибка происходит в другом стеке…
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
### Объяснение в один абзац
|
||||
|
||||
Без специального выделенного объекта для обработки ошибок больше шансов на то, что важные ошибки скрываются под радаром из-за неправильного обращения. Объект обработчика ошибок отвечает за отображение ошибки, например, путем записи в хорошо отформатированный регистратор, отправки событий в некоторые продукты мониторинга, такие как [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/) или [Raygun](https://raygun.com/). Большинство веб-фреймворков, таких как [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), предоставляют механизм промежуточного программного обеспечения для обработки ошибок. Типичный поток обработки ошибок может быть следующим: какой-то модуль выдает ошибку -> маршрутизатор API перехватывает ошибку -> он передает ошибку промежуточному программному обеспечению (например, Express, KOA), которое отвечает за перехват ошибок -> вызывается централизованный обработчик ошибок -> промежуточному программному обеспечению сообщается, является ли эта ошибка ненадежной (не работающей), чтобы она могла корректно перезапустить приложение. Обратите внимание, что обычная, но неправильная практика - обрабатывать ошибки в промежуточном программном обеспечении Express - это не распространяется на ошибки, возникающие в не-веб-интерфейсах.
|
||||
Без выделенного объекта для обработки ошибок есть больше шансов на то, что ошибки потеряются с радара из-за их неправильной обработки. Объект обработчика ошибок отвечает за отображение ошибки, например, путем записи в логгер, отправки событий в сервисы мониторинга, такие как [Sentry](https://sentry.io/), [Rollbar](https://rollbar.com/) или [Raygun](https://raygun.com/). Большинство веб-фреймворков, таких как [Express](http://expressjs.com/en/guide/error-handling.html#writing-error-handlers), предоставляют механизм обработки ошибок с помощью функций промежуточной обработки (**middlewares**). Типичный поток обработки ошибок может выглядеть следующим образом: какой-то модуль выдает ошибку -> API-маршрутизатор перехватывает ошибку -> он передает ошибку функции промежуточной обработки (Express, KOA), которая отвечает за перехват ошибок -> вызывается централизованный обработчик ошибок -> функции промежуточной обработки передается информация о том, что является ли эта ошибка ненадежной (необрабатываемой), чтобы она могла корректно перезапустить приложение. Обратите внимание, что обычная, но неправильная практика - обрабатывать ошибки в функции промежуточной обработки Express - это не распространяется на ошибки, возникающие в не-веб-интерфейсах.
|
||||
|
||||
### Пример кода - типичный поток ошибок
|
||||
|
||||
@ -10,13 +10,14 @@
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// DAL layer, we don't handle errors here
|
||||
// DAL-слой, мы не обрабатываем ошибки тут
|
||||
DB.addDocument(newCustomer, (error, result) => {
|
||||
if (error)
|
||||
throw new Error('Great error explanation comes here', other useful parameters)
|
||||
});
|
||||
|
||||
// API route code, we catch both sync and async errors and forward to the middleware
|
||||
// код API-маршрутизатора, мы обрабатываем как sync
|
||||
// так и async ошибки и переходим к middleware
|
||||
try {
|
||||
customerService.addNew(req.body).then((result) => {
|
||||
res.status(200).json(result);
|
||||
@ -28,7 +29,7 @@ catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
// Error handling middleware, we delegate the handling to the centralized error handler
|
||||
// Обработка ошибок в middleware, мы делегируем обработку централизованному обработчику ошибок
|
||||
app.use(async (err, req, res, next) => {
|
||||
const isOperationalError = await errorHandler.handleError(err);
|
||||
if (!isOperationalError) {
|
||||
@ -42,13 +43,14 @@ app.use(async (err, req, res, next) => {
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// DAL layer, we don't handle errors here
|
||||
// DAL-слой, мы не обрабатываем ошибки тут
|
||||
DB.addDocument(newCustomer, (error: Error, result: Result) => {
|
||||
if (error)
|
||||
throw new Error('Great error explanation comes here', other useful parameters)
|
||||
});
|
||||
|
||||
// API route code, we catch both sync and async errors and forward to the middleware
|
||||
// код API-маршрутизатора, мы обрабатываем как sync
|
||||
// так и async ошибки и переходим к middleware
|
||||
try {
|
||||
customerService.addNew(req.body).then((result: Result) => {
|
||||
res.status(200).json(result);
|
||||
@ -60,7 +62,7 @@ catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
// Error handling middleware, we delegate the handling to the centralized error handler
|
||||
// Обработка ошибок в middleware, мы делегируем обработку централизованному обработчику ошибок
|
||||
app.use(async (err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
const isOperationalError = await errorHandler.handleError(err);
|
||||
if (!isOperationalError) {
|
||||
@ -82,9 +84,9 @@ module.exports.handler = new errorHandler();
|
||||
function errorHandler() {
|
||||
this.handleError = async (err) {
|
||||
await logger.logError(err);
|
||||
await sendMailToAdminIfCritical;
|
||||
await saveInOpsQueueIfCritical;
|
||||
await determineIfOperationalError;
|
||||
await sendMailToAdminIfCritical(err);
|
||||
await saveInOpsQueueIfCritical(err);
|
||||
await determineIfOperationalError(err);
|
||||
};
|
||||
}
|
||||
```
|
||||
@ -97,9 +99,9 @@ function errorHandler() {
|
||||
class ErrorHandler {
|
||||
public async handleError(err: Error): Promise<void> {
|
||||
await logger.logError(err);
|
||||
await sendMailToAdminIfCritical();
|
||||
await saveInOpsQueueIfCritical();
|
||||
await determineIfOperationalError();
|
||||
await sendMailToAdminIfCritical(err);
|
||||
await saveInOpsQueueIfCritical(err);
|
||||
await determineIfOperationalError(err);
|
||||
};
|
||||
}
|
||||
|
||||
@ -108,13 +110,14 @@ export const handler = new ErrorHandler();
|
||||
</details>
|
||||
|
||||
|
||||
### Пример кода - антипаттерн: обработка ошибок в промежуточном программном обеспечении
|
||||
### Пример кода - антипаттерн: обработка ошибок в middleware
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// middleware handling the error directly, who will handle Cron jobs and testing errors?
|
||||
// middleware, обрабатывающий ошибки напрямую.
|
||||
// А кто будет обрабатывать ошибки возникшие в Cron или при юнит-тестировании?
|
||||
app.use((err, req, res, next) => {
|
||||
logger.logError(err);
|
||||
if (err.severity == errors.high) {
|
||||
@ -132,7 +135,8 @@ app.use((err, req, res, next) => {
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// middleware handling the error directly, who will handle Cron jobs and testing errors?
|
||||
// middleware, обрабатывающий ошибки напрямую.
|
||||
// А кто будет обрабатывать ошибки возникшие в Cron или при юнит-тестировании?
|
||||
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
logger.logError(err);
|
||||
if (err.severity == errors.high) {
|
||||
@ -145,20 +149,20 @@ app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
||||
```
|
||||
</details>
|
||||
|
||||
### Цитата из блога: "Иногда нижние уровни не могут сделать ничего полезного, кроме как сообщить об ошибке вызывающей стороне"
|
||||
### Цитата из блога: "Иногда нижние слои не могут сделать ничего полезного, кроме как сообщить об ошибке вызывающему слою"
|
||||
|
||||
Из блога Joyent, занимающий 1 место по ключевым словам "Обработка ошибок Node.js"
|
||||
Из блога Joyent, занимающего 1 место по ключевым словам "Обработка ошибок Node.js"
|
||||
|
||||
> … Вы можете обработать одну и ту же ошибку на нескольких уровнях стека. Это происходит, когда нижние уровни не могут сделать ничего полезного, кроме как передать ошибку вызывающей стороне, которая передает ошибку своей вызывающей стороне, и так далее. Зачастую только вызывающий пользователь верхнего уровня знает, что является подходящим ответом: попытка повторить операцию, сообщить пользователю об ошибке или что-то еще. Но это не значит, что вы должны пытаться сообщать обо всех ошибках в один обратный вызов верхнего уровня, потому что сам этот обратный вызов не может знать, в каком контексте произошла ошибка …
|
||||
> … Вы можете обработать одну и ту же ошибку на нескольких слоях. Это происходит, когда нижние слои не могут сделать ничего полезного, кроме как передать ошибку вызывающему слою, который передаст ошибку своему вызывающему слою, и так далее. Зачастую только самый верхний слой знает, что является подходящим действием на ошибку: попытка повторить операцию, сообщить пользователю об ошибке или что-то еще. Но это не значит, что вы должны пытаться сообщать обо всех ошибках в один верхний callback, потому что этот callback не может знать, в каком контексте произошла ошибка …
|
||||
|
||||
### Цитата из блога: "Обработка каждой ошибки по отдельности приведет к огромному дублированию"
|
||||
### Цитата из блога: "Обработка каждой ошибки по отдельности приведет к ужасному дублированию"
|
||||
|
||||
Из блога JS Recipes, занимающий 17 место по ключевым словам "Обработка ошибок Node.js"
|
||||
Из блога JS Recipes, занимающего 17 место по ключевым словам "Обработка ошибок Node.js"
|
||||
|
||||
> … Только в контроллере api.js Hackathon Starter имеется более 79 случаев появления объектов ошибок. Обработка каждой ошибки в отдельности привела бы к огромному количеству дублирования кода. Следующее, что вы можете сделать, это делегировать всю логику обработки ошибок в промежуточное ПО Express …
|
||||
> … Только в контроллере api.js Hackathon Starter имеется более 79 объектов ошибок. Обработка каждой ошибки в отдельности привела бы к ужасному дублированию кода. Следующее, что вы можете сделать, это делегировать всю логику обработки ошибок в middleware Express …
|
||||
|
||||
### Цитата из блога: "В коде вашей базы данных нет места ошибкам HTTP"
|
||||
|
||||
Из блога Daily JS, занимающем 14 место по ключевым словам "Обработка ошибок Node.js"
|
||||
|
||||
> … Вы должны установить полезные свойства в объектах ошибок, но использовать их последовательно. И не пересекайте потоки: в коде вашей базы данных нет места ошибкам HTTP. Или для разработчиков браузеров, ошибки Ajax имеют место в коде, который общается с сервером, но не в коде, который обрабатывает шаблоны усов …
|
||||
> … Вы должны добавлять полезные свойства в объекты ошибок, но использовать их согласовано. И не пересекайте логику: в коде вашей базы данных нет места ошибкам HTTP. Или, например, для frontend-разработчиков, ошибки Ajax имеют место в коде, который общается с сервером, но не в коде, который работает с шаблонами Mustache …
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
# Различайте операционные и программистские ошибки
|
||||
# Различайте операционные ошибки и ошибки программиста
|
||||
|
||||
### Объяснение в один абзац
|
||||
|
||||
Различение следующих двух типов ошибок минимизирует время простоя вашего приложения и помогает избежать сумасшедших ошибок: Операционные ошибки относятся к ситуациям, когда вы понимаете, что произошло, и влияние этого - например, запрос к какой-либо службе HTTP не выполнен из-за проблемы с подключением. С другой стороны, ошибки программиста относятся к случаям, когда вы не знаете, почему, а иногда и откуда возникла ошибка - это может быть какой-то код, который пытался прочитать неопределенное значение или пул соединений с БД, который приводит к утечке памяти. Операционные ошибки относительно легко обрабатываются - обычно достаточно регистрации ошибки. Вещи становятся неприятными, когда появляется ошибка программиста, приложение может быть в несовместимом состоянии, и нет ничего лучше, чем перезапуск изящно.
|
||||
Разделение ошибок на эти два типа минимизирует время простоя вашего приложения и помогает избежать сумасшедших ошибок: операционные ошибки относятся к ситуациям, когда вы понимаете происходящее и влияние ошибки на программу. Например, запрос к какой-нибудь службе HTTP не выполнен из-за проблемы с подключением. С другой стороны, ошибки программиста относятся к случаям, когда вы не знаете, почему, а иногда и откуда возникла ошибка - это может быть какой-то код, который пытался прочитать undefined-значение или код, который использует пул соединений с БД и приводит к утечке памяти. Операционные ошибки относительно легко обрабатываются - обычно достаточно логирования ошибки. Хуже становиться, когда появляется ошибка программиста, приложение может быть в несогласованном состоянии, и все, что вы можете сделать - перезапустить приложение.
|
||||
|
||||
### Пример кода - пометка ошибки как рабочей (доверенной)
|
||||
### Пример кода - помечаем ошибку как операционную (доверенную)
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// marking an error object as operational
|
||||
const myError = new Error('How can I add new product when no value provided?');
|
||||
// помечаем объект ошибки, как операционный
|
||||
const myError = new Error('Как мы можем добавить продукт, если значение не задано?');
|
||||
myError.isOperational = true;
|
||||
|
||||
// or if you're using some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
|
||||
// или, если вы используете централизированную фабрику ошибок (смотрите другие примеры в статье "Используйте только встроенный объект Error")
|
||||
class AppError {
|
||||
constructor (commonType, description, isOperational) {
|
||||
Error.call(this);
|
||||
@ -25,7 +25,7 @@ class AppError {
|
||||
}
|
||||
};
|
||||
|
||||
throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);
|
||||
throw new AppError(errorManagement.commonErrors.InvalidInput, 'Описываем, что произошло', true);
|
||||
|
||||
```
|
||||
</details>
|
||||
@ -34,7 +34,7 @@ throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here wha
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// some centralized error factory (see other examples at the bullet "Use only the built-in Error object")
|
||||
// или, если вы используете централизированную фабрику ошибок (смотрите другие примеры в статье "Используйте только встроенный объект Error")
|
||||
export class AppError extends Error {
|
||||
public readonly commonType: string;
|
||||
public readonly isOperational: boolean;
|
||||
@ -42,7 +42,7 @@ export class AppError extends Error {
|
||||
constructor(commonType: string, description: string, isOperational: boolean) {
|
||||
super(description);
|
||||
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
Object.setPrototypeOf(this, new.target.prototype); // восстанавливаем цепочку прототипов
|
||||
|
||||
this.commonType = commonType;
|
||||
this.isOperational = isOperational;
|
||||
@ -51,7 +51,7 @@ export class AppError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
// marking an error object as operational (true)
|
||||
// помечаем объект ошибки, как операционный (true)
|
||||
throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here what happened', true);
|
||||
|
||||
```
|
||||
@ -59,27 +59,27 @@ throw new AppError(errorManagement.commonErrors.InvalidInput, 'Describe here wha
|
||||
|
||||
### Цитата блога: "Ошибки программиста - это ошибки в программе"
|
||||
|
||||
Из блога Джойент, занявшему 1 место по ключевым словам "Обработка ошибок Node.js"
|
||||
Из блога Джойент, занявшего 1 место по ключевым словам "Обработка ошибок Node.js"
|
||||
|
||||
> … Лучший способ исправить ошибки программиста - это сразу же аварийно завершить работу. Вы должны запустить свои программы, используя перезапуск, который автоматически перезапустит программу в случае сбоя. С перезапуском на месте сбой является самым быстрым способом восстановления надежного сервиса перед лицом временной ошибки программиста …
|
||||
> … Лучший способ исправить ошибки программиста - это сразу же аварийно завершить работу. Вы должны запускать свои программы, используя сервис перезапуска, который автоматически будет перезапускать программу в случае сбоя. Сервис перезапуска является самым простым способом надежного восстановления сервиса при возникновении временной ошибки программиста…
|
||||
|
||||
### Цитата из блога: "Нет безопасного способа уйти, не создав неопределенного хрупкого состояния"
|
||||
### Цитата из блога: "Нет безопасного способа продолжить без возникновения хрупкого undefined-состояния системы"
|
||||
|
||||
Из официальной документации Node.js
|
||||
|
||||
> … По самой природе того, как throw работает в JavaScript, почти никогда не существует способа безопасно "выбрать то, на чем остановился", без утечки ссылок или создания какого-либо другого неопределенного хрупкого состояния. Самый безопасный способ отреагировать на возникшую ошибку - завершить процесс. Конечно, на обычном веб-сервере у вас может быть открыто много подключений, и нет смысла внезапно закрывать их, потому что кто-то еще вызвал ошибку. Лучший подход - отправить ответ об ошибке на запрос, который вызвал ошибку, позволяя остальным завершить работу в обычное время, и прекратить прослушивание новых запросов этого работника.
|
||||
> …По самой природе того, как throw работает в JavaScript, почти всегда нет способа безопасно "начать оттуда, где мы остановились", без утечки ссылок или создания другого undefined-состояния. Самый безопасный способ отреагировать на возникшую ошибку - завершить процесс. Конечно, на обычном веб-сервере у вас может быть открыто много подключений, и нет смысла внезапно закрывать все, потому что кто-то другой выбросил ошибку. Лучший вариант - отправить ответ об ошибке на запрос, который ее вызвал, позволяя остальным завершить работу в удобное время, и после прекратить прослушивание новых запросов в воркере, в котором возникла ошибка.
|
||||
|
||||
### Цитата блога: "В противном случае вы рискуете состоянием вашего приложения"
|
||||
|
||||
Из блога debugable.com, занявшего 3 место по ключевым словам "Node.js uncaught exception"
|
||||
|
||||
> … Итак, если вы действительно не знаете, что делаете, вам следует выполнить постепенный перезапуск службы после получения события исключения "uncaughtException". В противном случае вы рискуете привести к несогласованности состояния вашего приложения или сторонних библиотек, что приведет к всевозможным сумасшедшим ошибкам …
|
||||
> …Итак, если вы действительно не знаете, что делаете, вам следует выполнить постепенный перезапуск службы после получения события исключения "uncaughtException". В противном случае вы рискуете привести к несогласованности состояния вашего приложения или сторонних библиотек, что приведет к всевозможным сумасшедшим ошибкам…
|
||||
|
||||
### Цитата блога: "Есть три школы мысли об обработке ошибок"
|
||||
|
||||
Из блога: JS Recipes
|
||||
|
||||
> … Существует три основных направления работы с ошибками:
|
||||
> …Существует три основных направления работы с ошибками:
|
||||
1. Дайте приложению упасть и перезапустите его.
|
||||
2. Обрабатывайте все возможные ошибоки и никогда не роняйте.
|
||||
3. Сбалансированный подход между двумя предыдущими.
|
||||
2. Обрабатывайте все возможные ошибоки и никогда не роняйте сервис.
|
||||
3. Сбалансированный подход между двумя предыдущими.
|
||||
@ -2,20 +2,20 @@
|
||||
|
||||
### Объяснение в один абзац
|
||||
|
||||
Гибкая природа JavaScript наряду с его разнообразием параметров потока кода (например, EventEmitter, Callbacks, Promises и т.д.) приводит к значительному расхождению в том, как разработчики выдают ошибки - некоторые используют строки, другие определяют свои собственные пользовательские типы. Использование встроенного объекта Error в Node.js помогает сохранить единообразие в вашем коде, а с помощью сторонних библиотек он также сохраняет важную информацию, такую как StackTrace. При возникновении исключения обычно рекомендуется заполнить его дополнительными контекстными свойствами, такими как имя ошибки и связанный код ошибки HTTP. Чтобы добиться этого единообразия и практики, рассмотрите возможность расширения объекта Error дополнительными свойствами, см. пример кода ниже.
|
||||
Гибкая природа JavaScript наряду с его разнообразием вариантов потока кода (например, EventEmitter, Callbacks, Promises и т.д.) приводит к значительному расхождению в том, как разработчики выдают ошибки - некоторые используют строки, другие определяют свои собственные пользовательские типы. Использование встроенного объекта Error в Node.js помогает сохранить единообразие в вашем коде, а с помощью сторонних библиотек он также сохраняет важную информацию, такую как StackTrace. При возникновении исключения обычно рекомендуется заполнить его дополнительными контекстными свойствами, такими как имя ошибки и связанный код ошибки HTTP. Чтобы добиться этого единообразия и практики, рассмотрите возможность расширения объекта Error дополнительными свойствами, см. пример кода ниже.
|
||||
|
||||
### Пример кода - делай все правильно
|
||||
|
||||
```javascript
|
||||
// throwing an Error from typical function, whether sync or async
|
||||
// пробрасываем Error из типичной async или sync функции
|
||||
if(!productToAdd)
|
||||
throw new Error('How can I add new product when no value provided?');
|
||||
|
||||
// 'throwing' an Error from EventEmitter
|
||||
// пробрасываем Error из EventEmitter
|
||||
const myEmitter = new MyEmitter();
|
||||
myEmitter.emit('error', new Error('whoops!'));
|
||||
|
||||
// 'throwing' an Error from a Promise
|
||||
// пробрасываем Error из Promise
|
||||
const addProduct = async (productToAdd) => {
|
||||
try {
|
||||
const existingProduct = await DAL.getProduct(productToAdd.id);
|
||||
@ -31,23 +31,23 @@ const addProduct = async (productToAdd) => {
|
||||
### Пример кода - антипаттерн
|
||||
|
||||
```javascript
|
||||
// throwing a string lacks any stack trace information and other important data properties
|
||||
// пробрасывая строку, теряем информацию о stack trace и другие важные параметры
|
||||
if(!productToAdd)
|
||||
throw ('How can I add new product when no value provided?');
|
||||
```
|
||||
|
||||
### Пример кода - делаем это еще лучше
|
||||
### Пример кода - делаем еще лучше
|
||||
|
||||
<details>
|
||||
<summary><strong>Javascript</strong></summary>
|
||||
|
||||
```javascript
|
||||
// centralized error object that derives from Node’s Error
|
||||
// главные объект ошибки производный от нодовского Error
|
||||
function AppError(name, httpCode, description, isOperational) {
|
||||
Error.call(this);
|
||||
Error.captureStackTrace(this);
|
||||
this.name = name;
|
||||
//...other properties assigned here
|
||||
//... другие параметры тут
|
||||
};
|
||||
|
||||
AppError.prototype = Object.create(Error.prototype);
|
||||
@ -55,7 +55,7 @@ AppError.prototype.constructor = AppError;
|
||||
|
||||
module.exports.AppError = AppError;
|
||||
|
||||
// client throwing an exception
|
||||
// клиент пробрасывает исключение
|
||||
if(user == null)
|
||||
throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)
|
||||
```
|
||||
@ -65,7 +65,7 @@ if(user == null)
|
||||
<summary><strong>Typescript</strong></summary>
|
||||
|
||||
```typescript
|
||||
// centralized error object that derives from Node’s Error
|
||||
// главные объект ошибки производный от нодовского Error
|
||||
export class AppError extends Error {
|
||||
public readonly name: string;
|
||||
public readonly httpCode: HttpCode;
|
||||
@ -74,7 +74,7 @@ export class AppError extends Error {
|
||||
constructor(name: string, httpCode: HttpCode, description: string, isOperational: boolean) {
|
||||
super(description);
|
||||
|
||||
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
|
||||
Object.setPrototypeOf(this, new.target.prototype); // восстанавливаем цепочку прототипов
|
||||
|
||||
this.name = name;
|
||||
this.httpCode = httpCode;
|
||||
@ -84,7 +84,7 @@ export class AppError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
// client throwing an exception
|
||||
// клиент пробрасывает исключение
|
||||
if(user == null)
|
||||
throw new AppError(commonErrors.resourceNotFound, commonHTTPErrors.notFound, 'further explanation', true)
|
||||
```
|
||||
@ -96,22 +96,22 @@ if(user == null)
|
||||
|
||||
Из блога Бен Надель, занял 5 место по ключевым словам "объект ошибки Node.js"
|
||||
|
||||
> … Лично я не вижу смысла в том, чтобы иметь множество различных типов объектов ошибок - JavaScript, как язык, похоже, не предназначен для поиска ошибок на основе конструктора. Таким образом, дифференцирование по свойству объекта кажется гораздо проще, чем по типу Constructor …
|
||||
> … Лично я не вижу смысла в том, чтобы иметь множество различных типов объектов ошибок - JavaScript, как язык, похоже, не предназначен для поиска ошибок на основе конструктора. Таким образом, определение по свойству объекта кажется гораздо проще, чем по типу Constructor …
|
||||
|
||||
### Цитата блога: "Строка не является ошибкой"
|
||||
|
||||
Из блога devthought.com, занял 6 место по ключевым словам "Объект ошибки Node.js"
|
||||
|
||||
> … передача строки вместо ошибки приводит к снижению совместимости между модулями. Он нарушает контракты с API, которые могут выполнять проверки ошибок instanceof или хотят узнать больше об ошибке. Объекты ошибок, как мы увидим, обладают очень интересными свойствами в современных механизмах JavaScript, помимо хранения сообщения, переданного конструктору …
|
||||
> … передача строки вместо ошибки приводит к снижению совместимости между модулями. Это нарушает контракты с API, которые могут выполнять проверки ошибок с помощью instanceof или хотят узнать больше об ошибке. Объекты ошибок, как мы увидим, обладают очень интересными свойствами в современных механизмах JavaScript, помимо хранения сообщения, переданного конструктору …
|
||||
|
||||
### Цитата из блога: "Наследование от ошибки не увеличивает ценность"
|
||||
### Цитата из блога: "Наследование от ошибки не увеличивает их ценность"
|
||||
|
||||
Из блога Machadogj
|
||||
|
||||
> … Одна проблема, которую я имею с классом Error, заключается в том, что его не так просто расширить. Конечно, вы можете наследовать класс и создавать свои собственные классы ошибок, такие как HttpError, DbError и т.д. Однако это занимает время и не добавляет слишком много значения, если вы не делаете что-то с типами. Иногда вам просто нужно добавить сообщение и сохранить внутреннюю ошибку, а иногда вам может понадобиться расширить ошибку с помощью параметров, и так далее …
|
||||
|
||||
### Цитата из блога: "Все ошибки JavaScript и системы, возникающие в Node.js, наследуются от ошибок"
|
||||
### Цитата из блога: "Все ошибки JavaScript и системы, возникающие в Node.js, наследуются от Error"
|
||||
|
||||
Из официальной документации Node.js
|
||||
|
||||
> … Все ошибки JavaScript и System, возникающие в Node.js, наследуются или являются экземплярами стандартного класса JavaScript Error и гарантированно предоставляют как минимум свойства, доступные в этом классе. Общий объект JavaScript Error, который не обозначает каких-либо конкретных обстоятельств, по которым произошла ошибка. Объекты ошибок фиксируют "трассировку стека", детализирующую точку в коде, в которой был создан экземпляр ошибки, и могут предоставлять текстовое описание ошибки. Все ошибки, сгенерированные Node.js, включая все системные ошибки и ошибки JavaScript, будут либо экземплярами класса Error, либо наследоваться от него …
|
||||
> … Все ошибки JavaScript и System, возникающие в Node.js, наследуются или являются экземплярами стандартного класса JavaScript Error и гарантированно предоставляют как минимум свойства, доступные в этом классе. Общий объект JavaScript Error, который не обозначает каких-либо конкретных обстоятельств, по которым произошла ошибка. Объекты ошибок фиксируют "трассировку стека", детализирующую точку в коде, в которой был создан экземпляр ошибки, и могут предоставлять текстовое описание ошибки. Все ошибки, сгенерированные Node.js, включая все системные ошибки и ошибки JavaScript, будут либо экземплярами класса Error, либо наследоваться от него …
|
||||
@ -1,4 +1,4 @@
|
||||
# Выделяйте ваши компоненты в отдельный слой, держите Express в его граница
|
||||
# Выделяйте ваши компоненты в отдельный слой, держите Express в его границах
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user