Pull to refresh
17

User

9
Subscribers
Send message
Я не мог понять, почему она такая глупая и простая, намного проще, чем любой API для удалённой работы, и почему компьютерные системы, кажется, не способны на такое.

Никто этого еще не придумал потому что задача по сложности эквивалентна синхронизации состояния в распределенных базах данных (а это просто огромная и сложная область да еще с кучей фундаментальных ограничений). Вот как вы собрались работать с шаред-состоянием в этих телепроцессах на разных машинах? У вас не то что там проблемы с многопоточностью как в обычных потоках — у вас появятся куда более серьезные проблемы консистентности из-за того что будет отсутствовать даже банальный атомарный бродкаст (который уже обеспечивается кеш-когерентностью самого процессора фундаментально упрощая проблемы многопоточного программирования). В итоге вам придется начинать все с нуля и алгоритмов вроде paxos-а или raft-а и погрузиться во все тяжкие распределенных систем и транзакционности.

Согласен. Двухстороннее связывание решает эту проблему (если правильно его спроектировать и запретить локальное состояние и оставить только это самое связывание и динамическое добавление полей) но на текущий момент у реакта, jsx или даже js есть фундаментальные ограничения которые не позволяют использовать эту фичу удобно и в полную силу (предполагаю поэтому и нужны шаблоны $mol потому что в жс описывать такие связи получится неудобно или нетипизируемо)


Вообще-то "двухстороннее связывание" вообще очень редкий зверь и похоже нигде кроме $mol его нет.
С первого взгляда даже может показаться что двухстороннее связывание это просто способ избежать болерплейта передачи вложенному компоненту вместе с переменной заодно и коллбека на ее изменение. Но если представить что мы во вложенном компоненте объявляем состояние только в том объекте который нам передал родительский компонент (а он в свою очередь храниться в свойстве объекта который был передан еще выше и т.д по цепочке) то в итоге получится что с одной стороны у нас как бы есть концепция "локального состояния" — любой компонент на любой глубине ui-дерева может объявить переменную состояния без необходимости декларировать где-то в другом месте (в родительском компоненте или например с глобальном сторе) а с другой стороны все это состояние на самом деле хранится в дереве единственного root-объекта и к состоянию любого глубокого компонента можно добраться извне или с любого компонента в любой другой части ui-иерархии

-данные о dirty, validation, touched и пр. и пр. в state

А вообще мне кажется redux надо запретить в первые годы использования React, чтобы он не травмировал представление о React и SPA в целом :D
Люди начинают мыслить очень узко и не видеть всей картинки. Всё пихать в стор, плодить мульёны файлов, а потом героически со всем эти сражаться, когда минорные фичи задевают 250 файлов в разных частях приложения.

А мне кажется совсем наоборот — это до тех пор пока связанность фич в проекте небольшая и не будет увеличиваться то можно позволить изолировать стейт в отдельных компонентах и не выносить в глобальный стор.
Но если появится какая-нибудь задачка, например — в совсем другой части приложения, на другой странице нужно при доступе к чему-то проверить что юзер заполнил форму и показать надпись, мол "друг, дополни эти поля которые ты начал заполнять и исправь такие-то поля которые невалидны" то всё, приехали — вам придется теперь выносить состояние полей — dirty, validation, touched которое раньше хранилось внутри одного компонента в общий стор потому что теперь эта информация нужна в совсем другой ui-ирерахии компонентов и соотвественно вместе с вынесением потребуется переписывать весь код работы с этим состоянием.
А вот если бы статусы полей формы изначально хранились в сторе то вам бы не пришлось бы переписывать уже существующие компоненты и фичи
А заказчику или продакт-менеджеру ведь не объяснишь что мол какая-то новая фича требует каких-то там непонятных архитектурных изменений — заказчик обычно думает о фичах в контексте того что можно делать любые проверки или отображать любую информацию в любой части приложения.
И я еще не видел ни одного проекта (который развивается и постоянно требует добавления новых фич) в котором бы решение изолировать какое-то состояние не приводило бы к проблемам — я вижу явную тенденцию что в любом развивающемся продукте количество фич и связность между ними будет только увеличиваться а значит решение изначально хранить любое состояние приложения в глобальном сторе более чем оправдано

Еще час я потратил, чтобы узнать, как кроссплатформенно открыть файл и узнать его размер. Кажется, никак, если нет С++17 c std::filesystem.

О, знакомая история… У меня опыта с плюсами и си совсем немного но даже этого хватило чтобы вызвать отвращение к возни с этими библиотеками (включая стандартную) и кроссплатформенностью (с кучей враперов со своими нюансами над другими враперами которые там где-то сводятся к системным вызовам). И я решил по-другому — раз мой софт все равно будет работать на сервере (или в докере) в контролируем окружении (только линукс, без тонны остального софта и сервисов всяких убунту-дебиан-дистрибутивов — то есть только само ядро с моей софтиной в виде статического бинарника в качестве pid0) — то в итоге без кроссплатформенности все стало намного проще — у меня остался один источник правды в виде системных вызовов линукса и я избавился от тучи нюансов стандартной библиотеки или других врапперов и легко написал нужную мне софтину работы с файлами и сокетами

