Статьи

10 советов, как стать лучшим разработчиком узлов в 2017 году

Человек в традиционной позе со скрещенными ногами, сосредоточенный на том, чтобы стать лучшим разработчиком Node

10 советов, как стать лучшим разработчиком узлов в 2017 году, от гостевого автора Азата Мардана . Гостевые посты SitePoint нацелены на привлечение интересного контента от известных писателей и докладчиков веб-сообщества.

Примечание: оригинальное название этой статьи было «Лучшие практики узлов от Гуру Платформы». В статье рассматриваются настоящие, проверенные и проверенные шаблоны, а не новые и лучшие 2017 года. Хотя некоторые из старых добрых практик от Node gurus будут по-прежнему применяться в 2017 и 2018 годах и даже в 2019 году, новые передовые функции, такие как async / подождите, обещания здесь не рассматриваются. Это связано с тем, что эти новые функции отсутствуют ни в коде ядра Node, ни в популярных проектах, таких как npm, Express и т. Д. Вторая часть эссе будет отражать правильную природу контента.

Эта статья включена в нашу антологию, современный JavaScript . Если вы хотите, чтобы все в одном месте было в курсе современного JavaScript, зарегистрируйтесь в SitePoint Premium и загрузите себе копию.

Я начал работать с Node на полную ставку в 2012 году, когда присоединился к Storify. С тех пор я никогда не оглядывался назад и не чувствовал, что мне не хватает Python, Ruby, Java или PHP — языков, с которыми я работал в течение предыдущего десятилетия веб-разработки.

Storify была для меня интересной работой, потому что, в отличие от многих других компаний, Storify запускала (и, возможно, все еще делает) все на JavaScript. Видите ли, большинство компаний, особенно крупных, таких как PayPal, Walmart или Capital One, используют Node только для определенных частей своего стека. Обычно они используют его в качестве шлюза API или уровня оркестровки. Замечательно. Но для разработчика программного обеспечения ничто не сравнится с полным погружением в среду Node.

В этой статье я опишу десять советов, которые помогут вам стать лучшим разработчиком Node в 2017 году. Эти советы приходят от меня, который видел и изучал их в окопах, а также от людей, которые написали самые популярные модули Node и npm. Вот что мы будем освещать:

  1. Избегайте сложности — организуйте свой код в наименьшие куски, пока они не станут слишком маленькими, а затем сделайте их еще меньше.
  2. Используйте асинхронный код — избегайте синхронного кода, например чумы.
  3. Избегайте блокировки require — поместите ВСЕ ваши операторы require в верхнюю часть файла, потому что они синхронны и будут блокировать выполнение.
  4. Знайте, что require кешируется — это может быть функция или ошибка в вашем коде.
  5. Всегда проверяйте на ошибки — ошибки не футбольные мячи. Никогда не выбрасывайте ошибки и никогда не пропускайте проверку ошибок.
  6. Используйте try … catch только в коде синхронизацииtry...catch бесполезен для асинхронного кода, плюс V8 не может оптимизировать код в try...catch и обычный код.
  7. Возвратите обратные вызовы или используйте if… else — просто чтобы быть уверенным, верните обратный вызов, чтобы предотвратить продолжение выполнения.
  8. Прослушивание событий ошибок. Почти все классы / объекты Node расширяют источник событий (шаблон наблюдателя) и генерируют событие error . Обязательно послушайте это.
  9. Знайте свой npm — Установите модули с -S или -D вместо --save или --save-dev
  10. Используйте точные версии в package.json : npm по умолчанию тупо добавляет символ вставки при использовании -S , поэтому избавьтесь от них вручную, чтобы заблокировать версии. Никогда не доверяйте semver в ваших приложениях, но делайте это в открытых модулях.
  11. Бонус — используйте разные зависимости. Поместите вещи, в которых нуждается ваш проект, только в devDependencies а затем используйте npm i --production . Чем больше у вас ненужных зависимостей, тем выше риск уязвимости.

Итак, давайте рассмотрим и рассмотрим каждый из них в отдельности. А не ___ ли нам?

И не забывайте: как упоминалось выше, это первая часть. Вы можете найти еще десять советов во второй части .

Избегайте сложности

Взгляните на некоторые модули, написанные Исааком З. Шлютером, создателем npm. Например, use-strict обеспечивает строгий режим JavaScript для модулей, и это всего лишь три строки кода:

 var module = require('module') module.wrapper[0] += '"use strict";' Object.freeze(module.wrap) 

Так почему бы избежать сложности? Известная фраза, которая возникла в военно-морском флоте США в соответствии с одной из легенд, гласит: «ПРОДОЛЖАЙТЕ ЭТО ПРОСТО ГЛУПО» (или это «Держите это простым, глупым» ?). Это по причине. Человеческий мозг может хранить только пять-семь элементов в своей рабочей памяти одновременно. Это просто факт.

