Pull to refresh

Comments 46

Может, и я угодил в эту ловушку, но в предложении "Помимо связанности у нас есть и зацепленность" вместо "связанности" должно быть "связности".

сoupling - связанность

cohesion - связность

https://habr.com/ru/articles/568216/

Поправьте, если ошибаюсь.

Это дискуссионный вопрос, в интернетах о нем спорят. В англоязычной вики статьи по coupling и cohesion по ссылке на русский перевод обе ведут на одну и туже статью, где указаны вместе: "Зацеплениесцеплениесвязанностьсопряжение".

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

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

Пример в студию, что не может решить MobX, но при этом может решить Reatom пожалуйста.

Да вариантов много. Вот есть у нас процесс оформления заказа. Отдельно пилится менее важный, но полезный модуль подсказок, который никак с критичным процессом оформления не должен быть связан. Он подгружается лениво, подписывается на событие открытия формы заказа (она может быть открыта в разных местах, в том числе в модалке) и ждет событие завершения заказа, или через 1 минуту (это я сейчас придумал), показывает нотификацию "Вам нужна помощь? Напишите нам в чат!".

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

Вот еще один очень упрощенный пример:

Да вариантов много.

Вы так и не привели ни одного варианта. То что вы выдумали, решается с MobX'ом и с Redux'ом и просто на голом JS и т.п. А вообще вы слышали про такое понятие как EventEmitter?) С его помощью можно вообще элементарно решить ваш придуманный пример и без разницы что будет в паре с этим принципом, хоть mobx, хоть redux, хоть rxjs и т.п.

На реатоме достаточно просто следить за экшенами старта и окончания процесса оформления.

Без примеров конкретных в коде где обсирается MobX и решает Reatom это просто ваше предположение. Поэтому конкретный пример на codesandbox'e в студию пожалуйста.

Факт 1: на изменение стейта в мобыксе подписаться можно, на вызов экшена нельзя.

Факт 2: в реатоме можно подписаться и на изменение стейта и на вызов экшена

Факт 3: с ваших слов, мобыкс может работать только в паре с EventEmitter, те нужно еще где-то его взять. Первоначально вопрос был `что не может решить MobX?`, вы сами на него ответили

Факт 1: на изменение стейта в мобыксе подписаться можно, на вызов экшена нельзя.

А зачем собственно это нужно?) Это уже событийная модель. Это вообще не связано со стейт менеджментом. Для этого как раз EventEmitter нужен. "Недостаток" - не засчитан.

Факт 2: в реатоме можно подписаться и на изменение стейта и на вызов экшена

см. пункт 1. "Преимущество" - не засчитывается.

Факт 3: с ваших слов, мобыкс может работать только в паре с EventEmitter, те нужно еще где-то его взять. Первоначально вопрос был `что не может решить MobX?`, вы сами на него ответили

Нет, с моих слов, для вашего выдуманного примера в котором именно нужна событийная модель, на помощь приходит EventEmitter. И стейт менеджеры тут вообще не причем. "Недостаток" - не засчитан.

те нужно еще где-то его взять

2 минуты времени написать самому или нагуглить.

EventEmitter
export enum EVENT_EMITTERS {
    EXAMPLE = 'EXAMPLE',
}

export type EVENT_EMITTERS_CALLBACKS_PARAMS = {
    [EVENT_EMITTERS.EXAMPLE]: (param1: string, param2: number, param3?: any) => void;
};

interface IKeyFuncVal {
    [k: string]: (...args) => any;
}

export class EventEmitter<Events extends IKeyFuncVal, Key extends keyof Events = keyof Events> {
    logEmits: boolean = false;
    private listeners: Map<Key, Set<Events[Key]>> = new Map();

    emit<K extends Key>(eventName: K, ...restParams: Parameters<Events[K]>) {
        const events = this.listeners.get(eventName);

        if (this.logEmits) {
            let subscribersCount = 0;
            if (events) subscribersCount = events.size;

            console.log(`EventEmitter emits: "${String(eventName)}", subscribers: ${subscribersCount}`);
        }

        if (events) {
            const eventsArray = Array.from(events);
            for (const fn of eventsArray) {
                fn.call(null, ...restParams);
            }
        }
    }

