Pull to refresh
19

User

9
Subscribers
Send message
Использование этой простой стратегии делает компоненты более декларативными и упрощает понимание их кода.

Серьезно? Что же, давайте более подробно проанализируем этот кусок кода


import React from 'react'

const Student = ({ name }) => <p>Student name: {name}</p>
const Teacher = ({ name }) => <p>Teacher name: {name}</p>
const Guardian = ({ name }) => <p>Guardian name: {name}</p>

const COMPONENT_MAP = {
    student: Student,
    teacher: Teacher,
    guardian: Guardian
}

export default function SampleComponent({ user }) {
    const Component = COMPONENT_MAP[user.type]

    return (
        <div>
            <Component name={user.name} />
        </div>
    )
}

Сколько раз ревьюеру (который видит этот кусок кода первый раз) нужно будет промотать глазами чтобы понять что происходит в коде?
1) видим строчку COMPONENT_MAP[user.type] — ага, нужно найти взглядом эту переменную из внешнего скоупа и понять что там хранится,
2) видим строчку рендера какого-то компонента <Component name={user.name} /> — опять нужно найти взглядом переменную из внешнего скоупа и понять что записано в переменную Component.
3-6) и наконец по значениям-ссылкам на три компонента которые были записаны в COMPONENT_MAP мы теперь должны найти каждый компонент и понять что он рендерит


А теперь сравним это с такой версией


import React from 'react'

export default function SampleComponent({ user }) {
    return (
        <div>
          {user.type == "student" && 
             <p>Student name: {user.name}</p>
          }
          {user.type == "teacher" && 
             <p>Teacher name: {user.name}</p>
          }
          {user.type == "guardian" && 
             <p>Guardian name: {user.name}</p>
          }
        </div>
    )
}

Сколько раз в этой версии разработчику нужно будет мотать глазами чтобы понять что происходит в коде? Не проще ли становится код когда вообще не нужно мотать глазами? Не является ли вторая версия более "декларативной" ?

А что вы скажете насчет веб-компонентов? Разве они были придуманы не для того чтобы избавиться от проблемы ограниченного набора и неоднозначности "семантических" html-тегов? Почему вместо разнообразных <div>, <span>, <header>, <footer>, <main>, <section>, <article>, <h1>, <ul>, etc нельзя использовать кастомные веб-компоненты которые будут лучше подходить по семантике и функционалу к конкретной ситуации и лучше соответствовать дизайн-системе и семантически-функциональной структуре сайта/веб-приложения?

А кто-нибудь знает почему не взлетела идея с FPGA? Ведь тогда каждая программа могла бы сама определять наиболее эффективные для своего исполнения инструкции, кеши и пайплайны. Или, например, с++/rust компилятор после всевозможных оптимизаций мог бы компилировать программу не в набор ассемблерных инструкций а сразу в схему транзисторов и связей которая будет максимально эффективна для конкретной программы

А почему такой скромный заголовок? Судя по тому что в википедии написано что температура ядра солнца всего лишь 15 млн градусов то достижение в 100 млн градусов надо было назвать как-нибудь "Ученые создали и двадцать секунд удерживали самое горячее вещество в солнечной системе, в 7 раз горячее солнца!!!"


А вообще цифры конечно впечатляют и сразу возникает такой вопрос почему так несимметрично — значит если нагревать так и до 100 млн можно а если охлаждать то всего лишь до -273 градусов и больше нельзя (так как абсолютный ноль), разница аж целых 6 порядков!

Ну вот я использую голый реакт и получается даже более удобно чем с mobx, вот пример — https://codesandbox.io/s/competent-engelbart-cltwg. Нет никакой магии геттеров-сеттеров или прокси-объектов, просто вызываем функцию актуализации когда нужно актуализировать view с состоянием. Есть и недостаток в виде менее эффективного обновления (реакт будет делать diff всего приложения при изменении состояния). Но тормоза появляются лишь на больших приложениях (> 10к дом-нод) что встречается нечасто и для 99% mvp-приложений можно обойтись без mobx (и потом можно легко подключить его только в случае появления тормозов diff-механизма реакта).

