Как стать автором
Обновить
235
0
Timur Shemsedinov @MarcusAurelius

Chief Technology Architect at Metarhia

Отправить сообщение

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

Абстрагируясь от смысла статьи, сделаю код-ревью, блоков кода из нее:

  1. Как в 2021 в статью пробрались var? Очень много где в статье используется let, а нужно const. Ничего не мешало вот тут тоже использовать const: var data = []; или тут var triplify = (x) => 3 * x;

  2. В этом блоке пропущена обработка ошибок, гораздо лучше такое писать на интерфейче async iterable:


    fs.createReadStream(inputFileName)
    .pipe(csv(csvOptions))
    .on('data', (datum) => data.push({'x': Number(datum[columnX]), 'y': Number(datum[columnY])}))
    .on('end', () => myEmitter.emit('reading-end'));

    можно переписать через for..await а еще лучше сделать свой стрим и в него запайпить, страшно смотрится отлов 'end' и перебрасывание его в другой ивент-эмиттер.

  3. Вместо такой записи

    const fit_data = data.map((datum) => [datum.x, datum.y]);
    можно сделать покороче

    const fit_data = data.map(({ x, y }) => [x, y]);

  4. Так же и из двух строчек
    const slope = result.equation[0];
    const intercept = result.equation[1];
    можно сделать одну и более читабильную
    const [slope, intercept] = result.equation;

  5. Засилье магических чисел по всему коду

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

Спасибо! Скоро снова начну записывать. У нас 21 декабря релиз Метархии 2.0, а потом начну по базам данных, по ноде и по архитектуре писать лекции, уже десятка три тем в очереди стоят.
Позавчера Node.js 14 стал LTS начиная с 14.15.0
Ура, товарищи!
nodejs.org/en/blog/release/v14.15.0
Я записал 200 часов лекций, но их мало кто смотрит и все равно все пишут лапшу, учась по говнокурсам. Большая проблема мидлваров — что они создают shared state, а люди думают, что в однопоточном языке они защищены от проблем состояния гонки (race conditions), но это не так, о чем у меня есть несколько докладов на jsFest и fwdays. Я не против шаред стейта, но нужно уметь его готовить, нужны блокировки, мьютексы, семафоры, а ни кто этого не использует. Шаред стейт идет или из замыканий или из примесей в объекты (в те же Request и Response). А про GoF паттерн «цепочка ответственности» в мире ноды мало кто знает и не проводят параллели с мидлварами. А основная идея «цепочки ответственности» в том, что только одно звено должно мутировать состояние, передавая управление другу другу по цепочке, они и выясняют, чья же ответственность в этом случае, но менять состояние может только тот, кто принял на себя ответственность. А в мидлварах не так сделано, все все мутируют, а еще и события навешивают, потом управление уже ушло дальше, а события их догоняют, происходит коррапшен данных, а в сокет пишут из разных мест приложения. Когда все ломается, то люди переставляют мидлвары местами, заплатки ставят, но это все не стабильно, это все идет из того, что мидлвары это антипаттерн и это должны узнать и признать все.
Я считаю, что статья очень полезная, в тектовом виде нет аналогичных. Все до сих пор радуются мидлварам, я с 2012 года говорил, что это маразм, и ты чуть ли ни первый, кто это тоже понимает. Ну и по другим вопросам, домен в центре — это классика, я до этого на C#, C Builder, Delphi так писал и просто перенес это в ноду, но тут так ни кто не пишет. Переломить этот стиль сложно.
Модуль cluster это плохой способ масштабирование, если у нас более 6-8 процессов, все подключения проходят через родительский процесс, а потом передаются по IPC в дочерние, на большом кол-ве дочерних можно видеть, 100% загрузку главного процесса и недогрузку дочерних.

Я предлагаю масштабироваться при помощи тредов открывая по 1 порту в каждом, а балансировать в отдельном Auth-сервисе, при входе или первом контакте клиент получает токен и несколько точек подключения host:port, подключается к первой по токену и попадает в свой родной тред. При чем, я преимущественно во всех проектах использую вебсокеты для веба и TLS для мобильных (дальше планирую на http3 переходить). Если связь пропадает, то параллельно пробуем переподключиться к основному и запасным точкам подключения, если все открылись, то берем предпочтительную (основную) если основной сокет не подключается, то переходим на запасные. Таким образом не нужно весь трафик пропускать через один балансировщик, а распределение происходит только при создании сессиий.

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

Готового решения я сейчас не могу предоставить, но целая группа в которой много контрибьютеров ноды, работает над технологическим стеком Метархия, который будет готов для продакшена к концу года, в нем масштабирование будет решено из коробки. А пока можно смотреть прототип в моем Статрет ките и помогать нам все это быстрее привести в порядок.
Передача cpu-жрущей операции в воркер существенно дешевле передачи в другой инстанс: передавать можно через SharedArrayBuffer и MessagePort, а при использовании CAS можно даже общаться через расшаренную память, см. мой доклад: «Разделяемая память в многопоточном Node.js. Тимур Шемсединов. JS Fest 2019 Spring»
и лекции:
Вообще, архитектурное решение хорошее, но к нему слишком длинная подводка и описание не очень проблемных проблем. Модель в центре — вот основа, а не ssr и «проблема избыточных/недостаточных данных». Хорошие решенич были известны и до веба, просто веб не перенял опыт Дэлфи, Сибилдера, Сишарпа, Джавы… веб начал все сам изобретать, не читая книг. Вот и накрутили, а теперь только начали немного заглядывать в литературу и повторять то, что уже было и хорошо себя зврекомендовало.
Пример схемы, в ней и методы могут быть (прямо тебе дата-центрическая архитектура с доменом всередине):
({
  Category: { category: 'Category', index: true },
  StorageKind: { domain: 'StorageKind', required: true, index: true },
  Status: { domain: 'IdStatus', required: true, index: true },
  Creation: { domain: 'DateTime', required: true },
  Change: { domain: 'DateTime', required: true },
  Lock: { domain: 'Logical', required: true, default: false },
  Version: { domain: 'Version', required: true, default: 0 },
  Checksum: { domain: 'SHA2', required: true },

  CheckCategory: Validate(record => {
    if (record.Status === 'Actual' || record.Status === 'Historical') {
      return !!record.Category;
    } else {
      return !record.Category;
    }
  })
});