    on<K extends Key>(eventName: K, fn: Events[K]): () => void {
        if (!this.listeners.get(eventName)) {
            this.listeners.set(eventName, new Set());
        }

        const events = this.listeners.get(eventName);

        events.add(fn);

        // or use unsubscribe function
        return this.off.bind(this, eventName, fn);
    }

    once<K extends Key>(eventName: K, fn: Events[K]): () => void {
        // @ts-ignore
        const unsubscribe = this.on(eventName, (...args: any[]) => {
            fn(...args);
            unsubscribe();
        });

        return unsubscribe;
    }

    off<K extends Key>(eventName: K, fn: Events[K]) {
        const events = this.listeners.get(eventName);

        if (events) events.delete(fn);
    }
}

export const globalEventEmitter = new EventEmitter<EVENT_EMITTERS_CALLBACKS_PARAMS>();

Первоначально вопрос был `что не может решить MobX?`, вы сами на него ответили

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

Итого резюмируем:
Вся ваша логика того, что якобы Reatom лучше MobX, хотя на самом деле нет(достаточно просто взглянуть на итоговый код с использованием reatom и mobx и всё становится понятно), строится на том, что в MobX не встроенного EventEmitter'a, который нужен вообще для событий, а не для стейт менеджмента))

Это статья не про стейт менеджемент. Вы обратили внимание на утверждение "отсутствуют примитивы для описания реактивных процессов". Пример процессов, на которые нужно реагировать я привел. Зачем вы сейчас доказываете то о чем никто не просил?

Спектр задач которые может решать реатом больше, на этом и остановимся.

Спектр задач которые можешь решать реатом больше, на этом и остановимся.

Нет, не шире. Нет, не остановимся. Пустые слова не являются аргументами. Т.к. вы почему-то приплетаете событийную модель(EventEmitter) к стейт менджменту.
Reatom - стейт меннеджер.
MobX - стейт меннеджер.
Событийная модель - не стейт менеджмент. Её уже 100 лет в обед и они была задолго, до такого понятия как стейт менеджмент.

Пример процессов, на которые нужно реагировать я привел. Зачем вы сейчас доказываете то о чем никто не просил?

Так это событийная модель. При чем тут вообще Reatom, MobX, Redux и т.д. и т.п.??
events.on('start-form', doSome)
events.on('finish', doSome);

Это всё вообще никаким боком не относится ни к стейт менджменту, ни к реактивности. Это просто события, которые можно испускать и на которые можно подписываться.

А вы его зачем велосипедите, когда есть стандартный EventTarget?

Он не очень удобный и нет возможности делать так:

await eventEmitter.emit('lalla', data);
// do some after all async work in subscribers

А не пробовали предложить в mobx добавить функциональность подписки на экшены, выглядит так, что там не требуется много для этого?

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

Иметь разные очереди батчинга - так себе идея.

Зачем раздувать этого тормознутого монстра ещё больше :)

Лично моя нелюбовь к мобыксу обусловлена ещё и неприятием использования прокси - слишком много проблем с ними.

Зачем раздувать этого тормознутого монстра ещё больше :)

Тормознутого?) Это вы оцениваете по синтетике, а не по приложениям в реальной жизни. Типо ой, 100тыс синхронных операций отработаю на 1ms медленнее, какой ужас и кошмар. Тем более на стороне клиента.
60 FPS это 16.6ms между каждым кадром.

Лично моя нелюбовь к мобыксу обусловлена ещё и неприятием использования прокси - слишком много проблем с ними.

1) Проблем как бы нет, только если выдуманных и высосанных из пальца.
2) Как бы, есть такая штука, называется конфиг. Вжух, и никаких Proxy нет. Только getter/setters.

import { configure } from "mobx"

configure({
    useProxies: "never"
})

слишком много проблем с ними.

Каких??? Хоть 1 настоящую проблему назовите, которую можно реально проблемой считать.

Чем дольше живу, тем меньше понимаю, зачем усложнять код событийной моделью, если всё можно написать сверху-вниз и слева-направо внутри самой вызываемой функции