Сравнение некорректное. Java это язык а нода это рантайм (конкретная реализация взаимодействия с IO операционной системы). И скорость ноды и этой хваленый event loop и т.д — это все заслуга системного IO операционной системы — например на линуксе это системный вызов epoll_wait(..) — который позволяет одним потоком обслуживать много сокетов. Это значит что аналогичную эффективность NodeJS (скорости работы с io и обслуживание одним потоком многих tcp/http запросов) можно получить на всех популярных языках — не только на java но и например на php — достаточно всего лишь прокинуть системные вызовы epoll_wait/epoll_create/… в интерпретатор или компилятор языка.

Как известно, в Node.js реализовано однопоточная событийно-ориентированная модель. Это отлично подходит для большого количества запросов, но совершенно не годится для распараллеливания вычислений или реализации сложной бизнес-логики.

Вы серьезно? Тогда такой вопрос — как вы собираетесь поддерживать атомарность при выполнении сложной бизнес-логики? Многопоточная модель это прямой путь к race-conditions и неконсистетности данных. Вы знаете что в базах данных (включая postgres, mysql) по умолчанию не включен serializable уровень изоляции и поэтому любую бэкенд-логику которая работает с бд отдельными запросами нужно врапить в эти транзкции (от начала и до конца) иначе рано или поздно у вас появятся race-conditions и неконсистентность данных (https://www.youtube.com/watch?v=5ZjhNTM8XU8)?
А теперь вопрос — какой тип бд позволяет обрабатывать транзакции с любой логикой (запросы к различным таблицам, включая условия и циклы) c seriazlizable-уровнем изоляции со скоростью > 100к транзакций в секунду? Вы не поверите но это такие базы данных которые выполняют все транзакции в одном потоке и вполне могут быть написаны на Node.js. Яркий пример такой бд — это Tarantool (https://www.youtube.com/watch?v=yrTF3qH8ey8)


А что касается скорости одного потока javascript — то он вполне находится на уровне с++ (если не относиться наплевательски на советы по производительности) — вот доклад где сравнивается с++ и js — https://www.youtube.com/watch?v=UJPdhx5zTaw и js всего лишь на 17% медленнее чем с++ с O3-флагом оптимизации (и это было еще в 2012 году)

Вспомнил ваш ник в статьях CodeRush :) Вы случайно не в курсе что изменилось с тех пор? Насколько сложно сейчас вирусу с правами админа или рута пережить переустановку ос? И кстати если ли смысл как-то защищаться на этом уровне? Мол из-за таких защит сам юзер (имея права админа) уже не сможет просто обновить bios и перезагрузить — ему придется делать дополнительные манипуляции (писать на флешку, зажимать горячие клавиши при включении и т.д). И если мы не хотим доставлять неудобств юзеру то появляются такие уже мысли — мол пусть операционные системы становятся менее дырявыми и делают гранулярные права на те или иные возможности (как в ios и android), и если уж программа получила права рута так лишь бы не перезатерла одноразовые fuses в биос — чтобы можно было при переустановке (или покупке б/у) вычистить/сбросить весь перезаписываемый код в биос (и других разнообразных firmware-областях)

У вас в таком коде


socket.on('data', (data: Buffer) => {
  if (data[0] === this.OPCODE.SHORT_TEXT_MESSAGE) { // Обрабатываем в данном примере только короткие сообщения
    const meta = this.decryptMessage(data);
    const message = this.unmasked(meta.mask, meta.data);
    this.connections.forEach(socket => {
      this.sendShortMessage(message, socket);
    });
  }
});

не учитывается фрагментация когда буфер полученный в обработчике 'data'-события может быть длиной вплоть до одного байта

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

Вы серьезно? Знаете что я делаю когда мне нужно отобразить сложные формы как в вашем случае когда у нас "в общей сложности более 80 разных полей"?
Я не использую никакие стейт-менеджеры или библиотеки для форм я просто использую обычный реакт и в каждом обработчике поля onChange пишу примерно такое


<input onChange={(e)=>{
   AppState.form.someField = e.target.value;
   //валидация или другая логика
   actualize() //однострочный хелпер который вызывает ReactDOM.render(<App/>, el)
}}/>

Увидев вызов ReactDOM.render(<App/>), вы наверное подумаете "о боги, это же перерисовка всего приложения при вводе каждой буквы!". Поэтому позвольте мне напомнить что такое "перерисовка" в терминах реакта. В реакте "перерисовка" это просто рекурсивное сравнение двух деревьев js-объектов чтобы изменить в html/dom только то что отличается. Сравнение очень быстрое — никаких медленных обращений к дом-элементам, алгоритм линейный (просто спуск по дереву объектов и сравнение свойств с соответствующим объектом от предыдущего вызова перерисовки), сам javascript умеет компилироваться в ассеблер и его скорость на уровне с++ или даже быстрее (https://www.youtube.com/watch?v=UJPdhx5zTaw). В общем за 1мс можно "перерисовать" или точнее сравнить дерево из 50к объектов. И на этом фоне ваши желания оптимизировать вызов "перерисовки" отдельных компонентов для формы из всего лишь 100 полей выглядят забавно

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

И поэтому вы выбрали микросервисы? Вы не видите в этом противоречие? Микросервисы это изоляция по функционалу и по данным (каждый микросервис должен хранить данные в своей базе данных иначе считается что это не настоящие микросервисы). Ок, вы построили архитектуру и разбили по микросервисам — например платежами/переводами занимается один сервис а данными юзеров занимается второй сервис. Правильно? А потом на следующий день прилетает задача — вот мы хотим добавить программу лояльности и начислять юзеру какие-то баллы за переводы. И теперь для реализации этой задачи микросервису переводов нужно общаться с микросервисом который хранит данные юзеров. А теперь вопрос — как вы будете решать race-conditions и атомарное выполнение этой бизнес-логики? Речь не только про потерю связи, логику retry-ев на транспортном уровне (https://habr.com/ru/company/yandex/blog/442762) а про более фундаментальную проблему консистентной обработки данных и serializable уровня изоляции транзакций — https://www.youtube.com/watch?v=5ZjhNTM8XU8
В общем микросервисы можно применять только когда проект уже устоялся и не планирует расширяться, иначе добавление нового функционала имеет тенденцию увеличивать связность данных а это в свою очередь требует атомарного выполнения бизнес-логики которая обращается к разным микросервисам и реализации распределенных serializable-транзакций (иначе привет race-conditions и неконсистетность данных и дыры в безопасности)

Вы считаете что постоянно держать соединение дорого? Соединение в linux и в node это всего лишь файловый дескриптор размером с сотню байт. Расходов кроме памяти практически нет (браузеры либо вообще не отсылают специальные "ping"-вебсокет сообщения либо делают это очень редко — за полчаса я не получил ни одного такого сообщения, а потом мне ждать надоело)


А что касается http — в нем есть заголовок "connection: keep-alive" который сообщает серверу открыть и держать tcp-соединение (и пересылать все http запросы по этому соединению) точно так же как и с вебсокетами, плюс в версии http 1.1 это подразумевается по умолчанию (если явно не передано "connection: close"). В общем можно сказать что значительная часть интернета использует keep-alive. В таком случае у http нет никаких преимуществ перед websockets


Даже наоборот — в http есть фундаментальный недостаток — из-за того что http параллельный и "stateless" — браузеры не гарантируют что запросы на сервер поступят в том же порядке в котором были отправлены на клиенте (могут использовать keep-alive а могут и не использовать — это всего лишь оптимизация и узнать и проконтролировать со стороны javascript невозможно) и из-за этого на порядки усложняется решение одной из самых главных проблем всех бэкендов — https://habr.com/ru/company/yandex/blog/442762


А вот с вебсокетами проблема неидемпотентных запросов описанная в статье решается очень просто. Поскольку используется только одно единственное соединение которое сами контролируем то получаем гарантию что запросы на сервер будут поступать последовательно а значит на сервере достаточно сохранить только айдишник последнего запроса а не хранить айдишники для всех http-запросов (а как-то очищать по таймеру ненадежно потому потому что могут быть ситуации остановки приложений и запуска через время когда они уже были очищены)

А REST API обязательное условие? Что если разработчик в проектах использует другую технологию для взаимодействия клиента с сервером? Я например против подходов rest api и http в целом и считаю вебсокеты более эффективным способом коммуникации клиента и сервера (как минимум вебсокеты на порядок проще решают проблему идемпотетности — https://habr.com/ru/company/yandex/blog/442762) не говоря уже про реалтайм

В React Native только JIT-компиляция

Должен сказать что React Native не использует jit на iOS. Вот пруф (https://reactnative.dev/docs/javascript-environment)


Note that on iOS, JavaScriptCore does not use JIT due to the absence of writable executable memory in iOS apps.

То есть это значит что на iOS реактовский diff большого дерева компонентов будет тормозить потому что js будет интерпретироваться а не компилироваться в более оптимизированную версию как на android. Даже cordova будет быстрее потому что она использует webview со встроенным safari-движком а это единственное приложение которому iOS разрешает jit, соотвественно реакт c кордовой будет быстрее чем с react native

Я конечно понимаю что статья про rest но хочу напомнить что http это не единственный способ организации взаимодействия, есть еще вебсокеты. Я вот например выбросил http и перевел все взаимодействие клиента с сервером на вебсокеты и не нарадуюсь — мне стали не нужны все эти бэкенд-фреймворки (например expres, koa, nestjs) и библиотеки которые в основном нацелены на http-стек.
К тому же напомню что в области разработки десктопных приложений для взаимодействия клиента с сервером испокон веков использовали обычные сокеты. И только с появлением веба и потому что до некоторого времени в браузерах javascript поддерживал лишь отправку http запросов стали популярными все эти rest-подходы поверх http.
Но теперь когда у нас есть поддержка вебсокетов (а это не еще одна абстракция поверх http как бывают думают некоторые, да для установки соединения по вебсокетам используется http но дальше это просто передача хедера с размером сообщения поверх tcp) и растет популярность desktop-like web-приложений (а есть еще offline-first приложения которые могут работать без сети и нужно синхронизировать изменения) использовать http в качестве транспорта не имеет никакого смысла

Народ использовал классы раньше потому что тогда не было такого распространения компонентов и классы это был возможно единственный способ не дублировать стили при добавлении какой-нибудь кнопки в разных местах.
А теперь с появлением компонентного подхода какой смысл в классах? Нет больше той проблемы с дублированием зато есть неудобства в лишних переключениях между тегами и стилями и необходимость придумывать имена для классов.
Вопрос — если у меня есть уже компонент кпопки или какой-то карточки, зачем мне дополнительно создавать класс "button" или "card" и выносить стили в отдельный файл, или в отдельное место в том же файле? Или вот, например, когда мне нужно что-то изменить в дизайне. Я уже зашел в файл компонента <Card/> или <Button/> с целью изменить или поправить дизайн — зачем мне еще раз видеть на теге класс "card" и затем переходить в другое место для того чтобы увидеть стили? Почему бы просто не писать стили прямо рядом с тегами если мы уже разбиваем верстку на атомарные компоненты?

Способ такой. (Для его применения, надо обладать верной памятью). Надо провзаимодействовать с любым внешним объектом, хоть в чём либо превышающим ваши способности, и затем проверить результат. Например, калькулятор способен умножать числа намного быстрее, чем вы. Прекрасно! Воспользуйтесь калькулятором и запомните ответ, а затем проверьте его вручную — если ответ верен, то вы действительно можете воспользоваться внешним по отношению к вам объектом, а следовательно, не спите.

Интересно… сразу появляются вопросы:
1) А что уже доказано что мозг человека в состоянии сна не переключается например в режим суперспособностей способный переумножать числа не хуже калькулятора?
2) А может когда мозг во сне переумножает два каких-нибудь больших десятизначных числа (проверяя тот самый калькулятор) то это только видимость а на самом деле мозг усиленно пытается умножить два на два (а сам перед этим уже легко вычислил ответ когда играл роль калькулятора)

2) Проблему останова решать не нужно, если используется тайпскрипт или только подмножество js где мы можем за счет статического анализа найти циклы и рекурсию то дальше просто добавляем в цикл дополнительный код который будет проверять время и останавливать цикл если выполняется дольше положенного либо будет реагировать на кнопку остановки (если это внешний плагин в каком-то редакторе например как это работает в figma.com)
Известная компания Figma уже пыталась сделать песочницу используя всякие костыли вроде with и proxy-объекты — www.figma.com/blog/how-we-built-the-figma-plugin-system Но потом наевшись дыр они таки перешли на белый список правда через интерпретацию js собственным движком — www.figma.com/blog/an-update-on-plugin-security
Я придерживаюсь мнения что оба варианта это либо костыли либо тормоза. Правильным вариантом был бы статический анализ кода (тот же белый список но только без интерпретации — то есть со скоростью нативного js). Это правда реализовать сложнее — нужно взять некое подмножество typescript в котором невозможен будет any и будет разрешен только набор предусмотренных апишек но зато это будет белый список и эту песочницу по определению нельзя будет взломать
Интересно а как называется геометрия вселенной Симпсонов?

Information

Rating
Does not participate
Registered
Activity