Сюрреализм на JavaScript. Советы по разработке на NodeJS

    Привет, Хабра!

    Пол года назад я подумал: «А может книгу написать?», и таки написал.



    Все документы оформлены, страницы сверстаны, а тираж — отпечатан. Я не буду клянчить у вас деньги на кикстартере или предлагать что-либо купить, а вместо этого попытаюсь заинтриговать советами по разработке на NodeJS в целях пиара и привлечения внимания к книге.

    Совет 1. SQL запросы лучше хранить отформатированными


    SQL запросы лучше хранить отформатированными, т.к. код в этом случае гораздо проще читать и править. Т.к. SQL-запросы обычно довольно длинные, то лучше разбивать их на несколько строк, а строки в JavaScript — лучше всего выглядят в массиве.

    До:
    var query = "SELECT g.id, g.title, g.description, g.link, g.icon, t.id as tag_id, c.title as comment_title FROM games AS g LEFT JOIN tags AS t ON t.game_id = g.id LEFT JOIN comments AS c ON c.game_id = g.id WHERE g.id = $1";

    После:
    var query = [
    	"SELECT ",
    	"    g.id, g.title, g.description, g.link, g.icon, ",
    	"    t.id as tag_id, c.title as comment_title ",
    	"  FROM games AS g ",
    	"    LEFT JOIN tags AS t ON  t.game_id = g.id ",
    	"    LEFT JOIN comments AS c ON  c.game_id = g.id ",
    	"  WHERE ",
    	"    g.id = $1"
    ];

    Согласитесь, что во втором случае запрос гораздо понятнее для читателя. Кроме того, если вы перед запросом в базу выводите запрос в консоль, то массив, прокинутый в console.dir(), опять таки гораздо понятнее, чем строка, прокинутая в console.log().



    Совет 2. Жизнь становится проще, когда API различных компонентов принимает на вход любой формат


    Предположим мы создали клиента к базе данных и хотим выполнить некий SQL-запрос. На входе мы ожидаем строку и параметры. Т.к. воспользовавшись прошлым советом мы решили хранить длинные запросы в массивах, то хотелось бы забыть про его преобразование в строку на каждом запросе.

    До:
    dataBase(query.join(""), parameters, callback);

    После:
    dataBase(query, parameters, callback);

    Код становится проще, когда функция запроса к базе (в данном случае dataBase), сама проверяет в каком виде ей передали запрос, и если это массив — сама делает ему join().

    Совет 3. Разукрасьте консоль и отформатируйте вывод информации


    Дебажить программы на NodeJS трудно, т.к. очень сильно не хватает стандартной консоли разработчика со всеми фишками, типа «точек остановки». Все данные пишутся в консоль, и хочется сделать её более понятной. Если у вас нода крутится где-то на сервере, да ещё и в несколько инстансов, да ещё и несколько разных сервисов на каждой инстансе висит, а доступ вы имеете только по SSH, то консоль может реально заставить страдать.

    Если в NodeJS вывести в консоль строку вида «Hello world!» с управляющими ANSI-символами, она будет окрашена в разные цвета. Пример использования управляющих ANSI-символов:



    Чтобы не запоминать подобные хаки, вы можете подключить модуль colors и использовать следующий синтаксис:

    console.log("Error! Parameter ID not found.".red);

    Строка будет выведена красным цветом. При разработке с этим модулем вы можете раскрасить сообщения в консоли в различные цвета:
    • Красный (ошибка).
    • Желтый (предупреждение).
    • Зеленый (все хорошо).
    • Серый. Им можно выводить какие-либо параметры (например, параметры запроса), на которые можно не обращать внимания, пока не поймаете ошибку.

    Консоль до цветового выделения (при быстром просмотре информация воспринимается с трудом):



    Консоль после цветового выделения (при быстром просмотре информация воспринимается достаточно быстро):



    Благодаря раскрашенной консоли вам будет гораздо легче следить за состоянием сервера. Кроме того, если на одной инстансе у вас висит сразу несколько сервисов, которые работают с разными процессами, вы также должны писать в модулях отдельные методы для вывода в консоль. Например:

    var book = {
        console: function(message, color) {
            console.log(("Book API: " + (message || ""))[(color || white")]);
        }
    }


    Если все сообщения в консоли подписаны модулями, которые их отправляют, вы не только сможете сделать выборку по конкретному модулю, но и моментально найдете источник бага в критической ситуации. Форматирование текста также упрощает восприятие информации:



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

    var console = require("./my_console")("Scoring SDK");
    console.green("Request for DataBase.");
    console.grey([
        "SELECT *",
        "  FROM \"ScoringSDK__game_list\"",
        "  WHERE key = $1;"
    ]);

    Пример вывода данных в консоль:



    Совет 4. Оборачивайте все API в try/catch


    У нас на работе используется фреймворк express. Каково же было мое удивление, когда я узнал, что в стандартном объекте роутера нет обертки try/catch. Например:
    1. Вы написали кривой модуль
    2. Кто-то дернул его по URL`у
    3. У вас упал сервер
    4. WTF!?


    Поэтому всегда оборачивайте внешнее API модулей в try/catch. Если что-то пойдет не так, ваш кривой модуль, по крайней мере, не завалит всю систему. Та же ситуация на клиенте с шаблоном «медиатор» (его ещё называют «слушатели и публикующие»). Например:
    • Модуль А опубликовал сообщение.
    • Модули Б и В должны услышать его и отреагировать.
    • Система в цикле начинает перебирать подписчиков.
    • Модуль Б падает с ошибкой.
    • Цикл обрывается и callback-функция модуля В не вызывается.


    Гораздо лучше делать перебор в try/catch и если модуль Б действительно упадет с ошибкой, то по крайней мере не убьет систему и модуль В выполнит свою работу услышав событие.

    Т.к. при написании API модулей мне приходилось вновь и вновь отделять приватные и публичные методы, а после оборачивать все публичные методы в try/catch, я решил это дело автоматизировать и написал небольшой модуль для автогенерации API. Например, кидаем в него объект вида:

    var a = {
    	_b: function() { ... },
    	_c: function() { ... },
    	d:  function() { ... }
    }


    Из именования методов ясно, что первые два — приватные, а последний — публичный. Модуль создаст обертку для вызова последнего, вида:

    var api = {
    	d: function() {
    		try {
    			return a.d();
    		} catch(e) {
    			return false;
    		}
    	}
    };

    Таким образом, я стал генерировать обертку для API всех модулей, которая в случае возникновения ошибки не пропускала её дальше. Это сделало код более стабильным, т.к. ошибка отдельного разработчика, слитая в продакшн, уже не могла уронить весь сервер со всем его функционалом.

    Пример генерации API:
    var a = {
    	_b: function() { ... },
    	_c: function() { ... },
    	d:  function() { ... }
    }
    
    var api = api.create(a);
    
    api.d(); // пример вызова


    Совет 5. Собирайте запросы в конфиги


    Я думаю, у каждого веб-разработчика была ситуация, когда был какой-либо жирный клиент, которому нужно было небольшое API для работы с базой данных на сервере. Пару запросов на чтение, пару на запись и ещё несколько для удаления информации. Логики в таком сервере обычно нет, и он представляет собой просто набор запросов.

    Чтобы не писать каждый раз обертки для таких операций, я решил вынести все запросы в JSON, а сервер — оформить в виде небольшого модуля, который предоставляет мне API для работы с этим JSON`ом.

    Пример такого модуля под express:

    var fastQuery = require("./fastQuery"),
    	API = fastQuery({
    		scoring: {
    			get: {
    				query: "SELECT * FROM score LIMIT $1, $2;"
    				parameters: [ "limit", "offset" ]
    			},
    			set: {
    				query: "INSERT INTO score (user_id, score, date) VALUES ...",
    				parameters: [ "id", "score" ]
    			}
    		},
    		profile: {
    			get: {
    				query: "SELECT * FROM users WHERE id = $1;",
    				parameters: [ "id" ]
    			}
    		}
    	});

    Наверное, вы уже догадались, что модуль будет пробегать по JSON`у и искать объекты со свойствами query и parameters. Если такие объекты будут найдены, то он создаст для них функцию, которая будет проверять параметры, ходить в базу с запросами, и посылать клиенту результат. На выходе мы получим такое API:

    API.scoring.get();
    API.scoring.set();
    API.profile.get();
    

    И уже его привяжем к объекту роутера:

    exports.initRoutes = function (app) {
        app.get("/scoring/get", API.scoring.get);
        app.put("/scoring/set", API.scoring.set);
        app.get("/profile/get", API.profile.get);
    }

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

    А теперь представьте, что у вас есть ещё два серверных разработчика. Один пишет на PHP, а второй на Java. Если у вас вся серверная логика ограничивается только таким JSON`ом со списком запросов к базе, то вы можете моментально перенести/развернуть аналогичное API не только на другой машине, но и на абсолютно другом языке (при условии, что общение с клиентом стандартизировано и все общаются по REST API).

    Совет 6. Выносите все в конфиги


    Т.к. писать конфиги я люблю, у меня неоднократно возникала ситуация, когда у системы есть стандартные настройки, настройки для конкретного случая и настройки, возникшие в данные момент времени. Мне приходилось делать mix разных JSON объектов. Я решил выделить отдельный модуль для этих целей, а заодно добавил в него возможность брать JSON объекты из файла, т.к. хранить настройки в отдельном json-файле тоже очень удобно. Таким образом, теперь, когда мне нужно задать настройки для чего-либо я пишу:

    var data = config.get("config.json", "save.json", {
    	name: "Petr",
    	age: 12
    });

    Как вы уже могли догадаться, модуль перебирает переданные ему аргументы. Если это строка — то он пытается открыть файл и прочитать настройки из него, если это объект — то он сразу пытается скрестить его с предыдущими.

    В примере выше мы сначала берем некие стандартные настройки из файла config.json, потом накладываем на них сохраненные настройки из файла save.json, а потом добавляем настройки, которые актуальны в данный момент времени. На выходе мы получим mix из трех JSON объектов. Количество аргументов переданных модулю может быть любым. Например, мы можем попросить пригнать только настройки по умолчанию:

    var data = config.get("config.json");


    Совет 7. Работа с файлами и Модуль Social Link для СЕО


    Одна из главных фич, которые мне нравятся в NodeJS, возможность работать с файлами и писать парсеры на JavaScript. При том API NodeJS предоставляет множество методов и способов для решения задач, но на практике — нужно совсем не много. За полгода активной работы с парсерами я использовал только две команды — прочитать и записать в файл. Притом, чтобы не страдать с callback-функциями и различными проблемами асинхронности, всю работу с файлами я всегда делал в синхронном режиме. Так появился небольшой модуль работы с файлами, API которого очень напоминало localStorage:

    var file = requery("./utils.file.js"), // подключили модуль
    	text = file.get("text.txt);        // прочитали текст в файле
    	
    file.set("text.txt", "Hello world!");  // записали текст в файл

    На основание этого модуля работы с файлами, стали появятся другие модули. Например, модуль для СЕО. В одной из прошлых статей я уже писал, что существует огромное количество различных meta-тегов связанных с СЕО. Когда я начинал писать систему сборку для HTML приложений, СЕО я уделил особое внимание.

    Суть заключается в том, что у нас есть небольшой текстовый файл с описанием сайта/приложения/игры и непосредственно HTML файл для разбора. Модуль Social Link должен найти все meta-теги связанные с СЕО в HTML файле и заполнить их. Внешнее API модуля ожидает на входе текст из файла. Это сделано для того, чтобы была возможность подключать его к системам сборки и прогонять через него текст нескольких файлов не вызывая каждый раз лишнюю процедуру чтения/записи в файл.

    Например, до модуля:
    <title></title>
    <meta property="og:title" content=""/>
    <meta name="twitter:title" content=""/>

    После модуля:
    <title>Некий заголовок</title>
    <meta property="og:title" content="Некий заголовок"/>
    <meta name="twitter:title" content="Некий заголовок"/>

    Список и описание всех meta-тегов для СЕО и не только, вы можете посмотреть в книге http://bakhirev.biz/.

    Совет 8. Без callback`ов жизнь проще

    Многие разработчики жалуются на бесконечные цепочки callback`ов при написании сервера на NodeJS. На самом деле вы не всегда обязаны их писать и часто можно выстроить архитектуру, при которой такие цепочки будут минимальны. Рассмотрим небольшую задачу.

    Задача:
    Перегнать файлы с сервера А на сервер Б, получить некоторую информацию из базы данных, обновить эту информацию, отправить данные на сервер В.

    Решение:
    Это довольно рутинная процедура, которую мне неоднократно приходилось выполнять для решения каких-либо задач по сортировке / обработке контента. Обычно разработчики создают цикл и некую callback-функцию с методом nextFile(). Когда на очередной итерации мы вызываем nextFile(), механизм callback`ов начинается с начала, и мы обрабатываем следующий файл. Как правило, требуется в один момент времени обрабатывать только один файл и при удачном завершении процедуры переходить к обработке следующего файла. Упростить вложенность нам поможет код вида:

    var locked = false,
    	index = 0,
    	timer = setInterval(function() {
    		if(locked) return;
    		locked = true;
    		nextFile(index++);
    	}, 1000);

    Теперь мы будем раз в секунду пытаться начать обработку файла. Если программа освободится, то она выставит locked в значение false и мы сможем запустить следующий файл на обработку. Такие конструкции очень часто помогают уменьшать вложенность, распределить нагрузку по времени (т.к. очередная итерация обработки у нас запускается не чаще, чем один раз в секунду) и хоть немного сползать с бесконечных callback`ов.

    Итого
    Файлы с модулями можно скачать тут: http://bakhirev.biz/_node.zip (сейчас 2 часа ночи и мне лень разбираться с GitHub`ом и приводить код в человеческий вид).
    Книга тут: http://bakhirev.biz/
    На случай хабро-эффекта тут в PDF.

    Если советы выше пришлись вам по вкусу, то хочу сразу предупредить, что книга совсем про другое. А ещё там в конце список разных умных людей, которые внесли неоценимый вклад сами того не подозревая, и которых точно следует найти и прочитать по отдельности.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 36
    • +5
      По совету 4. Надо исключение хотя бы в консоль вывести, или в лог-файл — иначе отладка модулей превращается в какой-то ужас, когда ничего не работает — и причина не видна.
      • +2
        отладка — это да, но т.к. у нас все обертки генерирует один модуль API — то и отключить все try/catch защиты во всех модулях можно с одного места. Та же самая тема с консолью — если она не нужна, то её можно перекрыть исправив только один файл.
      • +6
        По совету №4 — в продакшене достаточно запускать приложение через forever или passenger, которые в случае падения переподнимут его. Более того, при тестировании удобнее и нагляднее будет если приложение упадет. Для логирования можно использовать сторонние модули, например, тот же Winston позволяет отлавливать исключения и продолжать работу приложения (не убивая его).

        По приватным и публичным методам — это лишь соглашение, но никто не защитит от прямого вызова этих методов. Удобнее обернуть модуль в анонимную функцию, а в ней все публичные методы определить в объекте и его возвратить.

        var module = (function() {
            var privateMethod = function() {
                // определение метода
            };
        
            return {
                publicMethod: function() {
                    return privateMethod();
                }
            };
        })();
        


        По совету номер 6. В своем случае я использую стандартную систему модулей Node.js подгружая json
        // config.json
        {
            "param1": "value1",
            "param2": "value2"
        }
        
        // app.js
        
        var config = require('./config.json');
        
        config.param1 // value1
        


        Совет 8. Почему бы не использовать существующие решения async и Q (кому что нравится)?

        Вообще мне в сообществе node.js нравится тот факт, что на каждую задачу можно найти готовый модуль, решающий ее, не изобретая велосипедов (велотренажеры не в счет)
        • 0
          Дополню по поводу исключений: на своём опыте пришлось столкнуться с ситуацией когда исключение бросается в одном месте, а трейс отображается из совершенно другого модуля. так было, например, с модулем node-curl, который ловил каким-то образом эксепшен, который должен был пойматься конструкцией try-catch в совершенно другом месте кода. Описание довольно сумбурное, но и проблема тоже оказалась непростой. Для себя решил — никаких эксепшенов в ноде.
          • 0
            Каждый файл подключенный в nodejs и так оборачивается в функцию, не изобретайте велосипед. Просто объявите через var или напишите именованную функцию, а все что нужно вернуть верните через exports.
          • +2
            Поздравляю с успешным завершением этого в общем-то непростого предприятия :) Хотелось бы узнать подробности, например: сколько времени, финансов и прочих ресурсов нужно, чтобы издать что-то подобное?
            • +2
              Было бы интересно в целом в виде статьи все это почитать — от идеи до реализации.
            • 0
              А почему нельзя обойтись для первого совета просто конкатенацией строк? Читабельность запроса будет такой же. А вообще, разве в NodeJS нет никаких queryBuilder?
            • +1
              Любопытно… Интересно узнать, сколько времени и ресурсов надо, чтобы издать что-то подобное?
              • +3
                Обложку оформили — супер =)
                • +2
                  Тот случай, когда хочется заиметь книгу в первую очередь из-за обложки.
                  • +3
                    Это пародия на Рене Магритт.
                    • 0
                      Спасибо, а то я долго думал, что лошадь с жокеем делают на крыше авто.
                      А так я имел в виду всю обложку в 8-ми битном стиле — прямо радует и глаз и душу, побольше бы таких обложек.
                • +8
                  Насчёт совета № 4 предостерегаю: употребление try…catch должно быть необыкновенно осторожным, потому что оно приводит к деоптимизации функций на движке V8 — а значит, и в Node.js.

                  Простой обёртке (которая внутри себя только вызывает другой метод) деоптимизация сильно не навредит. Но если внутри try…catch расположить нечто более сложное, то неизбежны проблемы со скоростью.
                  • 0
                    По 8 совету, использую замечательную библиотеку bluebird, обещания рулят!
                    • +8
                      Совет 1. SQL запросы лучше хранить отформатированными
                      Совет 2. Жизнь становится проще, когда API различных компонентов принимает на вход любой формат

                      Общий совет, подойдёт к любому ЯП.

                      Совет 3. Разукрасьте консоль и отформатируйте вывод информации

                      Как только Вы наиграетесь с консолью и начнёте весь лог укладывать в БД, Вы откатитесь к первоначальному нечитаемому логу. Решение более сложное. В development окружении сойдёт консоль, в production — уже нужно прибивать любую раскраску.

                      Совет 4. Оборачивайте все API в try/catch

                      Не используйте throw в runtime и не нужно ничего оборачивать. Используйте принятый стандарт записи callback-функции. function callback(err, result).
                      Совет 5. Собирайте запросы в конфиги
                      Совет 6. Выносите все в конфиги

                      Общий совет, подойдёт к любому ЯП.
                      Совет 7. Работа с файлами и Модуль Social Link для СЕО

                      Не понятно при чём здесь node.js вообще. Но вот следующее, я бы охарактеризовал как вредный совет:
                      Притом, чтобы не страдать с callback-функциями и различными проблемами асинхронности, всю работу с файлами я всегда делал в синхронном режиме.

                      Вы нарушаете саму идеологию асинхронного ввода/вывода, за что Вам будет больно.
                      Совет 8. Без callback`ов жизнь проще

                      Тоже в раздел вредных советов. Используйте callback`и. Не нравится, или говнокод получается — вас спасут promise`ы. Или не пишите на javascript, найдите другой язык… без колбеков.

                      Итого:
                      4 общих совета по программированию вообще. Даже не знаю зачем они, это приходит с опытом;
                      1 совет так себе, буду считать, что полезный (про консоль). Вреда от него не будет;
                      1 бессмысленный совет использовать try catch в асинхронном потоке исполнения ( скорее вредный );
                      2 совета вредных для javascript в принципе. (синхронная работа с вводом/выводом и боязнь коллбеков);
                      • 0
                        7. Синхронно читать файлы — нормально, но делать это можно только во время прогрева приложения (чтение конфигов, шаблонов, чего угодно ещё что случается один раз).
                        • 0
                          Не спорю. Синхронная работа возможна во время первоначальной загрузки (если точнее, до первого асинхронного вызова). Так же как впрочем не страшны и throw в этот момент. Но как только приложение сделало асинхронный вызов, например, начало читать сокет, после этого всё: никаких синхронных вызовов и throw.
                      • 0
                        Очень много как велосипедов, так и вредных советов.

                        Логи — см. пост habrahabr.ru/post/209436/. Раскраска по уровню важности — бесполезна при последующем анализе лог-файла.Нужны тэги, такие же, как и для модулей. И не забывайте, что для ошибок в unix-way надо использовать stderr.

                        Конфиги — куча их готовых, см. например, minimist

                        Глушить экзепшены — сказали выше

                        Отказ от асинхронности — сказали выше

                        Последовательное выполнение — сказали выше (async или promises).

                        Пол года назад я подумал: «А может книгу написать?», и таки написал.

                        А вот это действительно очень круто! :) Респект.
                        • 0
                          а где кнопка «помочь проекту»?
                          • +2
                            Тут «реверс-монетизация» :) Готов платить по рублю за каждого читателя.
                            • +2
                              тогда с Вас 2 рубля )

                              ps
                              спасибо за работу
                          • 0
                            По совету 8. Я бы вам посоветовал для этих целей посмотреть на стримы — весь прогрессивный мир их уже давно использует. Порой это даже более удобная высокоуровневая замена промисам.
                            • +5
                              Зачем вы вводите людей в заблуждение по поводу дебага nodejs?
                              Во-первых: nodejs умеет работать в режиме дебага из консоли.
                              Во-вторых: существует node-inspector который превращает хром в девтолзу для nodejs
                              В-третьих: В WebStorm встроена хорошая поддержка дебга, со всеми плюшками.

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

                              Без callback`ов может и проще, но это не дает вам права советовать применять синхронные функции вместо них. Хотите синхронности пишите на пхп, хотите синхронности в javascript пишите на javascript, но не давайте своих вредных советов. Для решения проблемы вложенности придумано уже много паттернов и библиотек. Самое простое и самое удобное это Promise. Они позволяют избавиться от Большего кол-ва проблем связанного с callback`ами, в том числе большая вложенность и отлова ошибок. Вскоре Promise станет частью языка, а знание их станет таким же обязательным знанию и пониманию. Про генераторы я просто помолчу.

                              В целом, книгу не читал, читать не собираюсь и если там уровень такой же как и в статье, то не советую ее читать, особенно новичкам.
                            • –1
                              ---Совет 1. SQL запросы лучше хранить отформатированными

                              Никогда и ни в каком приложении не делайте запросов к таблице из-за соображений безопасности.

                              Оберните запросы во VIEW или процедуры или функцию. SELECT a, b, c FROM vTable или EXEC spProc выглядите короче из защитит от sql injection
                              • 0
                                Зачем так сложно? Достаточно использовать параметризованные запросы.
                              • +3
                                /зануда on
                                Я так и не понял зачем главному исполнительному директору нужен модуль Social Link…

                                И не все советы полезны, некоторые даже вредны! Особенно меня коробит то, что вы призываете отказываться от коллбеков — главной фишки асинхронности! Это не правильно. Таких вещей не нужно бояться, к ним нужно привыкать и искать как работать с ними так, чтобы было удобнее.
                                • 0
                                  Книга супер! И стиль, и картинки. Интересный материал. Спасибо!
                                  • +2
                                    Советы так себе, скажу вам.
                                    • Тяжелые sql запросы следует хранить в отдельных *.sql файлах. И вообще, ребята, давно уже надо использовать es6, а там есть замечательные шаблонные литералы — и пишите себе мультилайн строки без всяких массивных хаков.
                                    • Это вредный совет. Если функция должна принимать на вход sql query string, так чего это мы должны разрешать какой-то array, тем более если учесть, что первый пункт отпадает. Всегда желательно что бы функция была как можно конкретнее.
                                    • Для дебага в консоли сойдёт, но тут ещё можно добавить группировки и различны уровни логов, как глобальные, так и групповые.
                                    • В ноде большинство вызовов асинхронные, какие здесь могут быть try..catch? Если инстанс падает из-за ошибки — это баг, ошибка должна логироваться, а какой нибудь процесс-менеджер должен подымать процесс.
                                    • Как и с первым пунктом, конфигурация не относится к коду и не должна там находиться. И вместо json лучше используйте yml, например.
                                    • Подходит лишь для баш скриптов.
                                    • Сколько можно уже мусолить тему callback-ов. Сколько же ненавистников есть, хотя ничего сложного в них нет. А совет с интервал какой-то смешной. Если уж хотите по одному файлу обрабатывать, так нужно использовать очередь, а не какой-то хак с секундным подёргиванием.
                                    • 0
                                      Вставлю свои пять копеек про try-catch, не мало уже прокомментировали, но как-то забыли про домены, которые рекомендованы быть заменой для отлова, исправления реалтайм ошибок. Кто не понимает особенностей работы try-catch и калбэков будет удивлен, почему ошибки не ловятся. Это скорее антисовет
                                      • 0
                                        А есть там что-нибудь про архитектуру crud-приложений (соц. сети и т.п.)?
                                        • +1
                                          Уже половину прочёл.
                                          Читается хорошо — я её открываю как сказку перед сном. Какие-то моменты читал в «Графика на JavaScript», а некоторые знал до этого, но всё равно почему-то интересно читать.
                                          Книга довольно сложная, не для новичков, из-за использованного словарного запаса, оборотов, резкого перехода от поверхностного описания в существенные детали.
                                          Но, повторюсь, читаю как сказку на ночь, интересно!

                                          Стал бы я её покупать? Нет, как-то не хочется. Не вижу её ценности, если открою через пол года.
                                          • –2
                                            Простите, а остальные советы в этой книге — они вот такого же примерно уровня?

                                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.