Заметки об effector (непутевые)
4. Юниты: Event Первый и самый важный. Дело в том, что мы как фронтэндеры живем в событийно-ориентированном окружении (DOM ака верстка). При построении бизнес-логики веб-приложений(те которые рядом с DOMом) глупо было бы ориентироваться на иную модель. Даже…
5. Юниты: Store
Ух, вот она жемчужина СТМ. Сторчик, Стореныш.
Объект для хранения значений. Необходимо задавать дефолтное значение(можно все кроме undefined). При прилете повторяющегося(эквивалентного предыдущему) значения не тригернет апдейт.
Обработчик для прилетевших событий представляет собой редьюсер (не мутируем текущий стейт), в случае возврата undefined в обработчике апдейт не тригернется
Учитывая предыдущий апроач с зонами ответственности, можно вывести следующую рекомендацию: никаких сингл сторов на все приложение. Я серьезно. Зоны ответственности позволяют нам иметь как минимум один стор под своим патронажем. И нет, не поля одного большого объекта. Независимые легкие сторы для каждой зоны ответственности.
Комбинировать их в гигастор не составит труда при возникшей необходимости.
Ух, вот она жемчужина СТМ. Сторчик, Стореныш.
Объект для хранения значений. Необходимо задавать дефолтное значение(можно все кроме undefined). При прилете повторяющегося(эквивалентного предыдущему) значения не тригернет апдейт.
Обработчик для прилетевших событий представляет собой редьюсер (не мутируем текущий стейт), в случае возврата undefined в обработчике апдейт не тригернется
Учитывая предыдущий апроач с зонами ответственности, можно вывести следующую рекомендацию: никаких сингл сторов на все приложение. Я серьезно. Зоны ответственности позволяют нам иметь как минимум один стор под своим патронажем. И нет, не поля одного большого объекта. Независимые легкие сторы для каждой зоны ответственности.
Комбинировать их в гигастор не составит труда при возникшей необходимости.
Заметки об effector (непутевые)
5. Юниты: Store Ух, вот она жемчужина СТМ. Сторчик, Стореныш. Объект для хранения значений. Необходимо задавать дефолтное значение(можно все кроме undefined). При прилете повторяющегося(эквивалентного предыдущему) значения не тригернет апдейт. Обработчик…
6: Юниты: Effect
Ключевой для понимания юнит.
Технически признаками эффекта являются (хотя бы один):
-влияние на окружение вне системы (запросы на сервер, локалсторадж)
- подверженность влиянию окружения (process.env)
Но, концептуально, если событие это штука, которая происходит всегда, то эффект же предоставляет конструкцию, которая позволит обрабатывать исключения(то есть отсутствие гарантии, что все действо внутри обработчика будет завершено с успехом)
Когда мы можем ловить исключения?
-запросы
-работы с локал сторадж
-работа с third-party API
-произвольный участок кода, где разработчику жуть как хочется написать явный throw
Эффект предоставляет нам handler, в который будут складироваться все подобные сомнительные конструкции.
Таким образом, "прожевывая" сомнительные конструкции, эффект эмитит события об успехе(.done) или о несварении (.fail). Во время работы так же доступно булево поле-стор .pending, которое явно скажет о том в процессе эффект или нет.
Для тех кому все равно на исход любезно предоставлено событие .finally, которое эмитится всегда.
Ключевой для понимания юнит.
Технически признаками эффекта являются (хотя бы один):
-влияние на окружение вне системы (запросы на сервер, локалсторадж)
- подверженность влиянию окружения (process.env)
Но, концептуально, если событие это штука, которая происходит всегда, то эффект же предоставляет конструкцию, которая позволит обрабатывать исключения(то есть отсутствие гарантии, что все действо внутри обработчика будет завершено с успехом)
Когда мы можем ловить исключения?
-запросы
-работы с локал сторадж
-работа с third-party API
-произвольный участок кода, где разработчику жуть как хочется написать явный throw
Эффект предоставляет нам handler, в который будут складироваться все подобные сомнительные конструкции.
Таким образом, "прожевывая" сомнительные конструкции, эффект эмитит события об успехе(.done) или о несварении (.fail). Во время работы так же доступно булево поле-стор .pending, которое явно скажет о том в процессе эффект или нет.
Для тех кому все равно на исход любезно предоставлено событие .finally, которое эмитится всегда.
Заметки об effector (непутевые)
6: Юниты: Effect Ключевой для понимания юнит. Технически признаками эффекта являются (хотя бы один): -влияние на окружение вне системы (запросы на сервер, локалсторадж) - подверженность влиянию окружения (process.env) Но, концептуально, если событие это…
7. Стандартные юниты
Все вышеобозначенные три юнита являются стандартными. Это важное уточнение так как дальше этот термин будет использоваться для краткости.
Все вышеобозначенные три юнита являются стандартными. Это важное уточнение так как дальше этот термин будет использоваться для краткости.
Заметки об effector (непутевые)
7. Стандартные юниты Все вышеобозначенные три юнита являются стандартными. Это важное уточнение так как дальше этот термин будет использоваться для краткости.
8. Юниты: Domain
Домен это неймспейс для всех стандартных юнитов. Предоставляет хуки на создание стандартных юнитов, находящихся под патронажем этого домена. Что полезно для массовых операций. Домен может быть свободно создан внутри домена. Все юниты внутри домена могут выведены через domain.history
P.S. домены необходимы при SSR, а также при написании тестов, покрывающих большинство сценариев нашей системы
Домен это неймспейс для всех стандартных юнитов. Предоставляет хуки на создание стандартных юнитов, находящихся под патронажем этого домена. Что полезно для массовых операций. Домен может быть свободно создан внутри домена. Все юниты внутри домена могут выведены через domain.history
P.S. домены необходимы при SSR, а также при написании тестов, покрывающих большинство сценариев нашей системы
Заметки об effector (непутевые)
7. Стандартные юниты Все вышеобозначенные три юнита являются стандартными. Это важное уточнение так как дальше этот термин будет использоваться для краткости.
9. Подготовка данных
Подобно караванам с товарами ивенты распространяют данные по нашей системе(только грабить их не нужно). Периодически нам нужно эти данные подготовить: добавить в эти данные какое-нибудь статическое значение или умножить пришедшую в данных цифру на два.
Для таких задач служат три вещи:
1) пожалуй самой «плоской» версией для подготовки данных между юнитом «отправки» и юнитом «назначения» (датафлоу все-таки) является поле
2) остальные варианты являются методами события непосредственно. Первый из них
3) и последний вариант это
Например, эффект по получению баланса определенной валюты. Обработчик для всех валют одинаковый, отличие будет будет лишь в статическом коде валюты. Таким образом, можно создать множество «препенднутых» событий, функция-трансформер которого примиксовывает в аргумента вызова статический код валюты и решить поставленную задачу.
Подобно караванам с товарами ивенты распространяют данные по нашей системе(только грабить их не нужно). Периодически нам нужно эти данные подготовить: добавить в эти данные какое-нибудь статическое значение или умножить пришедшую в данных цифру на два.
Для таких задач служат три вещи:
1) пожалуй самой «плоской» версией для подготовки данных между юнитом «отправки» и юнитом «назначения» (датафлоу все-таки) является поле
fn
в операторе sample.
Но к нему вернусь через пару глав, так как обо всем по порядку.2) остальные варианты являются методами события непосредственно. Первый из них
event.map
позволяет трансформировать payload, пришедший в событие как вам заблагорассудится лишь с одним ограничением: функция-трансформер должна быть чистой (то есть не содержать сайд-эффектов). Данный метод события вернет новое событие, которое будет неразрывно связано с оригинальным незамедлительным вызовом, как только оригинальное было «тригернуто».3) и последний вариант это
event.prepend
. Если с .map
мы взаимодействуем как с постобработчиком, то .prepend,
напротив, будет являться прелюдией к оригинальному событию. Соответственно, возвращать будет событие которое исполнит функцию-трансформер и затем незамедлительно вызовет оригинальное событие. Какое можно найти этому применение? Например, эффект по получению баланса определенной валюты. Обработчик для всех валют одинаковый, отличие будет будет лишь в статическом коде валюты. Таким образом, можно создать множество «препенднутых» событий, функция-трансформер которого примиксовывает в аргумента вызова статический код валюты и решить поставленную задачу.
Заметки об effector (непутевые)
5. Юниты: Store Ух, вот она жемчужина СТМ. Сторчик, Стореныш. Объект для хранения значений. Необходимо задавать дефолтное значение(можно все кроме undefined). При прилете повторяющегося(эквивалентного предыдущему) значения не тригернет апдейт. Обработчик…
10. Подготовка данных стора в необходимой форме
Данные из сторов тоже не последние люди в нашем цирке под названием датафлоу, поэтому как-то несправедливо было бы обделить стор методом для подготовки данных. Стор подобно событию имеет метод
Применение? Например, стор вам нужен в форме ассоциативного массива(ключ-значение) и в форме обычного массива объектов.
Данные из сторов тоже не последние люди в нашем цирке под названием датафлоу, поэтому как-то несправедливо было бы обделить стор методом для подготовки данных. Стор подобно событию имеет метод
.map,
в котором можно трасформировать стор по заранее указанным правилам. Такой стор называется вычисляемым стором. Вычисляться он будет только при апдейте оригинального. Не больше и не меньше. Применение? Например, стор вам нужен в форме ассоциативного массива(ключ-значение) и в форме обычного массива объектов.
11. Датафлоу. Начало
Мы успели затронуть как обрабатывать данные в рамках одного стандартного юнита. А как же быть когда их несколько??
Вот тут-то и начинается самое интересное - декларативная связь юнитов! Первым самым простым оператором является оператор forward. Его апи достаточно явное: поля
P. S. Только не надо подписывать завершение эффекта на его вызов - в вас ударит молния.
Мы успели затронуть как обрабатывать данные в рамках одного стандартного юнита. А как же быть когда их несколько??
Вот тут-то и начинается самое интересное - декларативная связь юнитов! Первым самым простым оператором является оператор forward. Его апи достаточно явное: поля
from
и to,
принимающие любой стандартный юнит. Его исполнение означает, что поле to
явно подписано на триггер(изменение значения в сторе или вызов события) поля from
и будет тригернуто соответственно после.P. S. Только не надо подписывать завершение эффекта на его вызов - в вас ударит молния.
12. Датафлоу. Фильтрация
Обработка данных у нас есть, принуждение к общению юнитов - тоже. А что если юнитов не хотят общаться без соблюдения некоторых формальностей? Тут на помощь приходит guard. Оператор, имеющий три поля: source, filter, target.
Source это стандартный юнит, который инициирует общение.
Filter - та самая преграда в их общении. Принимает либо функцию-предикат, которая проверит данные, пришедшие из source на вшивость. Стоит этой функции вернуть truthly, все преграды уйдут. Помимо функции предиката может принимать булевый стор.
Target - стандартный юнит, получающий в себя данные из source, как только filter оказался truthly.
Но что, если одной фильтрации недостаточно и нужно в случае truthly еще и трансформировать payload неким образом? Тут придет на помощь
Так ладно это все круто, но ты рассматриваешь связи юнитов 1 к 1, а что если одному событию нужно связаться со многими событиями с различными условиями в зависимости от получателя?
И тут рецепт есть! Оператор split к вашим услугам.
Обработка данных у нас есть, принуждение к общению юнитов - тоже. А что если юнитов не хотят общаться без соблюдения некоторых формальностей? Тут на помощь приходит guard. Оператор, имеющий три поля: source, filter, target.
Source это стандартный юнит, который инициирует общение.
Filter - та самая преграда в их общении. Принимает либо функцию-предикат, которая проверит данные, пришедшие из source на вшивость. Стоит этой функции вернуть truthly, все преграды уйдут. Помимо функции предиката может принимать булевый стор.
Target - стандартный юнит, получающий в себя данные из source, как только filter оказался truthly.
Но что, если одной фильтрации недостаточно и нужно в случае truthly еще и трансформировать payload неким образом? Тут придет на помощь
event.filterMapТак ладно это все круто, но ты рассматриваешь связи юнитов 1 к 1, а что если одному событию нужно связаться со многими событиями с различными условиями в зависимости от получателя?
И тут рецепт есть! Оператор split к вашим услугам.
13. Датафлоу. Сигналы
Частый случай, когда юнитам нужно связаться не просто так и даже не по условию, а по сигналу! А если точнее, то по тригеру любого стандартного юнита.
Самый явный пример - по маунту компонента(а маунт внезапно событие) взять данные из некого стора и вызвать эффект.
clock - здесь ключевое поле. В него и записывается необходимый сигнал для замыкания всей цепочки.
Как я обещал в 9-ой главе мы вернемся к способу подготовки данных через sample.
Дело в том, что помимо этих трех полей в sample существует опциональное поле fn - функция-комбинатор. Она принимает в себя два аргумента. payload из source и payload из clock (если не имеется - undefined). Далее мы вольны комбинировать и трансформировать эти значения в соответствии с поставленной задачей, не выходя за рамки чистоты этой функции, разумеется.
Частый случай, когда юнитам нужно связаться не просто так и даже не по условию, а по сигналу! А если точнее, то по тригеру любого стандартного юнита.
Самый явный пример - по маунту компонента(а маунт внезапно событие) взять данные из некого стора и вызвать эффект.
sample({
source: $store,
clock: mount,
target: effectFx
})
Это что-то на клингонском? Нет, это реализация задачи, которую я описал выше! clock - здесь ключевое поле. В него и записывается необходимый сигнал для замыкания всей цепочки.
Как я обещал в 9-ой главе мы вернемся к способу подготовки данных через sample.
Дело в том, что помимо этих трех полей в sample существует опциональное поле fn - функция-комбинатор. Она принимает в себя два аргумента. payload из source и payload из clock (если не имеется - undefined). Далее мы вольны комбинировать и трансформировать эти значения в соответствии с поставленной задачей, не выходя за рамки чистоты этой функции, разумеется.
14. Организация датафлоу
Мы научились строить маршруты данных любой сложности по системе. Остался вопрос в организации этого дела. Я предлагаю максимально простой и наивный вариант - разделение на зоны ответственности.
Соответственно у нас есть папка со всей бизнес-логикой. Она разделяется на папки с соответствующими зонами ответствености.
Каждая зона ответственности содержит 2 файла (реже 3, когда сторы лежат в отдельном файле).
Первый - index-ный файл с декларациями всех юнитов эффектора(create***).
Второй - init файл, который ничего из себя не экспортит(!), а только импортит. Контент у этого файла следующего содержания:
1) хэндлеры эффектов
2) обработчики сторов соответствующей зоны ответственности
3) взаимодействие между юнитами из соседних зон ответственности(forward, guard, split, sample). когда задумываетесь в какой зоне ответственности разместить связь, просто задайте себе вопрос: «Кто инициатор этой связи?». Там и размещайте.
Так, в корне папки со всей бизнес-логикой создаем корневой init-файл, импортим в него init файлы со всех зон ответственности. Далее импортим этот корневой инит в корень приложения и инициализируем таким образом граф связей всего приложения статически!
Мы построили граф? Получается, что так.
P. S. Если чувствуете, что файлы зон ответственности начинают сильно разрастаться, это не подход плохой, а скорее вы упустили момент, когда зона ответственности превратилась в несколько.
Мы научились строить маршруты данных любой сложности по системе. Остался вопрос в организации этого дела. Я предлагаю максимально простой и наивный вариант - разделение на зоны ответственности.
Соответственно у нас есть папка со всей бизнес-логикой. Она разделяется на папки с соответствующими зонами ответствености.
Каждая зона ответственности содержит 2 файла (реже 3, когда сторы лежат в отдельном файле).
Первый - index-ный файл с декларациями всех юнитов эффектора(create***).
Второй - init файл, который ничего из себя не экспортит(!), а только импортит. Контент у этого файла следующего содержания:
1) хэндлеры эффектов
2) обработчики сторов соответствующей зоны ответственности
3) взаимодействие между юнитами из соседних зон ответственности(forward, guard, split, sample). когда задумываетесь в какой зоне ответственности разместить связь, просто задайте себе вопрос: «Кто инициатор этой связи?». Там и размещайте.
Так, в корне папки со всей бизнес-логикой создаем корневой init-файл, импортим в него init файлы со всех зон ответственности. Далее импортим этот корневой инит в корень приложения и инициализируем таким образом граф связей всего приложения статически!
Мы построили граф? Получается, что так.
P. S. Если чувствуете, что файлы зон ответственности начинают сильно разрастаться, это не подход плохой, а скорее вы упустили момент, когда зона ответственности превратилась в несколько.
15. Реиспользование и зависимый от окружения код
Периодически возникают ситуации, когда мы можем реиспользовать какие-то функции для нашего датафлоу или даже события для нескольких зон ответственности.
Как быть? Куда положить такую вундервафлю? В utils? No fucking way! У нас есть зона ответственности app! Точно такая же как и остальные, хранит специфичный для зоны ответственности под названием приложение код.
Такая же история и с биндингами. Биндинги для реакта предоставляют такую штуку как Gate. Где их создавать? В определенной зоне ответственности или во вьюхе?
Их стоит создавать в зоне ответственности под названием приложение. Так как это специфичный код для конкретного приложения.
Та же история с init файлом. Те связи, где тригер гейта (маунт, анмаунт компонента или ререндер компонента где у гейта обновились свойства) является инициатором, стоит размещать там.
Таким образом при тестировании будет явно видно какие события надо будет вызывать явно (реакта в тестах бизнес-логики нет).
Периодически возникают ситуации, когда мы можем реиспользовать какие-то функции для нашего датафлоу или даже события для нескольких зон ответственности.
Как быть? Куда положить такую вундервафлю? В utils? No fucking way! У нас есть зона ответственности app! Точно такая же как и остальные, хранит специфичный для зоны ответственности под названием приложение код.
Такая же история и с биндингами. Биндинги для реакта предоставляют такую штуку как Gate. Где их создавать? В определенной зоне ответственности или во вьюхе?
Их стоит создавать в зоне ответственности под названием приложение. Так как это специфичный код для конкретного приложения.
Та же история с init файлом. Те связи, где тригер гейта (маунт, анмаунт компонента или ререндер компонента где у гейта обновились свойства) является инициатором, стоит размещать там.
Таким образом при тестировании будет явно видно какие события надо будет вызывать явно (реакта в тестах бизнес-логики нет).
Заметки об effector (непутевые)
8. Юниты: Domain Домен это неймспейс для всех стандартных юнитов. Предоставляет хуки на создание стандартных юнитов, находящихся под патронажем этого домена. Что полезно для массовых операций. Домен может быть свободно создан внутри домена. Все юниты внутри…
16. Тестирование
Я специально использовал словосочетание зоны ответственности вместо короткого слова домен, чтобы не сбивать вас с толку. Так как домен это юнит эффектора.
Говоря о тестировании бизнес-логики с нормальным покрытием, а не одиночными тестами, домен становится необходим.
1) Мы, как разработчики, можем создать один домен на всю систему.
2) Заменить явные импорты createEvent, createStore, createEffect на myDomain.createEvent и тд. Таким образом вся система становится под патронажем одного домена и его можно форкнуть - fork(domain, config)
3) Эта функция принимает в себя домен и опциональный конфиг, в котором вы можете явно указать хэндлеры каких эффектов вы хотите мокнуть через ключ handlers, а также явно указать значения сторов для тестов через ключ values
4) Вызов функции форк вернет вам скоуп( const scope = fork(domain, config) ) - виртуальный инстанс вашего домена
5) Теперь остается лишь выбрать начальное событие сценария, который мы хотим оттестировать, передав его в функцию allSettled первым аргументом, а вторым перед payload с которым этот сценарий должен начаться. В виду того, что резолв всей сценарной цепочки может занять больше времени чем один тик, вызов allSettled нужно await-ить
6) Через scope.getState($сторкоторыйнужен) проверяем состояния нашей системы по прошествии тестируемого сценария, вероятно проверяем вызовы событий/эффектов нашей библиотекой для тестирования(например jest)
7) Вы способны оттестировать всю вашу систему!
Я специально использовал словосочетание зоны ответственности вместо короткого слова домен, чтобы не сбивать вас с толку. Так как домен это юнит эффектора.
Говоря о тестировании бизнес-логики с нормальным покрытием, а не одиночными тестами, домен становится необходим.
1) Мы, как разработчики, можем создать один домен на всю систему.
2) Заменить явные импорты createEvent, createStore, createEffect на myDomain.createEvent и тд. Таким образом вся система становится под патронажем одного домена и его можно форкнуть - fork(domain, config)
3) Эта функция принимает в себя домен и опциональный конфиг, в котором вы можете явно указать хэндлеры каких эффектов вы хотите мокнуть через ключ handlers, а также явно указать значения сторов для тестов через ключ values
4) Вызов функции форк вернет вам скоуп( const scope = fork(domain, config) ) - виртуальный инстанс вашего домена
5) Теперь остается лишь выбрать начальное событие сценария, который мы хотим оттестировать, передав его в функцию allSettled первым аргументом, а вторым перед payload с которым этот сценарий должен начаться. В виду того, что резолв всей сценарной цепочки может занять больше времени чем один тик, вызов allSettled нужно await-ить
6) Через scope.getState($сторкоторыйнужен) проверяем состояния нашей системы по прошествии тестируемого сценария, вероятно проверяем вызовы событий/эффектов нашей библиотекой для тестирования(например jest)
7) Вы способны оттестировать всю вашу систему!
Заметки об effector (непутевые)
16. Тестирование Я специально использовал словосочетание зоны ответственности вместо короткого слова домен, чтобы не сбивать вас с толку. Так как домен это юнит эффектора. Говоря о тестировании бизнес-логики с нормальным покрытием, а не одиночными тестами…
17. SSR
Помните писал в позапрошлой главе о специфичном для окружения коде и его отделении? SSR ровно как и тесты подподает под это определение. Значит, нам нужно точно также форкнуть корневой домен и через allSettled вызвать все необходимые событийные махинации, которые мы задумали вычислить на сервере.
Но это лишь малюсенькая затравка для большой темы, которую @sovasergey раскроет в ближайшем будущем вдоль и поперек! Стей тунец.
Помните писал в позапрошлой главе о специфичном для окружения коде и его отделении? SSR ровно как и тесты подподает под это определение. Значит, нам нужно точно также форкнуть корневой домен и через allSettled вызвать все необходимые событийные махинации, которые мы задумали вычислить на сервере.
Но это лишь малюсенькая затравка для большой темы, которую @sovasergey раскроет в ближайшем будущем вдоль и поперек! Стей тунец.
18. Практическое применение
Я думаю без практических примеров вам было сложновато это воспринимать. Для таких целей в конце лета я сделал целое приложение-воркшоп для Одесса жс и всех желающих. Оно разбито по веткам. В мастере бойлерплейт, а дальше по главам можете навигироваться, заглядывая в пул реквесты, осматривая что изменилось.
Я думаю без практических примеров вам было сложновато это воспринимать. Для таких целей в конце лета я сделал целое приложение-воркшоп для Одесса жс и всех желающих. Оно разбито по веткам. В мастере бойлерплейт, а дальше по главам можете навигироваться, заглядывая в пул реквесты, осматривая что изменилось.
GitHub
GitHub - YanLobat/effector-workshop: Educational effector app
Educational effector app. Contribute to YanLobat/effector-workshop development by creating an account on GitHub.
Заметки об effector (непутевые)
6: Юниты: Effect Ключевой для понимания юнит. Технически признаками эффекта являются (хотя бы один): -влияние на окружение вне системы (запросы на сервер, локалсторадж) - подверженность влиянию окружения (process.env) Но, концептуально, если событие это…
Отличный пост от автора эффектора, раскрывающий природу применения эффектов по полной. По моему скромному мнению после моего нарочито упрощенного первичного описания это будет отличным продолжением с плеядой практических примеров.
P.S. Пост расположен на патреоне, который является формой поддержки автора, разрабатывающего экосистему эффектора фултайм, побочным продуктом которой являются, помимо прочего, образовательные посты по темам.
P.P.S Это дало некоторый пинок написать продолжение своих глав про пути уменьшения количества шаблонного кода в ваших проектах.
P.S. Пост расположен на патреоне, который является формой поддержки автора, разрабатывающего экосистему эффектора фултайм, побочным продуктом которой являются, помимо прочего, образовательные посты по темам.
P.P.S Это дало некоторый пинок написать продолжение своих глав про пути уменьшения количества шаблонного кода в ваших проектах.
❤1
19.Унификация и светоч в конце тоннеля нашего бытия
Прошу простить за долгую задержку. Прокрастинация, хаотичность мыслей и нежелание рассказывать своей аудитории дерьмо не дали мне написать этот пост раньше!
Дима, выпустив последний минорный релиз эффектора совершил еще одну веху в облегчении и стандартизации рутины джаваскриптоциркачей.
Однако мой посыл, который я пытаюсь донести несколько шире.
Это облегчение не только для нас люда программисткого, но и для бизнеса, по щучьему велению которого эти системы и выстраиваются.
Давайте вспомним о сути бизнеса. В чем она заключается кроме извлечения прибыли? Ведь все-таки прибыль получается за предоставляемые услуги, а не из воздуха.
А что есть предоставляемые услуги? Решение проблем пользователей.
А нужен ли был бы бизнес если решение проблемы заключалось в атомарном решении? Я испытываю сомнения на этот счет!
Таким образом, получаем, что решение проблем это всегда история о последовательности действий.
Приводя пример более бытовым языком: «Когда пользователь делает что-то мы делаем вот это и вот это опционально»
Казалось бы при чем здесь эффектор? При том, что он дает наиболее близкую к бизнесовой концепцию решения проблем в виде чрезвычайно доступной оркестрации сигналами.
Стоп, сигналами? Это еще что такое? Видите ли, каждый раз говоря «когда что-то(пользователь заходит/выходит или любой другой пул событий) мы неявно подразумеваем сигнал. Кстати, поздравляю теперь вы будете подразумевать их явно🌚
Хотелось бы добавить, что «когда что-то» это исходящий сигнал и он может быть двух типов:
1) Самый тривиальный это одиночное событие (пример когда пользователь вышел из личного кабинета — событие выход пользователя)
2) Менее тривиальный это, когда исходящий сигналом будет служить любое событие из заданного множества(массива). Пример, настигший меня в самолете: для того, чтобы мне сейчас упасть достаточно одного события из множества — либо пилот заснет(и квс и второй), либо полный отказ электроники.
Сигналы в эффекторе выражены полем clock.
Теперь можно наконец перейти к чрезвычайной доступности. Дело в том, что для оркестрации сигналов любой последовательности вам необходимо всего три оператора.
Давайте перед как я их упомяну еще раз определимся со всеми возможными операциями с сигналами. Это:
Предобработка(трансформация исходящего сигнала)
Постобработка(трансформация входящего сигнала)
Фильтрация(фильтрация сигналов) Ветвление(создание множества сигналов из одного)
И теперь к операторам! Упомянутый мной ранее forward теперь является не более чем шортхэндом сэмпла.
Соответственно, первый из этих операторов, как вы догадались, является сэмпл! Я писал о нем ранее и давайте по-новому освежимся. Он обладает 4 полями:
source - примиксовка внешних данных. Порой данных исходящего сигнала недостаточно для входящего и нам нужны дополнительные вводные. Сорсом может являться любой шейп стора (одиночный или комбинированный в объектной форме), либо событие(возьмется аргумент вызова последнего такого события)
clock - как раз тот самый исходящий сигнал, который я разжевал
fn - функция для операции предобработки исходящего сигнала. Отмечу, что как раз здесь есть возможность обработать данные из сорса и клока в одном месте, чтобы превратить их в необходимый пейлоад для входящего сигнала
target - входящий сигнал(ы). Либо одиночный, либо пул событий(старт эффекта тоже событие), каждый из которых будет вызван. В случае пула операция постобработки в таргете доступна путем метода prepend у событий, где, мы способны задать каждому свою тонкую настройку. В случае же связей сигналов
Прошу простить за долгую задержку. Прокрастинация, хаотичность мыслей и нежелание рассказывать своей аудитории дерьмо не дали мне написать этот пост раньше!
Дима, выпустив последний минорный релиз эффектора совершил еще одну веху в облегчении и стандартизации рутины джаваскриптоциркачей.
Однако мой посыл, который я пытаюсь донести несколько шире.
Это облегчение не только для нас люда программисткого, но и для бизнеса, по щучьему велению которого эти системы и выстраиваются.
Давайте вспомним о сути бизнеса. В чем она заключается кроме извлечения прибыли? Ведь все-таки прибыль получается за предоставляемые услуги, а не из воздуха.
А что есть предоставляемые услуги? Решение проблем пользователей.
А нужен ли был бы бизнес если решение проблемы заключалось в атомарном решении? Я испытываю сомнения на этот счет!
Таким образом, получаем, что решение проблем это всегда история о последовательности действий.
Приводя пример более бытовым языком: «Когда пользователь делает что-то мы делаем вот это и вот это опционально»
Казалось бы при чем здесь эффектор? При том, что он дает наиболее близкую к бизнесовой концепцию решения проблем в виде чрезвычайно доступной оркестрации сигналами.
Стоп, сигналами? Это еще что такое? Видите ли, каждый раз говоря «когда что-то(пользователь заходит/выходит или любой другой пул событий) мы неявно подразумеваем сигнал. Кстати, поздравляю теперь вы будете подразумевать их явно🌚
Хотелось бы добавить, что «когда что-то» это исходящий сигнал и он может быть двух типов:
1) Самый тривиальный это одиночное событие (пример когда пользователь вышел из личного кабинета — событие выход пользователя)
2) Менее тривиальный это, когда исходящий сигналом будет служить любое событие из заданного множества(массива). Пример, настигший меня в самолете: для того, чтобы мне сейчас упасть достаточно одного события из множества — либо пилот заснет(и квс и второй), либо полный отказ электроники.
Сигналы в эффекторе выражены полем clock.
Теперь можно наконец перейти к чрезвычайной доступности. Дело в том, что для оркестрации сигналов любой последовательности вам необходимо всего три оператора.
Давайте перед как я их упомяну еще раз определимся со всеми возможными операциями с сигналами. Это:
Предобработка(трансформация исходящего сигнала)
Постобработка(трансформация входящего сигнала)
Фильтрация(фильтрация сигналов) Ветвление(создание множества сигналов из одного)
И теперь к операторам! Упомянутый мной ранее forward теперь является не более чем шортхэндом сэмпла.
Соответственно, первый из этих операторов, как вы догадались, является сэмпл! Я писал о нем ранее и давайте по-новому освежимся. Он обладает 4 полями:
source - примиксовка внешних данных. Порой данных исходящего сигнала недостаточно для входящего и нам нужны дополнительные вводные. Сорсом может являться любой шейп стора (одиночный или комбинированный в объектной форме), либо событие(возьмется аргумент вызова последнего такого события)
clock - как раз тот самый исходящий сигнал, который я разжевал
fn - функция для операции предобработки исходящего сигнала. Отмечу, что как раз здесь есть возможность обработать данные из сорса и клока в одном месте, чтобы превратить их в необходимый пейлоад для входящего сигнала
target - входящий сигнал(ы). Либо одиночный, либо пул событий(старт эффекта тоже событие), каждый из которых будет вызван. В случае пула операция постобработки в таргете доступна путем метода prepend у событий, где, мы способны задать каждому свою тонкую настройку. В случае же связей сигналов
n к 1
или 1 к 1
фазы предобработки и постобработки смешиваются и превращаются просто в операцию обработкиВторой оператор это guard. Благодаря унификации мне проще сказать о различиях с сэмплом. Из ограничений нем отсутствует поле fn, однако операция обработки все еще доступна путем использования prepend как для единственного события в таргете так и для множества, где препенд будет применен лишь там где необходим.
Из дополнений в нем присутствует поле filter, которое допускает связь исходящего и входящего сигнала лишь при возврате truthy значения в нем. Принимает два аргумента — данные пришедшие с source и c clock.
Входящий сигнал в поле target будет вызван со значением в source, если присутствует, в противном случае со значением из поля clock
Третий оператор split позволяет нам совершать ветвление. Когда исходящий сигнал разветвляется на множество различных входящих сигналов в зависимости от удовлетворения детерминированным паттернам.
В качестве поля, принимающего исходящий сигнал в данном случае выступает source. (Это не продлится вечность и когда-нибудь придем к единому clock),
Поле match, которое в своей самой емкой форме может принимать стор(со значениями ключей в cases). Или функцию, которая в зависимости от условия будет возвращать ту или иную строку(имя ключа в cases).
И, наконец, поле cases, где в объектной форме имеем пары ключ — значение, где значения являются входящими сигналами. Операции предобработки здесь доступна путем метода map у исходящего сигнала в сорсе. А операция постобработки доступна путем все того же prepend на входящих сигналах в cases
Таким образом, вы, как разработчики, владея всего тремя операторами способны организовывать сценарии абсолютно любой сложности и вложенности и вы, как бизнес имеющий таких разработчиков с соответствующим инструментарием, способны запускать продукты и валидировать гипотезы за понятное время и разработчики смогут быть полезными не только как ремесленники, но и проявлять собственное видение на продукт ввиду освободившегося мыслительного ресурса. Я дал вам точку соприкосновения теперь можете строить коммуникацию проще!
Стей факин тюнд
Из дополнений в нем присутствует поле filter, которое допускает связь исходящего и входящего сигнала лишь при возврате truthy значения в нем. Принимает два аргумента — данные пришедшие с source и c clock.
Входящий сигнал в поле target будет вызван со значением в source, если присутствует, в противном случае со значением из поля clock
Третий оператор split позволяет нам совершать ветвление. Когда исходящий сигнал разветвляется на множество различных входящих сигналов в зависимости от удовлетворения детерминированным паттернам.
В качестве поля, принимающего исходящий сигнал в данном случае выступает source. (Это не продлится вечность и когда-нибудь придем к единому clock),
Поле match, которое в своей самой емкой форме может принимать стор(со значениями ключей в cases). Или функцию, которая в зависимости от условия будет возвращать ту или иную строку(имя ключа в cases).
И, наконец, поле cases, где в объектной форме имеем пары ключ — значение, где значения являются входящими сигналами. Операции предобработки здесь доступна путем метода map у исходящего сигнала в сорсе. А операция постобработки доступна путем все того же prepend на входящих сигналах в cases
Таким образом, вы, как разработчики, владея всего тремя операторами способны организовывать сценарии абсолютно любой сложности и вложенности и вы, как бизнес имеющий таких разработчиков с соответствующим инструментарием, способны запускать продукты и валидировать гипотезы за понятное время и разработчики смогут быть полезными не только как ремесленники, но и проявлять собственное видение на продукт ввиду освободившегося мыслительного ресурса. Я дал вам точку соприкосновения теперь можете строить коммуникацию проще!
Стей факин тюнд
Долгожданный мажорный релиз настолько, что даже этот блог оживет
🔥3🥰1
Forwarded from Effector news (Дима Zerꙫbias)
effector 23.0.0 Spacewatch
В этом релизе мы сконцентрировались на улучшении пользовательского опыта:
🔹Вывод сообщений об ошибках теперь включает в себя имя юнита
🔹Депрекейтнуты методы, которые путали людей — вместо forward и guard теперь используется sample
🔹Депрекейтнуты старые и неактуальные апи
🔹Введены отдельные типы для юнитов, которые можно вызывать, чтобы было проще организовывать архитектуру и показывать, что из публичного апи модуля/сервиса/команды можно использовать только для чтения, а что можно менять извне
🔹Часто используемые библиотеки добавлены в дефолты бабель-плагина
🔹Производительность ускорена до 10%
а так же сделано множество других улучшений, полный список изменений по ссылке, а так же на страницах релизов effector-react, effector-vue и effector-solid
Помимо этого, мы подготовили migration guide чтобы процесс обновления был проще
Спасибо за то, что пользуетесь эффектором 🥳
В этом релизе мы сконцентрировались на улучшении пользовательского опыта:
🔹Вывод сообщений об ошибках теперь включает в себя имя юнита
🔹Депрекейтнуты методы, которые путали людей — вместо forward и guard теперь используется sample
🔹Депрекейтнуты старые и неактуальные апи
🔹Введены отдельные типы для юнитов, которые можно вызывать, чтобы было проще организовывать архитектуру и показывать, что из публичного апи модуля/сервиса/команды можно использовать только для чтения, а что можно менять извне
🔹Часто используемые библиотеки добавлены в дефолты бабель-плагина
🔹Производительность ускорена до 10%
а так же сделано множество других улучшений, полный список изменений по ссылке, а так же на страницах релизов effector-react, effector-vue и effector-solid
Помимо этого, мы подготовили migration guide чтобы процесс обновления был проще
Спасибо за то, что пользуетесь эффектором 🥳
GitHub
Release effector Spacewatch 23.0.0 · effector/effector
Improvements
Introduce EventCallable, StoreWritable and UnitTargetable types to allow users to express and understand what could be updated or called directly and what could not. Now createStore r...
Introduce EventCallable, StoreWritable and UnitTargetable types to allow users to express and understand what could be updated or called directly and what could not. Now createStore r...
👍7😁1