export const submit = () => {
  // делаем всё необходимое
  analytics.formSubmitted()
}

Чем эта более читаемая запись принципиально хуже decoupled-решения на эвентах?

Ваш вариант разумеется самый адекватный и правильный.

Просто извращенцы не любят легких путей и пишут говнокод максимально нелепо и сложно, таким образом они думают что они умнее других)) Типа я элементарную вещь сделал очень сложной, значит я умнее того, кто элементарную вещь так и оставил элементарной. Более того, элементарные вещи не являются проблемами, а им же надо чтобы у них было много проблем, что их потом "решать", такое контрпродуктивное и анти-логическое мышление для меня остается большой загадкой. Хоть убей, ни когда не пойму тех, кто сам себе капает яму и потом зарывает из нее себя))

Тут подробно описал https://t.me/artalog/846

Тут подробно описал https://t.me/artalog/846

Ахахах, вы опять написали свой бред с умными видом. И опять игнорируете банальный EventEmitter, с помощью которого все ваши "задачи" и "проблемы" решаются элементарнейшим образом. И никакой reatom, mobx, redux и т.д. и т.п. для этого вообще нафиг не нужны(для ваших "задач" и "проблем").

По этому поводу уже был коммент - https://habr.com/ru/companies/ruvds/articles/737114/comments/#comment_25582614

В мобыксе нет встроенного EE, нужно брать сторонний или писать самому, бороться с гонками (нотификация должна быть только внутри экшена), и все равно это будет костыль сверху.

В реатоме уже есть и и работает нативно и слаженно, включая инфраструктурные тулы (логирование, мокирования для тестов). Оно просто уже есть и уже работает, в этом поинт.

Бред пишите вы, сравнивая библиотеки предлагая брать дополнительные библиотеки и выставляя это как отсутствие сложности.

В мобыксе нет встроенного EE

Да, в MobX этого нет, и быть не должно, т.к. это не имеет ничего общего с управлением состоянием и человеческой реактивностью(с использованием getters/setters и автоматической подпиской/отпиской).

нужно брать сторонний или писать самому

У каждого уважающего себя разработчика есть реализация EventEmitter и этот вопрос всегда решается в рамках до 5ти минут.
Даже если вдруг кто-то ни разу его не использовать, этот гуглится и копи-пастится всё так же в рамках 5ти минут.

бороться с гонками

Какие нафиг гонки когда события эмитятся синхронно и обрабатываются синхронно. И не надо выдумывать сказочные кейсы, чтобы попытаться оправдать это высказывание.

 (нотификация должна быть только внутри экшена)

Кто сказал? Опять ваши сказочные условия. Разумеется испускать события можно откуда угодно и когда угодно, так же как и подписываться на них можно когда угодно и откуда угодно в этом вся прелесть.

и все равно это будет костыль сверху.

Лолшто? Стандартная реализация EventEmitter это костыль? :D Вот это вы юморист однако. В таком случае следуя вашей "логике" - webpack, typescript, scss и т.д. и т.п. - это костыль сверху.

В реатоме уже есть и и работает нативно и слаженно, включая инфраструктурные тулы (логирование, мокирования для тестов). Оно просто уже есть и уже работает, в этом поинт.

Вы так говорите, как будет вставить EventEmitter куда-то это подвиг :D Тут нет никакого поинта, вы просто воткнули EE себе и пытаетесь это преподнести как фичу))) Код который приходится писать используя ваш подход всё равно слишком плох, чтобы такая вещь как встроенный EE мог быть просто бонусом.

Бред пишите вы, сравнивая библиотеки предлагая брать дополнительные библиотеки и выставляя это как отсутствие сложности.

1) Вы выдаете стандартный, базовый, элементарный подход в индустрии (EventEmitter) как сложность. А меня упрекаете в том, что я называю вещи своими именами и говорю что событийная модель в JS это просто и элементарно. Ну это же нонсенс.
2) EventEmitter это не библиотека) Это реализация publish/subscribe. Пару десятков строк кода, а реализацию я уже выше скидывал.

Как бы да, сложности тут ровном счетом 0, т.к. это стандартный и нативный подход в JS. Чего не скажешь о ваших обертках и абстракциях, которые как раз и добавляют сложности и нечитаемосоти для вашего write-only кода)