Сохраняя свой код модульным на более мелкие части, вы и другие разработчики сможете лучше понять и обдумать это. Вы также можете проверить это лучше. Рассмотрим этот пример,

 app.use(function(req, res, next) { if (req.session.admin === true) return next() else return next(new Error('Not authorized')) }, function(req, res, next) { req.db = db next() }) 

Или этот код:

 const auth = require('./middleware/auth.js') const db = require('./middleware/db.js')(db) app.use(auth, db) 

Я уверен, что большинство из вас предпочтут второй пример, особенно когда имена говорят сами за себя. Конечно, когда вы пишете код, вы можете подумать, что понимаете, как он работает. Может быть, вы даже хотите показать, насколько вы умны, объединяя несколько методов в одну строку. Пожалуйста, код для тупой версии вас. Код для вас, который не просматривал этот код в течение шести месяцев, или для вас, чтобы попробовать или выпить версию. Если вы пишете код на пике своих умственных способностей, вам будет сложнее понять его позже, не говоря уже о ваших коллегах, которые даже не знакомы с тонкостями алгоритма. Сохранение простоты особенно актуально для Node, который использует асинхронный способ.

И да, произошел инцидент на левой панели, но это затронуло только проекты, зависящие от публичного реестра, и замена была опубликована за 11 минут. Преимущества небольшого перевеса перевешивают недостатки. Кроме того, npm изменил свою политику отмены публикации , и любой серьезный проект должен использовать стратегию кэширования или частный реестр (как временное решение).

Использовать асинхронный код

Синхронный код имеет (небольшое) место в узле. Это в основном для написания команд CLI или других сценариев, не связанных с веб-приложениями. Разработчики Node в основном создают веб-приложения, поэтому они используют асинхронный код, чтобы избежать блокирования потоков.

Например, это может быть хорошо, если мы просто создаем сценарий базы данных, а не систему для обработки параллельных / параллельных задач:

 let data = fs.readFileSync('./acconts.json') db.collection('accounts').insert(data, (results))=>{ fs.writeFileSync('./accountIDs.json', results, ()=>{process.exit(1)}) }) 

Но это было бы лучше при создании веб-приложения:

 app.use('/seed/:name', (req, res) => { let data = fs.readFile(`./${req.params.name}.json`, ()=>{ db.collection(req.params.name).insert(data, (results))=>{ fs.writeFile(`./${req.params.name}IDs.json`, results, ()={res.status(201).send()}) }) }) }) 

Разница заключается в том, пишете ли вы параллельные (обычно долго работающие) или не параллельные (краткосрочные) системы. Как правило, всегда пишите асинхронный код в Node.

Избегайте блокирования требуют

Узел имеет простую систему загрузки модулей, которая использует формат модуля CommonJS. Его встроенная функция require — это простой способ включить модули, которые существуют в отдельных файлах. В отличие от AMD / requirejs, способ загрузки модулей Node / CommonJS является синхронным. Способ работы require : вы импортируете то, что было экспортировано в модуль или файл .

 const react = require('react') 

Большинство разработчиков не знают, что require кешируется. Таким образом, до тех пор, пока нет решительных изменений в разрешенном имени файла (а в случае модулей npm их нет), код из модуля будет выполнен и загружен в переменную только один раз (для этого процесса). Это хорошая оптимизация. Тем не менее, даже с кэшированием, вам лучше поставить свои требования сначала. Рассмотрим этот код, который загружает только модуль axios на маршрут, который фактически использует его. Маршрут /connect будет медленнее, чем нужно, потому что импорт модуля происходит при выполнении запроса:

 app.post('/connect', (req, res) => { const axios = require('axios') axios.post('/api/authorize', req.body.auth) .then((response)=>res.send(response)) }) 

Лучший, более производительный способ — загрузить модули еще до того, как сервер будет определен, а не в маршруте:

 const axios = require('axios') const express = require('express') app = express() app.post('/connect', (req, res) => { axios.post('/api/authorize', req.body.auth) .then((response)=>res.send(response)) }) 

Знайте, что требуется Кэшируется

Я упоминал, что require кешируется в предыдущем разделе, но интересно то, что у нас может быть код вне module.exports . Например,

 console.log('I will not be cached and only run once, the first time') module.exports = () => { console.log('I will be cached and will run every time this module is invoked') } 

Зная, что некоторый код может выполняться только один раз, вы можете использовать эту функцию в своих интересах.

Всегда проверяйте на ошибки

Узел не Java. В Java вы генерируете ошибки, потому что большую часть времени, если есть ошибка, вы не хотите, чтобы приложение продолжалось. В Java вы можете обрабатывать несколько ошибок на более высоких уровнях с помощью одной try...catch .