Хорошая статья. Нечто подобное (но со стороны куда более простого языка) было и у меня. Некоторое время назад я считал что знаю javascript (как никак больше 6 лет на нем пишу) а потом открыл спеку и просто ужаснулся от того огромного количества нюансов, особенностей, моментов и разнообразных языковых конструкций про которые я до этого был не в курсе. И такое чувство что нужно не какие-то там десять-пятнадцать лет опыта — тут нужно быть разработчиком движка чтобы можно было сказать что знаешь js (хотя я не уверен что разработчики v8 знают наизусть все детали спеки). И знаете что помогло мне преодолеть этот страх от неизвестности и сбросить с плеч тот груз безысходности и необходимости всю остальную карьеру подучивать какие-то нюансы языка как какой-то там "вечный студент"? Я просто взял и написал свой парсер который парсит по белому списку лишь необходимое мне подмножество языка отбрасывая все те избыточные и переусложненные нюансами конструкции и фичи языка которые понапридумывали укуренные авторы спеки (и продолжают придумывать с каждым годом не считая то количество разнообразных пропозалов и stage0 фич). В итоге я не стал лучше разбираться в каких-то там нюансах языка — я просто перестал беспокоится о них так как в коде который я пишу эти нюансы и конструкции просто больше никогда мне не понадобятся и соотвественно скрытых нюансов просто быть не может так как мой парсер парсит все по белому списку нужных мне конструкций, нюансов синтаксиса и фич в которых я уверен

Я вот из тех людей которые твердо считают что первым языком должен быть ассемблер. Потому что именно ассемблер даст фундамент и понимание того как работает память, процессор и т.д — то есть те знания которые помогут отделить зерна от плевел при изучении любого высокоуровневого языка программирования. И это важно потому что в любых современных языках куда не плюнь постоянно есть и добавляют разнообразные фичи (классы/трейты/прототипы/замыкания и т.д, не говоря про фичи связанные с многопоточностью) и понимание того как все это строится, и какова стоимость абстракций поможет новичку правильно ориентироваться в мире языков и различных подходов и практик программирования (а то например некоторые всерьез сравнивают прототипное программирование с классовым не понимая что они совсем разного уровня — с прототипами доступ к свойству это цикл с перебором свойств по цепочке прототипов когда же в классах это константное считывание по смещению в памяти)

Проблема с бенчмаркингом js заключается в том, что ты никогда не знаешь, что именно оптимизировал компилятор — твой код или (гораздо более вероятно) комбинацию твоего кода и твоего бенчмарка

Всегда можно совершенно точно узнать что наоптимизировал компилятор, достаточно посмотреть ассемблерный код в который компилируется js (через комманду node --print-opt-code --code-comments code.js) и там легко увидеть (по call инструкциям и комментариям) что заинлайнилось а что нет, либо есть инструмент для визуального отображения различных оптимизаций v8 — Turbolizer (оригинальный репозиторий тут а описание и онлайн-версию можно найти тут). А для того чтобы код бенчмарка не влиял на производительность тестируемого кода то можно не мерять производительность а просто прогнать оптимизации для конкретной функции и посмотреть на то что и как инлайнится и для этого просто нужную функцию вызываем через специальную встроенную глобальную функцию %OptimizeFunctionOnNextCall(fn) (которая будет доступна после запуска ноды с флагом node --allow-natives-syntax code.js)


