This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-09
Channels
- # beginners (38)
- # boot (160)
- # cider (143)
- # cljs-dev (62)
- # cljsjs (2)
- # cljsrn (3)
- # clojure (278)
- # clojure-austin (8)
- # clojure-brasil (5)
- # clojure-greece (2)
- # clojure-italy (11)
- # clojure-russia (188)
- # clojure-sg (2)
- # clojure-spec (118)
- # clojure-uk (103)
- # clojurescript (87)
- # core-async (8)
- # cryogen (2)
- # cursive (12)
- # datomic (119)
- # emacs (13)
- # hoplon (4)
- # immutant (12)
- # off-topic (12)
- # om (54)
- # om-next (5)
- # onyx (1)
- # pedestal (2)
- # portland-or (2)
- # re-frame (58)
- # reagent (18)
- # ring-swagger (18)
- # rum (4)
- # spacemacs (4)
- # specter (3)
- # untangled (65)
- # yada (25)
http://www.tiobe.com/tiobe-index/ говнорейтинг, но кложура на 47 месте (раньше вроде в топ 50 даже не была) ну и да
The main drivers behind Go's success are its ease of learning and pragmatic nature. It is not about theoretical concepts such as virtual inheritance and nomads (!?) but about hands-on experience
Господа, а у кого-нибудь случается низкоинтенсивный, но перманентный баттхёрт из-за того, что всякие реагенты всё ещё заставляют разбивать логику на куски "нажали кнопку -> вызвался хэндлер, чего-то посчитал, обновил shared state; нажали другую кнопку -> вызвался другой хэндлер, поднял из shared state недосчитанное, чего-то ещё посчитал"?
Я пытаюсь понять, как скрестить Ричевую идею "вернуть всю логику в одно место" из его core.async-презенташки и при этом сделать это так, чтобы персистентные данные а-ля Ом были синхронизированы с этой логикой даже при рефреше страницы (когда состояние сохраняется, а весь core.async-стейт теряется).
Нет. Эвент заэмитили, создался го-блок, который внутри себя все взаимодействия целого куска программы держит.
Проблема в том, что этот го-блок что-то рисует (через стейт), и если стейт персистить в localStorage, а страничку обновить, то будет десинхронизация.
Конечно, можно забить и сказать "всё, что складывается в этот кусок стейта - транзиентное, его мы не сохраняем; всё, что складывается в другой кусок стейта - персистентное, мы его через refresh тянем", и тогда, например, диалог, привязанный к go-блоку, после рефреша пропадёт. Но хочется же лучше.
Бинго. Я уже смотрел в потроха core.async, но они слишком запутанные, чтобы их сторадж данных целиком положить в атом реагента 🙂
Например, диалог аплоада фоток. Нажал кнопку, получил диалог с какими-то взаимодействиями в нём: добавить то, повернуть сё, это залить, это убрать.
Вариант 1: весь этот state - transient, после рефреша страницы пропадёт. ОК, жить можно.
Вариант 2, holy grail: весь этот state, включая стейт go-блоков его обслуживающих - persistent, после рефреша страницы продолжает, как был (если были XHR в полёте - отвалятся, но UI останется как есть, можно продолжать работать).
Я нашёл Dragonmark и ago, которые делают что-то в этой же области, но ещё не покопал.
кажется, что тебе нужно каналы инициализировать с восстановленными данными. это ж, по-сути, очереди
Есть у меня на экране открытый диалог аплоада фоток. Есть go-блок, который от этого диалога кучку хэндлеров к каналам привязал.
дак сделай что евент меняет стейт
Получится вот эта картинка из Рича: http://endot.org/notes/2014-02-14-core-async-clojure/problem.png
А я хочу это получить: http://endot.org/notes/2014-02-14-core-async-clojure/result.png
не очень понимаю. Тут вроде просто - либо персистишь значения либо нет, либо имеешь их после рефреша или нет
Я ж выше приводил пример - логика аплоада картинок. Вот есть картинка, мы её повращали, пообрезали, но ещё не зааплоадили.
Вот если я нахожусь в середине диалога редактирования, то у меня код находится в каком-то состоянии стейт-машины.
Хорошо. Юзер нажал кнопку аплоада, рисуется прогрессбар, аплоадятся фотки. Тут жмакнули рефреш.
Это всё не для того, чтобы сделать мою жизнь сложной, а наоборот 🙂 Если сделать мою жизнь простой не получается, то тогда я это делать не буду, а буду делать "discard transient on refresh"
Собственно, проблема в том, что в этом случае "интересность" данных начинает влиять на структуру кода, а это нехорошо.
у тебя есть сервер, клиент и неожиданный ребут страницы - это сложная задача - если хочешь консистентности
Если у меня есть код, который проще всего написать стейт-машинкой, но при этом данные терять не хочется, то получается, что нужно извращаться.
Ну вот я вижу, как это можно решить - засушиванием стейта core.async и регидрацией потом.
после восстановления upload отвалится с ошибкой, это ясен пень. но upload может отвалиться с ошибкой и без рефреша.
так что если у меня есть логика retry на клиенте для сетевых проблем, то upload пойдёт дальше.
не, другая задача: клиент выбрал пачку фоток и они улеглись в локальный стейт, а потом по upload они поехали XHR-ом на сервер.
если есть логика retry т.е. есть и стейт (не явный наверно) который говорит о том что картинка ушла на сервак или нет. В чем проблема сделать этот стейт явныМ и персистить? при рефреше логика та же как при ретрае - есть чо не загруженное - загружаем
ну тебе нужно добится, чтобы ты мог востановить свои процессы и каналы по локальному стэйту
дак а как ретрай работает у тебя?
Ну вот сидит себе код на канале и ждёт, пока ему придёт событие "закончили" от коллбэка XHR, завёрнутое в канал. В цикле повторяет, если ошибка или таймаут.
ну вот, не явный стейт ага
Когда управление доходит до точки, в которой core.async паркует го-блок, core.async сохраняет этот стейт куда-то.
без кор.асинка по мне дак просто решается, а как с ним хз
Нужен. Если без него, то это пачка эвентхэндлеров. Я не хочу эвентхэндлеры писать, это код, вывернутый наизнанку.
Рич тут всё правильно говорит: https://www.infoq.com/presentations/clojure-core-async
да по мне core.async как замену коллбеков тащить это из пушки по воробьям. Я по началу тоже его везде тащил, но счас сто раз подумаю
тебе стейт нужно поделить на сохраняемый и несохраняемый. повороты/ресайзы картинки - сохраняемый, флаг "начался ли аплод" - нет. показывать прогресс бар - зависит от флага. при рефреше: ресайзы все восстановятся, а флаг начала аплода заресетится в false ==> прогресс бар не появится
добавления минимальной логики, реагирующей на ключи и значения стейта ты не избежишь. а кор асинк тут вообще ортогонален, мне кажется
но я бы и сам посмотрел, как взрослые дядьки используют корасинк "по-назначению". в юае пока что я видел только юзкейс заменяющий {:on-click #(logic)} на {:on-click #(tell that channel I want to execute logic)}
окей, я ещё поковыряюсь, и как у меня будет что-нибудь полезное/вечное/светлое - покажу.
у меня есть ещё один вариант, где такое было бы просто очень нужно: слаковый бот, который тоже event-based, в котором stateful-взаимодействия с клиентами, и которому было бы очень клёво переживать рестарт сервера.
Ну можно еще в хэндлере написать (let [res (<! ch (xhr)] do something), посмешивать их и тп
привет! а я пришёл порыдать. автор микрофреймворка-для-веб chestnut сейчас впиливает 'system', и не любит библиотеку 'mount' 😞 https://github.com/plexus/chestnut/issues/184
Вот не хочу я персистить 100500 чатов с клиентами руками, и делать стейтмашину руками на эвентхэндлерах.
@leov дак это вроде же темплейт просто? Инит сделал, потом поменял чо надо не?
если ты следишь за своим состоянием - то всегда из него можешь востановится - программа должна быть подчинена данным
ты жеж должен стремиться к pure-functions и минимизировать сайд эффекты. например с аплодом - единственный сайд эффект - аплод. всё остальное можно сериализовать в атом (реф)
дак человек не хочет руками все делать, в атомы класть и доставать. Кор.асинк юзать для хранения стейта, хопа-хопа и само и без атомов. Проблема тока что стейт не явный и достать его из каналов никак, зато не руками. Ну это я так понял)
@artemyarulin да, но следующая версия будет на системе. я не понимаю, почему просто люди могут любить систему вместо маунта. это же джава джава джава джава джава борщ борщ.. (
@leov вкусовщина. Форк тебе в помощь.
я не один из них не юзаю, мне норм
@artemyarulin не достать из каналов, если эти каналы кто-то уже нахачил, и впадлу переделывать
с форками какая беда - если ты делаешь форк в такой штуке, как веб микрофреймворк - ты сразу теряешь в безопасности и совместимости. это не та вещь, которых можно иметь миллион
@misha ну оно уже есть, выкидывать код жалко может 🙂
делать костыль, хлоп-хлоп-и-в-продакшен 🙂
цензура, вдруг тут дети 🙂
я вот смотрю , вчера ребята обсуждали как контекст пробрасывать в реакте, тут стейт корасинк
а там есть чо для контекста?
ну надо будет ID какой пробросить все равно ж
а там вчера было обсуждения на тему дерева вроде как
<Root id=‘main’>
<Link id=‘1’>
<Link id=‘2>
<Link id=‘3’/>
</Link>
</Link>
а ну ок, я краем глаза все читал, сори
@andre так ты и без рефрейма можешь на глобальный атом подписаться, а не получать его в аргументах
гм. вопрос по кложе - я пробрасываю в джавный интерфейс листенеров каких-то событий свою функцию, которую в reify этого интерфейса дёргаю
когда я обновляю код этой функции - он не обновляется а каким-то образом дёргается код старой функции
ща попробую ссылку из имплементации интерфейса на мой перезагружаемый реплом метод сделать явной, а не пробрасывать через паметры функции, которая всё это создаёт. может чего изменится
@leov Происходит следующее, если я правильно расшифровал подземный стук - когда ты даёшь джаве свою функцию, ты даёшь ей IFn
, который значение функции. Когда ты обновляешь функцию - ты меняешь состояние Var
, в котором начинает лежать новое значение.
Т.е. это то же самое, что сначала сказать (def myvar 42)
, потом передать myvar
в джаву, а потом удивляться, что после (alter-var-root #'myvar 43)
джава продолжает использовать старое значение.
Когда ты работаешь с самой кложей, ты этого не замечаешь: из символа myfun
вычисляется текущее значение Var
с именем myfun
, т.е. каждый раз происходит неявное разыменование.
@leov чтобы этого избежать, достаточно передавать в джаву вместо myfun
– #(myfun %)
, который каждый раз будет разыменовывать Var
, а не в момент засовывания значения в листенер.
В кложе всё – неизменные данные, и функции тоже 🙂 При переопределении функции меняется только Var
.
@leov А ещё Var
реализует IFn
, поэтому вместо анонимной функции в джаву можно передать #'myfun
@misha по поводу ссылки на твиттер. там один чувак спросил: what's so complex about abstract proxy bean factory factories? мне показалось это смешным, т.к. ответ: Все!
современное OOP таких монстров породило вида "ООП ради ООП", что отношения бизнеса и программистов похожи на отношения светской власти и шаманов. Шаманы просят дофига ресурсов ибо ООП код пухнет и требует больше помощников и ресурсов для шамана. Бедный бизнес платит за это. По моему мнению Рич вернул программирование на ту дорогу, с которой когда-то свернули. То есть признал шаманов шарлатанами и сказал "в жопу тайп корректнес - даешь business корретный код в массы".
в общем кложа екзистенциальная угроза религиозным фанатикам ООП.
ну не получается у них переписать сервис из 2000 строк на кложе меньше чем 6000 на скала и не менее чем в 2 раза дольше по времени.
@mike1452 Не для всех компаний это проблема. Но да, это отличное конкурентное преимущество.
Есть и недостатки — для того, чтобы компания, использующая Clojure, могла расти, ей нужно либо быть распределённой, либо быть готовой заниматься импортом программистов.
Даже Cognitect с самого начала был распределённым, а они-то могут себе позволить снять сливки 🙂
хм, а я могу как-нить из мапы достать значения по ключу но не fully qualified?
(def x #:person {:id 1 :identity 42 :name "Sam" :on? true :age 23 :friend [:person/id 2]})
(def y #:company {:id 1 :name "Co#1" :team [[:person/id 1] [:person/id 2]]})
;; Нужно достать :id, префикс для ключей допустим я не знаю, можно вот костыльно, ничо лучше нету?
(filter #(= "id" (-> % first name)) (seq x)) ;;> ([:person/id 1])
(filter #(= "id" (-> % first name)) (seq y)) ;;> ([:company/id 1])