Анти-паттерны в NodeJS

Синхронное выполнение

Избегаем всех синхронных операций, так же известных как блокирующий ввод/вывод. NodeJS построен на неблокирующим вводе/выводе и любой одиночный блокирующий вызов незамедлительно привносит узкое место.

  • fs.renameSync
  • fs.truncateSync
  • fs.statSync
  • path.existsSync
  • ...

Всех операций блокирующих ввод/вывод необходимо избегать.

Хотя они существуют не спроста. Они могут и должны только использоваться на этапе инициализации вашего сервера. Очень полезно использовать синхронные операции на протяжении инициализации, таким образом вы будете иметь контроль над порядком выполнения, и вам не нужно переживать о функциях обратного вызова которые могли быть, или нет, выполнены к моменту приема первого входящего запроса.

Понимание V8

NodeJS построен на JavaScript интерпретаторе V8. (Да, spidernode в разработке). V8 очень быстрый, имеет очень хороший сборщик мусора, он точно знает что делает. Не нужно делать микро оптимизации или недооценивать V8.

Утечки памяти

Если вы прежде разрабатывали только на броузером JavaScript, тогда вы не сильно заботились об утечках памяти так как время жизни одной страницы измеряется диапазоном от нескольких секунд до пары часов. В то время один сервер на NodeJS имеет диапазон от нескольких дней до нескольких месяцев.

Утечки памяти это не то чем вы думали когда пришли с не серверного JS. Очень важно иметь хорошее понимание об утечках памяти.

Несколько полезных советов:

  • Основной проблемой является непонимание как замыкания работают из областями видимости и контекстами других функций. Это значит что есть множество способов создать цикличные ссылки или создать переменные которые не могут быть очищены/удалены. В частности потому что код является неоднозначным и интерпретатор не может быть уверен что может безопасно удалить мусор. Возможно принудительно указать собощику мусора что оно может удалить переменную присвоив ей значение null.

    function(foo, cb) {
    var bigObject = new BigObject();
    doFoo(foo).on("change", function(e) {
         if (e.type === bigObject.type) {
              cb();
              // bigObject = null;
         }
    });
    }

    Как в этом случае V8 может знать когда можно безопасно удалить большой объект в обработчику сообщения? Он не знает этого, поэтому вы должны сказать ему что больше не будете использовать переменную присвоив ей значение null.

  • Найти течки можно с помощью отладчика node-inspector

JavaScript

Все антипаттерны JavaScript применимы и здесь. По моему особенно вредным является использовать JavaScript в стиле C (использовать только процедурный стиль) или как C#/Java (подделывать классическое наследование.)

JavaScript должен использоваться как язык с прототипным ООП или как функциональный язык. Лично я бы порекомендовал использовать новый функционал из ES5 и использовать библиотеку underscore. Если начнете использовать обе рекомендации вы начнете писать код в функциональном стиле который наиболее подходит JavaScript'у.

Модульный код

NodeJS имеет хороший оператор require, который позволит вам разбить ваш код на модули.

В NodeJS нет необходимости использовать глобальное состояние. Ну вообще то вы можете использовать global.foo = ... для вставки в глобальное состояние, но это всегда является антипаттерном.

В общем ваш код должен быть слабо связным, EventEmitter позволяет хорошо писать слабосвязанные модули.

Совершенный код

Все что описано в книжке "Совершенный код" применимо, и я не вижу смысла повторять ее.

Оригинал