Ну а после того как вы убедились что нужный код заинлайнен в инструкции ассемблера (а иначе он наверняка будет работать медленно так как v8 на текущий момент научился инлайнить очень многое — не только различные циклы, но и методы работы с массивами — всякие .map(), .filter(), .find(), а также создание объектов и функций) то дальше можно совершенно точно (вплоть до тактов) предсказать время работы кода — достаточно понять как работают кеши процессора (https://www.youtube.com/watch?v=JU_RAcsfQVs), немного про то как работает виртуальная память (https://www.youtube.com/watch?v=dFquxC6qTSA) ну и конечно же дока по процессору (https://software.intel.com/en-us/articles/intel-sdm) где с точностью до тактов расписано время работы каждой ассемблерной инструкции

Почему все так любят добавлять кеш к серверу? Это же сразу добавление в проект race-conditions и проблем с консистентностью данных. Советую посмотреть доклад на эту тему — https://www.youtube.com/watch?v=5ZjhNTM8XU8

И какой же по вашему нормальный формат даты и времени? В js unix time можно было получить всегда. А для других форматов получаем слишком много нюансов — https://habr.com/ru/post/146109 и https://habr.com/ru/post/313274/

Такое чувство что весь этот фронтенд катится в ад со всей этой раздутой сложностью. Интересно есть ли в it-индустрии области где для тех же 100к требуется меньше знаний? Может быть чисто бэкенд-разработка? Или database (dba) разработка, или может разработка встраиваемых систем и микроконтроллеров?

Вот смотришь на весь этот прогресс и удивляешься что например купив за пару сотен долларов 7нм процессор становишься обладателем невероятно длинной цепочки открытий, огромных вложений и труда. Интересно есть ли попытки собрать эту цепочку воедино как например в известном рассказе Жюля Верна "Таинственный остров" (про то как несколько человек попали на необитаемый остров и не имея ничего с собой пошагово проходят технологический прогресс от выплавки посуды из глины до телеграфа) только более формально — собрать все "зависимости" 7нм процессора до уровня первобытного человека и пошагово их описать (отсортировать в топологическом порядке) ?

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


Почему без объявления типов?

Возможность указать тип имеет тенденцию усложняться — просто указать тип недостаточно надо еще добавить возможность generic-типов а потом потребуется добавить контр- и ковариантность и различные ограничений по иерархии типов а потом возможность объединения-пересечения типов, но потом этого тоже будет недостаточно и появится желание добавить conditional-типы как в последнем тайпскрипте, а потом всякие параметризированные или зависимые типы как в julia или idris — и в итоге внутри языка мы создаем еще один язык со своим синтаксисом но уже на типах

Вдогонку к статье советую посмотреть очень крутой доклад про то как работают нереляционные базы данных — https://www.youtube.com/watch?v=yrTF3qH8ey8 (ну и также крутой доклад про атомарность и транзакции https://www.youtube.com/watch?v=5ZjhNTM8XU8)

Интересно что в рейтинге производительных фреймворков нет настоящего победителя — dpdk который выдерживает миллион запросов в секунду на одном ядре (https://habr.com/ru/post/416651)

Разворот строки это отличная задача для собеседования, она интересна тем что для успешного решения собеседующему даже не нужно писать код. Точнее тот кто сразу бросится писать код успешно провалит эту задачку и сразу будет видно что перед тобой джуниор. Когда же сеньор-разработчик вместо того чтобы начать писать код сразу задаст кучу уточняющих вопросов — что такое строка? Это список двух-байтных символов в представлении js или же это список код-символов юникода или что-то посложнее (графем и т.д)? И зависимости от ответа сеньор будет задавать уточняющие вопросы — а входит ли в понятие элементов строки всякие управляющие символы или символы из разных категорий и т.д.
И я думаю по похожему принципу можно составить кучу других задач которые смогут точно определить кем является собеседующий — джуниором который нахватался отдельных знаний (или натаскал себя на решения типичных задач для собеседовании или даже заучил как студент перед экзаменом без понимания что к чему) или сеньор у которого в голове знания разложены по полочкам и составляют единую картину

Интересно как с этой концепцией иммутабельной бд вы собираетесь поддерживать консистентность для различной бизнес-логики? Допустим юзер хочет перевести деньги другому юзеру. При параллельной обработке таких запросов может возникнуть ситуация гонки (race-condition) когда параллельный запрос увидит только только часть изменений другого запроса и таким образом перезапишет значения тем самым нарушив консистентность (не сойдутся остатки по счетам)
Ок, с предлагаемым вами иммутабельным подходом можно не изменять данные в разных местах а просто запушить в лог некую запись об операции перевода а потом при чтении выполнить reduce и получить остатки по счету.
Но стоит только добавить условие что юзер может выполнить перевод только при положительном остатке так вся эта идея с иммутабельностью проваливается потому что уже не получится запушить в лог факт операции так как клиенту нужно вернуть либо успех либо ошибку а значит проверку положительного остатка при переводе (редюс по всему списку переводов) нужно выполнить в самом запросе
И таким образом получаем на порядок худший вариант чем изначально "мутабельная" версия так как редюс списка истории переводов (чтобы проверить остаток) будет занимать больше времени что увеличивает время конфликта с другими параллельными запросами (не говоря уже про саму неэффективность редюса при каждом запросе)
И в конечном счете получается что мутабельность (точечные изменения в разных местах) и поддержка нужных индексов вместо пуша в лог и свертки (или всяких там подходов разделения чтения и записи а-ля cqrs) это самый эффективный способ реализации serializable-транзакций в базах данных (если конечно вам нужна консистентность чтобы сошлись остатки по счетам). Кстати советую посмотреть хороший доклад про уровни изоляции транзакций https://www.youtube.com/watch?v=5ZjhNTM8XU8
Ну а хранение данных полнотью в оперативке (с консистентным сохранением на диск в режиме append-log) позволит выполнять несколько сот тысяч таких serializable-транзакций в секунду.
Правда sql-базы под это не заточены но яркий пример базы данных которая умеет в больше 100к serializable-транзакций в секунду это Tarantool (https://habr.com/ru/company/oleg-bunin/blog/340062/, https://habr.com/ru/company/oleg-bunin/blog/310690/).
Если вкратце то отличия подобных тарантулу in-memory баз от sql-баз (когда просто увеличиваем кеш) заключаются в следующем:
а) не нужно поддерживать индексы на диске — так как используется только последовательная запись в конец файла то получаем скорость больше 100мб в секунду даже на крутящихся дисках а это позволяет записать больше сотни тысяч транзакций в секунду в бинарном формате
б) изначально заточена под хранение в оперативке архитектура которая намного эффективнее кеша sql-баз — подробности тут — https://habr.com/ru/company/oleg-bunin/blog/310560/)
в) при переходе с клиентских транзакций на серверные уменьшается время конфликта параллельных запросов и вообще необходимость в mvcc так как можно тупо выполнять транзакции в одном потоке что гарантирует serializable. Серверные транзакции отличаются от клиентских тем что вместо того чтобы стартовать транзакцию на клиенте и посылать отдельные запросы а потом посылать коммит (как это традиционно делают c sql-базами) — в базу одним запросом сразу передается вся логика обработки данных включая if-ы и разные циклы и вся эта логика уже выполняется на самой бд максимально близко к данным