По ссылке вы частично описали тоже самое, что и в этом комменте, но я всё равно не понимаю.

Ну вот есть у вас такой код. Вы пишите, что хотите подгружать аналитику лениво, поэтому нужен декаплинг на эвентах

Но у вас же загрузка тяжёлой библиотеки в бандл будет происходить не в файле ~/features/some/analytics.ts, а где-то, где вы пропихиваете SENTRY внутрь window. Получается, в ленивом импорте здесь не будет никакого смысла.

Вы в телеграме ещё пишите, что моделей, которые нужно обмазать аналитикой, много. Но это тоже никак не мешает линейному коду. Если писать совсем просто и линейно, то эвенты проиграют в количестве кода, который нужно написать для подключения аналитики. Вот так будет выглядеть мой код:

// ~/analytics.ts
export function sendMsg(msg: string) {
  window.SENTRY.captureEvent({ message: msg });
}


// ~/some/model-1.ts
import * as analytics from '~/analytics.ts';

export function submit() {
  // Какой-то код сабмита
  analytics.sendMsg('model-1 form submit');
}


// ~/some/model-2.ts
import * as analytics from '~/analytics.ts';

export function submit() {
  // Какой-то код сабмита
  analytics.sendMsg('model-2 form submit');
}


// ~/some/model-n.ts
import * as analytics from '~/analytics.ts';

export function submit() {
  // Какой-то код сабмита
  analytics.sendMsg('model-n form submit');
}

Зачем тут эвенты? Чем вызов функции из модуля отличается от эвента конкретно в этой ситуации? Эвент здесь просто добавит indirection на ровном месте, который при отладке, фиксе багов или добавлении фичей будет только создавать головную боль.

Вот ещё ваш аргумент из телеграма: Есть процесс оформления заказа. Отдельно пилится менее важный, но полезный модуль подсказок, который никак с критичным процессом оформления не должен быть связан.

Что значит "никак с критичным процессом не должен быть связан"? Подсказки же всё равно будут связаны с процессом, просто неявно. Типа, если явной связи не видно, то связи вообще нет? Но оно так не работает :) Если под отсутствием связи вы понимаете, что код подсказок может падать, и это никак не должно влиять на процесс оформления, то для таких случаев есть try/catch или catch у промисов. Можно писать как-то так

const noop = () => null;

async function createOrder() {
  // Какой-то важный код
  await tips.showSomeTip().catch(noop);
  // Продолжение важного кода
  await tips.showOtherTip().catch(noop);
}

Такой подход простой как палка, поэтому любое изменение фичи, фикс бага, добавление функциональности делается явно. Весь код, который нужен для понимания происходящего в рантайме, можно посмотреть в IDE с помощью Go To Definition. Такой код использует возможности языка и не обязывает читателя знать какие-то специфические библиотеки.

Чем конкретно этот подход хуже эвентов?

window.SENTRY.captureEvent -> import('/sentry').then({captureEvent} => ...), если быть точным, я думал это и так понятно.

Вы зачем-то чистый доменный код разбавляете системной логикой (аналитикой) или другим доменом (подсказки, например). Не надо фантазировать "ну и норм", надо попытаться проскалировать это на большие модули реальных проектов, примеры которых я не могу привезти и по этическим причинам, и из-за необходимости объяснять кучу контекста.

Можно поискать умные книжки или статьи по событийной архитектуре. Сам посоветовать что-то не могу, т.к. у меня это в голове это все от десятков проектов и летов опыта.

Буду повторять то что о чем уже писал :)
Конечно, код без абстракций лучше, чем код с абстракциями и я сам с Reatom пропагандирую процедурный стиль и НЕ предлагаю писать весь код с событийном стиле. Наоборот, я ругаю тот же effector за то что там вообще все на событиях и код так выглядит сложнее и запутанее. Но, как и написано в статье, бывают "редкие, но также важные задачи", которые удобнее решать с описанием логики снаружи модуля. Редкие эти случаи, понимаете? Никто не говорит что отсутствие событийной функциональности делает инструмент неюзабельным, это просто один из факторов, который нужно учитывать.