Еще примеры: github.com/metarhia/globalstorage/tree/master/schemas/system
Ни каких декораторов, ни каких require, ни каких мидлваров даже под капотом, в прикладном слое вообще нет global и все интерфейсы под фризом, вместо orm схемы, и схемы могут валидировать как объекты предметной области, так и структуры данных и интерфейсы (сигнатуры методов). Но еще очень много делать, хотя у нас грант на это есть и несколько крупных компаний внедряет и помогает, все будет в оупенсорсе.
У меня в NodeJsStarterKit сделан DI на для JS на базе vm.createContext и vm.runInContext.
А сейчас я делаю возможность для impress писать не только js методы, но ts и AssemblyScript. При этом, все метаданные про методы описываются декларативно, пример:
({
  access: 'public',
  method: async ({ login, password }) => {
    const user = await application.auth.getUser(login);
    const hash = user ? user.password : undefined;
    const valid = await application.security.validatePassword(password, hash);
    if (!user || !valid) throw new Error('Incorrect login or password');
    console.log(`Logged user: ${login}`);
    return { result: 'success', userId: user.id };
  }
});

а код методов может выглядеть очень кратко:
async ({ countryId }) => {
  const fields = ['Id', 'Name'];
  const where = { countryId };
  const data = await application.db.select('City', fields, where);
  return { result: 'success', data };
};

или даже
({ countryId, minArea, maxArea }) => application.db
  .select(['cityId', 'cityName', 'population'])
  .from('locality')
  .where({
    countryId,
    lacalityType: 'city',
    population: { '>': 1000000 },
    area: { between: [minArea, maxArea] },
  })
  .timeout(5000)
  .cache(2000)
  .paging(100);

Уже сейчас есть: подгрузка изменений с hd без перезагрузки процессов, утилизация CPU через потоки, очередь запросов на вход в API, авто балансировка и куча всего. В стартер ките все это поместилось в 25кб без зависимостей (для ознакомительных с внутренностями целей), а в impress все так же, но с оптимизациями и распилено на npm-модули. Можно посмотреть архитектуру в стартер-ките, но платформа будет готова только к концу года, с прозрачным масштабированием стейтфул приложений.

Мидлвары — сломанная версия паттерна "цепочка ответственности" развращающая не знакомых с SOLID, GRASP и GoF при помощи шаренного состояния и сайдэффектов.

Одобряю! Почти полностью совпадает с моими 3 весенними вебинарами на jsfwdays: https://fwdays.com/en/event/node-js-in-2020
Кроме одного: декораторы — зло, nest.js сделал большую работу по уничтожению центра говнокода (express) и но он умрет из-за TypeScript.

Слава вебсокетам! Смерть socket.io!
Кстати, кое-что быстрее работает, если оно полностью в юзерспейсе на js живет, чем на с++, потому, что js работает не так уж и медленно, а накладные расходы на взаимодействие между js и c++ действительно большие. Тут нужно пробовать всегда, иначе нельзя заранее сказать. Эта штука с отслеживанием ресурсов, по хорошему вообще должны быть достаточно глубоко в v8 интегрирована чтобы стать быстрой, тут нужны оптимизации, а то из всех объектов торчат эти Symbol с ресурсами в виде примесей, а это портит форму объектов.
В тестовом режиме есть AsyncLocalStorage
Да, спасибо, конечно же, я поправил. А c `async_hooks` пока сам присматриваюсь и экспериментирую, но еще в продакшен не пускал и в лекциях не советовал. Если есть где ссылка на багрепорт с проблемами, буду очень признателен.
Другая природа языка, потоки есть, worker_threads в ноде и workerы есть в браузере, но у них другой смысл и применять их как потоки в Java, C++ и C# не выйдет. В JS все на асинхронном программировании, это дико сложнее, но дает преимущество в утилизации ресурсов. Асинхронно можно писать системный код, но вот бизнес-логику нужно писать в псевдо-синхронном стиле, на async/await.
Этот стартер кит показывает, что можно взять 500мб зависимостей, а можно написать 15кб. Что находится в этих 500мб и действительно ли там все тестами покрыто и хорошо поддерживается, у меня вот сомнения. А 15кб это очень мало, их можно посмотреть и понять, их даже поддерживать можно. Ну и я эти 15кб покрою тестами и можете их переиспользовать, как Вы любите. Возможно, я допишу еще кое-что и там будет 20кб, но не 500мб.

Информация

В рейтинге
Не участвует
Откуда
Киев, Киевская обл., Украина
Дата рождения
Зарегистрирован
Активность