А есть еще подход CSS-in-HTML (когда пишем стили рядом с тегами: <div style="margin: 10px, padding: 10px; color: red; ....">...</div>) который решает и проблему модульности стилей и проблему синхронизации с компонентами-версткой (удаление куска верстки заодно удалит и стили и т.д) и проблему именования классов

А почему вы завязываетесь на древний способ 2д отрисовки — возней с пикселями, копиями, битмапами, кешированием и софтварной растеризацией? Сейчас практически на каждом устройстве есть поддержка как минимум OpenGL ES а это значит что графическую подсистему можно построить так что заниматься растеризацией и прочей возней с пикселями будет видеокарта а со стороны программы или os достаточно просто на каждый фрейм отрисовки передать на gpu массив объектов данных примитивов (если это прямоугольик то координаты вершин или точка + ширина-высота, если кривая безье то координаты контрольных точек и т.д) — и уже на видеокарте в шейдерах будет происходить отрисовка. Причем примитивы можно бесконечно усложнять поскольку шейдеры можно программировать.
Что касается взаимодействия отдельных программ-окон то тут есть 2 варианта
1) Каждое окно будет лично взаимодействовать с видеокартой — вызывать функцию отрисовки (draw-call) но результат будет сохраняться во временный буфер-текстурку а потом os еще раз вызовет отрисовку композируя из нескольких текстурок итоговую картинку. Причем надо заметить что результат отрисовки каждого окна можно хранить на видеокарте а не заниматься копированием между cpu и gpu
2) Можно попробовать построить взаимодействие так чтобы вызов отрисовки (draw-call) на видеокарте был только один — для этого собираем результат от каждого окна и дополнительно препроцессим смещая координаты — либо на уровне массива примитивов (через постпроцессинг либо через некий общий апи рисования) смещая координаты каждого примитива с соотвествии со смещением каждого окна либо на уровне компиляции кода шейдеров добавить дополнительный код который будет относительно каждого окна добавлять смещение для gl_Position

Хм, а если бы они вместо cookies сохраняли бы в LocalStorage то штрафа бы не было? Вообще непонятно почему вокруг GDPR и закона про персональные данные все говорят только про куки если есть еще куча различных способов сохранить индефикатор сессии на устройствах клиента

Пожалую попробую прояснить подробней — суть не в том чтобы юзать kvm вместо докера — тут суть в том чтобы избавиться от лишнего программного слоя. Сейчас когда заказываем машинку у хостера (vps или различные облачные решения) то вместо целой физической машинки получаем лишь запущенный образ виртуальной машины с другими такими же соседями.
И дальше поверх этой запущенной машины мы добавляем еще один программный слой в виде докера для еще одной изоляции. И появляется вопрос — почему нельзя точно также как с докером собрать весь код, зависимости и окружение вместе в виде некого контейнера но только без докера? То есть это будет не контейнер (который будет запускаться внутри виртуальной машины которую нам предоставил хостер) это будет уже сразу готовый iso-образ операционной системы который будет запущен хостером на той виртуальной машине которую мы арендуем.
Уже сейчас многие хостеры предоставляют возможность загрузить кастомные iso-образы — и если можно собрать весь код и деплоить сразу в виде iso-образа то тогда докер становится просто ненужной абстракцией и лишним программным слоем

Information

Rating
7,470-th
Registered
Activity