EE - достаточно общий и часто применяемый паттерн, глупо говорить что он вообще не нужен. Как я уже отвечал в соседней ветке, в реатоме он уже встроен и работает лаконично со всей экосистемой, чем это не плюс?

На самом деле EE полезен тут лишь когда нужно более одного обработчика. В частой ситуации, когда обработчиков не более одного, достаточно обычной функции и инверсии контроля.

Вы зачем-то чистый доменный код разбавляете системной логикой (аналитикой) или другим доменом (подсказки, например)

Вы так говорите, как будет он тем самым усложнил код и сделал его непонятным/не читаемым. А на самом деле он сделал всё с точностью да на оборот, сделал код максимально понятным, очевидным, простым и читаемым. Вы исповедуете максимально усложняющий простые вещи подход и write-only говнокод, не надо так делать. Делайте это один, на своих проектах, не срите там, где потом после вас кому-то работать.

Не надо фантазировать "ну и норм"

Он не фантазирует, он делает правильно. А вот вы тот ещё фантазер, который элементарные вещи выставляет как сложные)

 надо попытаться проскалировать это на большие модули реальных проектов

Ну и? Какая разница проект маленький или огромный когда в явном виде и в явном месте указаны такие вещи как analytics.sendMsg('model-n form submit'); ?

Можно поискать умные книжки или статьи по событийной архитектуре.

Судя по тому, к чему они вас привели - не надо пожалуйста) KISS и YAGNI должены оставаться превыше всего.

Сам посоветовать что-то не могу, т.к. у меня это в голове это все от десятков проектов и летов опыта.

То как вы пишете код и "решаете" элементарные задачи говорит само за себя)

Я говорю, "редкие сложные кейсы" и привожу минимальные примеры для понимания. Посмотрите на всю статью, что вы прицепились к одной формулировке? Вам же лишь бы гнуть свою линию и грубить - это токсично и сообществу лучше не делает.

Я говорю, "редкие сложные кейсы" и привожу минимальные примеры для понимания

Я не увидел ни одного примера в ваших "сложных" кейсах, где ваш странный подход лучше, чем традиционный, в котором всё легко и просто и в явном виде написано.

Вам же лишь бы гнуть свою линию и грубить - это токсично и сообществу лучше не делает.

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

Вы сами для себя придумываете проблемы из элементарных вещей, а потом пытаетесь их решить изподвыподверта, и после этого кода, который вы наворотили, ваш проект и правда становится сложным, не понятным, write-only и bus факторным.

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

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

Ну вы не увидели, зачем врать и обобщать мои "редкие кейсы" до "ваш проект становится сложным"? Оскорблять меня зачем? Вся публика хабра соответствующей тематики знакома с вашей агресивной идеализацией мобыкса. Ну посмотрите вы на рынок и сделайте выводы. Идите лучше на конференциях выступать, курсы делайте. А здесь в комментариях от вас только плохое настроение.

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

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

обобщать мои "редкие кейсы" до "ваш проект становится сложным"? Оскорблять меня зачем?

То, как вы расписываете банальные вещи и то, какие примеры кода показываете для их решения тут волей не волей делается вывод - что вы усложняете простые вещи на ровном месте. Не надо это воспринимать как оскорбление личного характера, это лишь наблюдение и мысли в слух. Может вы подумаете об этом и немного пересмотрите подход, а может и нет.

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

window.SENTRY.captureEvent -> import('/sentry').then({captureEvent} => ...), если быть точным, я думал это и так понятно.

Тогда можно использовать абсолютно любой подход, ленивая загрузка будет из коробки :)

Вы зачем-то чистый доменный код разбавляете системной логикой (аналитикой) или другим доменом (подсказки, например)

Что такое этот ваш доменный код в разрезе фронтенд-приложений? Если что, синюю книжку Эванса читал, DDD в реальных проектах видел (не понравилось).

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

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

Что-то я растёкся мыслею, поэтому повторю вопрос: что такое этот ваш доменный код в разрезе фронтенд-приложений?

EE - достаточно общий и часто применяемый паттерн, глупо говорить что он вообще не нужен. 

