Что такое Floating Promise и почему это опасно?
#code_pattern #nodejs_api
TL;DR Используйте
Floating (не отловленный, плавающий) promise как правило указывает на ошибку в коде. Если внутри Floating promise произойдет ошибка, то #nodejs процесс аварийно завершит работу. Для отлавливания таких событий существует
Отлавливать Floating promise лучше не в run time, а с помощью линтера. Для этого существуют правила:
➡️ в eslint
➡️ в typescript-eslint
➡️ тут мог бы быть tslint, но его уже нельзя использовать.
В определенных случаях, бизнес логика не требует ожидания завершения промиса. Тогда необходимо использовать комментарий в коде, указывающий линтеру игнорировать ошибку. Вот пример, когда REST не дожидается отправки емейла новому пользователю.
#code_pattern #nodejs_api
TL;DR Используйте
no-floating-promises и unhandledRejectionFloating (не отловленный, плавающий) promise как правило указывает на ошибку в коде. Если внутри Floating promise произойдет ошибка, то #nodejs процесс аварийно завершит работу. Для отлавливания таких событий существует
unhandledRejection. Пример из документации:process.on('unhandledRejection', (reason, promise) => { console.log('Unhandled Rejection at:', promise, 'reason:', reason);});Отлавливать Floating promise лучше не в run time, а с помощью линтера. Для этого существуют правила:
➡️ в eslint
➡️ в typescript-eslint
➡️ тут мог бы быть tslint, но его уже нельзя использовать.
В определенных случаях, бизнес логика не требует ожидания завершения промиса. Тогда необходимо использовать комментарий в коде, указывающий линтеру игнорировать ошибку. Вот пример, когда REST не дожидается отправки емейла новому пользователю.
import { usersRepository } from '~/repositories';import { sendConfirmationEmail } from '~/services/notifications';import logger from '~/logger';// pseudo route handlerexport async function registerUser(data: newUserDTO): { const user = await usersRepository.create(data); // eslint-disable-next-line @typescript-eslint/no-floating-promises sendConfirmationEmail(user) .catch(err => logger({err, user}, 'Error during sending confirmation email'); return user;}refactoring.guru
#code_pattern #typescript
В комментариях к код ревью считается хороший тоном оставлять ссылки на внешние ресурсы. Так коллега сможет быстрее понять, что ему рекомендуют. Помимо ссылок на документацию библиотек или #nodejs я оставляю ссылки на разделы refactoring.guru.
Там есть и паттерны проектирования, и советы по рефакторингу. Александр Швец сопровождает их хорошей визуализацией, переводами на разные языки и примерами кода, в том числе на TypeScript.
#code_pattern #typescript
В комментариях к код ревью считается хороший тоном оставлять ссылки на внешние ресурсы. Так коллега сможет быстрее понять, что ему рекомендуют. Помимо ссылок на документацию библиотек или #nodejs я оставляю ссылки на разделы refactoring.guru.
Там есть и паттерны проектирования, и советы по рефакторингу. Александр Швец сопровождает их хорошей визуализацией, переводами на разные языки и примерами кода, в том числе на TypeScript.
refactoring.guru
Refactoring and Design Patterns
Refactoring is a controllable process of improving code without creating new functionality. Design Patterns are typical solutions to the commonly occurring problems in software design.
Как итерировать массив?
#code_pattern
Проводя интервью, я практикую live coding, то есть решение простых задач со скриншарингом экрана. Так сразу видно пишет ли кандидат код на современном JavaScript.
Итерировать массив можно 4-мя способами:
1️⃣ for
2️⃣ forEach
3️⃣ for in
4️⃣ for of
Упрощенный анализ показывают, что 1️⃣и 3️⃣ создают ненужную переменную, а 2️⃣– контекст ненужной функции. Поэтому при написание кода старайтесь использовать 4️⃣ for of.
Бенчмарки и глубокий анализ можно провести самостоятельно или нагуглить. Вместо этого я порекомендую добавить к себе в проект eslint правило disallow forEach. Это же можно сделать с помощью no-restricted-syntax и селектора
#code_pattern
Проводя интервью, я практикую live coding, то есть решение простых задач со скриншарингом экрана. Так сразу видно пишет ли кандидат код на современном JavaScript.
Итерировать массив можно 4-мя способами:
1️⃣ for
for (let i = 0; i < arr.length; ++i) { console.log(arr[i]);}2️⃣ forEach
arr.forEach((v, i) => console.log(v));3️⃣ for in
for (let i in arr) { console.log(arr[i]);}4️⃣ for of
for (const v of arr) { console.log(v);}Упрощенный анализ показывают, что 1️⃣и 3️⃣ создают ненужную переменную, а 2️⃣– контекст ненужной функции. Поэтому при написание кода старайтесь использовать 4️⃣ for of.
Бенчмарки и глубокий анализ можно провести самостоятельно или нагуглить. Вместо этого я порекомендую добавить к себе в проект eslint правило disallow forEach. Это же можно сделать с помощью no-restricted-syntax и селектора
CallExpression[callee.property.name="forEach"]😁4🤯2
Почему вам нужны знания Promise-ов в async/await коде?
#code_pattern
Async/await является основным стилем для написания асинхронного кода в современной #nodejs. Стоит помнить, что это синтаксический сахар поверх Promise chain. Поэтому для любого уровня разработчика важно понимать когда и для чего использовать такие конструкции:
➡️ Promise.all – необходимо использовать для получения значений, которые независимы. Будет прерван при первой ошибке.
➡️ Promise.race – необходимо использовать для получения первого значения или ошибки. Классический пример, это выброс ошибки по таймауту.
➡️ Promise.allSettled – необходимо использовать для получения всех значений. Ошибки не вызовут остановку, а будут частью результата.
Что дает использование этих конструкций? Вы можете запускать промисы не последовательно, а параллельно. В результате время ответа становиться быстрее.
#code_pattern
Async/await является основным стилем для написания асинхронного кода в современной #nodejs. Стоит помнить, что это синтаксический сахар поверх Promise chain. Поэтому для любого уровня разработчика важно понимать когда и для чего использовать такие конструкции:
➡️ Promise.all – необходимо использовать для получения значений, которые независимы. Будет прерван при первой ошибке.
➡️ Promise.race – необходимо использовать для получения первого значения или ошибки. Классический пример, это выброс ошибки по таймауту.
➡️ Promise.allSettled – необходимо использовать для получения всех значений. Ошибки не вызовут остановку, а будут частью результата.
Что дает использование этих конструкций? Вы можете запускать промисы не последовательно, а параллельно. В результате время ответа становиться быстрее.
JavaScript Algorithms and Data Structures
#code_pattern
Чтобы писать код нужно: знать его синтаксис и инструментарий. Чтобы писать качественный код нужно: знать теория программирования, алгоритмы и структуры данных.
Для JavaScript разработчиков существует отличный репозитарий javascript-algorithms. В нем разобраны классические алгоритмы и структуры данных. Есть разделение по уровню Beginner/Advanced и переводы, в том числе на русский и украинский языки. Рекомендую к изучению!
#code_pattern
Чтобы писать код нужно: знать его синтаксис и инструментарий. Чтобы писать качественный код нужно: знать теория программирования, алгоритмы и структуры данных.
Для JavaScript разработчиков существует отличный репозитарий javascript-algorithms. В нем разобраны классические алгоритмы и структуры данных. Есть разделение по уровню Beginner/Advanced и переводы, в том числе на русский и украинский языки. Рекомендую к изучению!
GitHub
GitHub - trekhleb/javascript-algorithms: 📝 Algorithms and data structures implemented in JavaScript with explanations and links…
📝 Algorithms and data structures implemented in JavaScript with explanations and links to further readings - trekhleb/javascript-algorithms
Как подтянуть TypeScript?
#typescript #code_pattern
Лучший способ тренировки паттернов кодирование это решений задач. Для этого отлично подойдет проект type-challenges. Каждая из задач предлагает написать свой тип. Есть встроенная проверка. Как это работает можно глянуть на Hello World примере.
В Readme проекта задачи отсортированы по темам и уровням сложности. Некоторые задачи начального уровня предлагают реализовать built-in тип, т.е. который уже есть в TypeScript.
#typescript #code_pattern
Лучший способ тренировки паттернов кодирование это решений задач. Для этого отлично подойдет проект type-challenges. Каждая из задач предлагает написать свой тип. Есть встроенная проверка. Как это работает можно глянуть на Hello World примере.
В Readme проекта задачи отсортированы по темам и уровням сложности. Некоторые задачи начального уровня предлагают реализовать built-in тип, т.е. который уже есть в TypeScript.
GitHub
GitHub - type-challenges/type-challenges: Collection of TypeScript type challenges with online judge
Collection of TypeScript type challenges with online judge - type-challenges/type-challenges
Зачем нужен Symbol в JavaScript?
#code_pattern
В ECMAScript2015 (ES6) появился примитивный тип Symbol. Он используется, чтобы создавать уникальные идентификаторы. Пример:
Основное назначение Symbol это работа со встроенными фичами языка. Для этого существуют Well-known Symbols, такие как:
- Symbol.iterator
- Symbol.hasInstance
- Symbol.toStringTag
- и т.д., подробней об встроенных символах смотри typescript doc или на habr.
Well-known Symbols, используются на системном уровне программирования, т.е. на уровне библиотек и фреймворков. На прикладном уровне, т.е. на уровне написания кода приложения, а не библиотек, устоявшейся практикой является использование Symbol в декораторах на TypeScript. Пример:
Стоит еще знать об Symbol.for и Symbol.keyFor, которые позволяют работать с shared Symbol. По своей сути это глобальные переменные в shared Symbol scope, поэтому опытные программисты стараются их избегать.
#code_pattern
В ECMAScript2015 (ES6) появился примитивный тип Symbol. Он используется, чтобы создавать уникальные идентификаторы. Пример:
const first = Symbol('example')
const second = Symbol('example')
first === first // true
first === second // false
Т.е. создать второй раз тот же самый идентификатор нельзя. Их используют для определения свойств объектов, т.е. обращения к его ключам.Основное назначение Symbol это работа со встроенными фичами языка. Для этого существуют Well-known Symbols, такие как:
- Symbol.iterator
- Symbol.hasInstance
- Symbol.toStringTag
- и т.д., подробней об встроенных символах смотри typescript doc или на habr.
Well-known Symbols, используются на системном уровне программирования, т.е. на уровне библиотек и фреймворков. На прикладном уровне, т.е. на уровне написания кода приложения, а не библиотек, устоявшейся практикой является использование Symbol в декораторах на TypeScript. Пример:
import { SetMetadata } from '@nestjs/common';
export const isPublic = Symbol('isPublic');
export function Public() {
return SetMetadata(isPublic, true);
}
Таким образом можно вы можете гарантировать, что не произойдет коллизии в чтение/записи метаданных из ваших объектов.Стоит еще знать об Symbol.for и Symbol.keyFor, которые позволяют работать с shared Symbol. По своей сути это глобальные переменные в shared Symbol scope, поэтому опытные программисты стараются их избегать.
www.typescriptlang.org
Documentation - Symbols
Using the JavaScript Symbol primitive in TypeScript
👍2
30 seconds of code – сборник код-снипетов
#list #code_pattern
В начале лета я делился ссылкой на 1loc.dev. В комментариях была ссылка на аналогичный ресурс – 30 seconds of code. Примеры кода чуть длинней, но суть та же самая. Есть раздел отдельно по #nodejs сниппетам.
#list #code_pattern
В начале лета я делился ссылкой на 1loc.dev. В комментариях была ссылка на аналогичный ресурс – 30 seconds of code. Примеры кода чуть длинней, но суть та же самая. Есть раздел отдельно по #nodejs сниппетам.
www.30secondsofcode.org
30 seconds of code
Browse 692 coding articles to level up your coding skills on 30 seconds of code.
Почему нужно избегать магии?
#code_pattern
Там где исчезает понимание техника превращается в магию. Программистам следует этого избегать.
Avoid magic strings
Выглядит данная магия так:
Поддерживать и читать этот код сложно. Вынесение таких строк как Alice в отдельный файл или объект с константами обычная практика в JS. В TypeScript для этих целей используется string base enum.
Avoid magic numbers
Аналогичная проблема может быть с числами.
Решение аналогично. Перенос в константы. Улучшение читабельности и поддержки. 16 лет как пороговое значение будет разным в разных доменах.
Для автоматизации используйте eslint, там есть правило no-magic-numbers.
#code_pattern
Там где исчезает понимание техника превращается в магию. Программистам следует этого избегать.
Avoid magic strings
Выглядит данная магия так:
function isFriend(name) { if (name === 'Alice') return true; ... }Поддерживать и читать этот код сложно. Вынесение таких строк как Alice в отдельный файл или объект с константами обычная практика в JS. В TypeScript для этих целей используется string base enum.
Avoid magic numbers
Аналогичная проблема может быть с числами.
function isAdult(user) { return user.age >= 16; }Решение аналогично. Перенос в константы. Улучшение читабельности и поддержки. 16 лет как пороговое значение будет разным в разных доменах.
Для автоматизации используйте eslint, там есть правило no-magic-numbers.
Чем отличаются операционные ошибки от ошибок программиста?
#code_pattern
Ошибки в ходе выполнения можно разделить на операционные ошибки (база данных не доступна, внешний API не вернул ответ и т.д.) и на ошибки программиста, т.е. баги в коде. Типичная ошибка #nodejs программиста
С точки зрения REST API отмечу, что необходимо использовать валидацию входящих данных и использовать 400 код, если она не прошла. А вот 500-ый http код создан именно для ошибок программиста.
Ошибки обоих типов должны быть залогированы, но уровень для операционных ошибок info/error, а ошибок программиста – error/fatal.
Операционные ошибки могут и должны быть обработаны. Ошибки же программиста не могут быть обработаны, так как приводят программу в неизвестное состояние. По хорошему приложение необходимо перезапустить.
Подробней по теме:
🔗Distinguish operational vs programmer errors
🔗Error Handling in Node.js
#code_pattern
Ошибки в ходе выполнения можно разделить на операционные ошибки (база данных не доступна, внешний API не вернул ответ и т.д.) и на ошибки программиста, т.е. баги в коде. Типичная ошибка #nodejs программиста
TypeError: Cannot read property '...' of undefined. TypeScript снижает количество таких ошибок, но не убирает их полностью. С точки зрения REST API отмечу, что необходимо использовать валидацию входящих данных и использовать 400 код, если она не прошла. А вот 500-ый http код создан именно для ошибок программиста.
Ошибки обоих типов должны быть залогированы, но уровень для операционных ошибок info/error, а ошибок программиста – error/fatal.
Операционные ошибки могут и должны быть обработаны. Ошибки же программиста не могут быть обработаны, так как приводят программу в неизвестное состояние. По хорошему приложение необходимо перезапустить.
Подробней по теме:
🔗Distinguish operational vs programmer errors
🔗Error Handling in Node.js