Не так с Node. Поскольку Node использует цикл событий и выполняется асинхронно, любые ошибки отделяются от контекста любого обработчика ошибок (например, try...catch ) при их возникновении. Это бесполезно в узле:

 try { request.get('/accounts', (error, response)=>{ data = JSON.parse(response) }) } catch(error) { // Will NOT be called console.error(error) } 

Но try...catch все еще можно использовать в синхронном коде Node. Так что это лучший рефакторинг предыдущего фрагмента:

 request.get('/accounts', (error, response)=>{ try { data = JSON.parse(response) } catch(error) { // Will be called console.error(error) } }) 

Если мы не можем заключить request в блок try...catch , это оставляет нас с ошибками, поступающими из запроса, необработанными. Разработчики Node решают эту проблему, предоставляя вам сообщение error в качестве аргумента обратного вызова. Таким образом, вам нужно всегда вручную обрабатывать error в каждом обратном вызове. Вы делаете это путем проверки на наличие ошибки (убедитесь, что она не null ), а затем либо выводите сообщение об ошибке пользователю или клиенту и регистрируете его, либо передаете его обратно в стек вызовов, вызывая обратный вызов с error (если у вас есть обратный вызов и другая функция вверх по стеку вызовов).

 request.get('/accounts', (error, response)=>{ if (error) return console.error(error) try { data = JSON.parse(response) } catch(error) { console.error(error) } }) 

Небольшая хитрость, которую вы можете использовать, это хорошая библиотека. Вы можете применить это так, чтобы избежать ручной проверки ошибок на множестве вложенных обратных вызовов (Hello, callback hell ).

 var ok = require('okay') request.get('/accounts', ok(console.error, (response)=>{ try { data = JSON.parse(response) } catch(error) { console.error(error) } })) 

Вернуть обратные вызовы или использовать, если … еще

Узел одновременно. Так что это особенность, которая может стать ошибкой, если вы не будете осторожны. Чтобы быть в безопасности, завершите выполнение оператором return:

 let error = true if (error) return callback(error) console.log('I will never run - good.') 

Избегайте непреднамеренного параллелизма (и сбоев) из-за неправильно обработанного потока управления.

 let error = true if (error) callback(error) console.log('I will run. Not good!') 

Просто чтобы быть уверенным, return обратный вызов, чтобы предотвратить продолжение выполнения.

Прослушайте error События

Почти все классы / объекты Node расширяют источник событий (шаблон наблюдателя) и генерируют событие error . Это возможность для разработчиков отлавливать эти надоедливые ошибки и обрабатывать их до того, как они нанесут ущерб.

Сделайте хорошей привычкой создавать обработчики событий для error , используя .on() :

 var req = http.request(options, (res) => { if (('' + res.statusCode).match(/^2\d\d$/)) { // Success, process response } else if (('' + res.statusCode).match(/^5\d\d$/)) // Server error, not the same as req error. Req was ok. } }) req.on('error', (error) => { // Can't even make a request: general error, eg ECONNRESET, ECONNREFUSED, HPE_INVALID_VERSION console.log(error) }) 

Знай свой нпм

Многие разработчики Node и front-end событий знают, что есть --save (для npm install ), которая не только установит модуль, но и создаст запись в package.json с версией модуля. Ну, есть также --save-dev для devDependencies (вещи, которые вам не нужны в производстве). Но знаете ли вы, что вы можете просто использовать -S и -D вместо --save и --save-dev ? Да, ты можешь.

И пока вы находитесь в режиме установки модуля, продолжайте и удалите те знаки ^ которые создадут -S и -D для вас. Они опасны, потому что позволяют npm install (или его ярлыку npm i ) извлекать последнюю минорную (вторую цифру в семантической версии) версию из npm. Например, v6.1.0 до v6.2.0 является второстепенным выпуском.

Команда npm верит в Семвер , но не стоит. Я имею в виду, что они осторожны, потому что доверяют разработчикам открытого исходного кода не вносить существенных изменений в второстепенные версии. Никто в здравом уме не должен доверять этому. Заблокируйте свои версии. Еще лучше использовать shrinkwrap : npm shrinkwrap который создаст новый файл с точными версиями зависимостей зависимостей.

Вывод

Этот пост был частью первой из двух. Мы уже проделали большую работу, от работы с обратными вызовами и асинхронным кодом, до проверки на наличие ошибок и блокировки зависимостей. Я надеюсь, что вы нашли что-то новое или полезное здесь. Если вам понравилось, обязательно ознакомьтесь со второй частью: 10 Node.js Best Practices: Просвещение от Node Gurus .

И скажи мне, что ты думаешь. Я что-то пропустил? Вы делаете это по-другому? Позвольте мне знать в комментариях ниже.