Может и нужен, но точно не в таком простом виде. В эвентах должна быть какая-то практическая изюминка. В событийной модели DOM'а есть всплытия событий, в очередях -- возможность подписываться на события по паттерну типа on('form-*-changed', doSomething). Но когда события добавляются только для создания decoupling'а, потому что это "правильно" и Боб Мартин с Мартином Фаулером про это писали, то от такого паттерна только вред

ОРП тут недоумевает: с чего это реактивный код вдруг стал менее императивным.

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

В $mol_wire можно:

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

Какая-то спец олимпиада. Вот так выглядит короткий понятный реактивный код с тем же поведением:

В $mol_wire можно

В реатоме тоже можно :) в некоторых случаях там вывод внутренней структуры покрасивее мола будет. Но это все еще заметно сложнее нативных структур, как можно утверждать что 100 байт читать так же просто как 10?

короткий понятный реактивный код

Только этот код с пачкой ошибок. Нет `"Loading post..."`, current должен выставляться после завершения фетчинга.

Хз, что за нативные структуры такие. Там обычные js объекты с прямыми ссылками друг на друга. Можно по всему приложению гулять, разворачивая их.

Это не ошибки. Не надо подгонять задачу под решение. Анимированный индикатор ожидания рисуется рендерером автоматически - это его задача, а не прикладной логики. А current, как источник истины для comments, выставляться должен раньше, чтобы следствие не шло раньше причины.

Диктовать бизнесу дизайн и UX, запрещая использовать текст для описания состояния загрузки - это мощно!

А current не нужно сразу менять, потому что пока идет загрузка показывается старый список, соответственно со старым индетефикатором. Что будет если лоадинг упадет - будут разные айди и список.

  1. Не диктовать. Индикатор при необходимости кастомизируется в одном месте в слое рендеринга, а не размазывается ровным слоем по прикладной логике.

  2. Это вне зоны ответственности "бизнеса". Эти м занимается дизайнер, если не забивает. Обычно всем плевать как оно будет.

  3. Индикатор ожидания в виде текста - это плохой UX.

---

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

Я правильно понимаю, что суть всего этого вашего реактивного программирования в том что UI подписывается на обновления модели? В чём принципиальное отличие от MVC, которой лет так сорок если не больше?

MVC - по каким признакам делить код. Реактивность - технический способ разделения кода. Одно другому не противоречит, а может и помогать.

Лет 10 назад мы с товарищем проводили митапы по дизайну и архитектуре программ. Мое внимание привлек мужичок лет 60+, который начал смеяться через пару минут после начала и продолжал до самого перерыва. Я решил узнать, что же так его развеселило - ответом было "Мужики, то о чем вы тут спорите - мы в <местный аналог AT&T> решили еще в 70х".
В достаточно древнем Smalltalk вообще нет понятия "вызов метода", там можно только послать сообщение обьекту - и рантайм вызовет соответствующий обработчик. И @slonopotamus совершенно прав - в классическом MVC или MVVM изменение модели вызывает событие, на которое автоматически реагируют "подписанные" на него элементы View.
Кстати, основные проблемы реактивного программирования - вообще не те, которые вы упомянули. Проблемы - это невозможность контроля состояния всей системы (например - в виде транзакций), отсутствие уверенности что ваше сообщение будет обработано вообще, один раз и вовремя - и так далее.

Уточню, в реатоме нет полноценных акторов и соотстветствующей изоляции, нет нормальной возможности из родителя перехватывать ошибку и перезапускать актор, но некоторые свойства акторов есть, например возможность извне декларировать лайфсайкл хуки: onConnect, onDisconnect, onUpdate, которые работают не только на прямые, но и косвенные связи (подписки).

Насколько я понимаю - речь идет о браузере. Я же имею в виду более сложные и распределенные системы. Да и упомянутые вами транзакции вряд ли работают с Web workers.

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

"Реактивность позволяет значительно снизить сложность реализации надёжных программ" - это неправда.
Снизить количество boilerplate-кода - да, улучшить деление на компоненты - тоже. А вот сложность - нет, гуглите например "exactly-once".

Вы лучше сами погуглите различие квантора существования от всеобщности.

Sign up to leave a comment.