This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-07-12
Channels
- # aleph (10)
- # beginners (79)
- # boot (81)
- # chestnut (3)
- # cider (9)
- # cljs-dev (336)
- # cljsrn (17)
- # clojure (121)
- # clojure-boston (1)
- # clojure-italy (4)
- # clojure-nl (1)
- # clojure-russia (218)
- # clojure-spec (32)
- # clojure-uk (98)
- # clojurescript (109)
- # cloverage (1)
- # core-async (5)
- # cursive (17)
- # datascript (15)
- # datomic (38)
- # editors (4)
- # emacs (6)
- # graphql (1)
- # hoplon (140)
- # instaparse (1)
- # jobs (2)
- # klipse (1)
- # leiningen (4)
- # lumo (2)
- # mount (103)
- # off-topic (3)
- # om (8)
- # onyx (19)
- # parinfer (32)
- # pedestal (3)
- # precept (32)
- # re-frame (33)
- # reagent (24)
- # remote-jobs (11)
- # rum (1)
- # spacemacs (1)
- # specter (37)
- # unrepl (4)
- # untangled (43)
- # vim (11)
Народ, как вы тестируете ваше API? Что используете? У меня pedestal, схемой валидирую запросы и ответы. Мне нужно мокать обращения к БД и другим сервисам, генерировать или подготовить данные для тестов и собственно запускать тесты. Что почитать что бы лучше в вопросе разобраться?
дак тестирование или валидация?
если генерить данные для тестов то конечно спека. Ну или https://github.com/clojure/test.check если спеку не охота тащить, но я б все равно лучше спеку взял
а мокать запросы чем?
эм, т.е. ты хочешь интеграционный тест прям, от ХТТП запроса до мок БД и до респонса? Есть кието либы, компонент вроде чота умеет типа этого, на а если просто нужно для юнит тестов то я обычно пишу свои функции как
(defn get-customer-fn [customer-finder]
(fn [id]
(do-other-pure-logic (customer-finder id))))
(def get-customer (get-customer-fn (my-actual-db-connection/find-customer-by-id)))
Т.е. по сути весь IO идет как параметром, поэтому тестить все очень простогоспода, а что такоего почитать по организации стейта в коде? проблема: дофига атомов и полей в них, между которыми связи со всякими нюансами (вочеры, которые сравнивает/не сравнивает значения на входе/выходе) хочется это всё нагляднее как-то засетапить, чтобы в глаза умещалось
можно конечно стейт машину в столбик написать, и из нее картинку генерить на каждое изменение, но хочется это как-нибудь по-кошернее распедалить
дофега mutable атомов это прям жава какая-то
а чо не один где весь стейт?
например сейчас "пишу" видео плеер, в котором звук отдельно, это уже сами по себе 2 мьютабл жс хреновины со своими ивентами
их нужно синхронизировать, давать возможность сдвигать звук левее/правее, потому что жизнь
и чтобы юай не захлебывался, много где нужно хирургичненько из одного здорового атома получать значение конкретного поля и игнорировать остальные изменения
хочется чистую тупую функцию "перемотать", которая не знает, что есть атом, а получает просто время куда мотать.
но если так сделать со здоровым атомом, нужно везде будет оборачивать вызов "перемотать" проверками "стаорое ≠ новое", инача на например изменение громкости оно будет на последнее место перемотки перематывать
ха, я делал видеоплеер тоже в свое время 🙂 у меня все эвенты от UI были в виде данных [:action/forward 10] [:action/pause true]
и дальше один диспатчер который уже все менял/мониторил
но если диспатчер не напрямую модифицирует audio/video объекты, а атом обновляет – то начинается всё, что я выше описал
>и чтобы юай не захлебывался, много где нужно хирургичненько из одного здорового атома получать значение конкретного поля и игнорировать остальные изменения т.е. у тебя UI подписывается на эвенты по сути всякие aka pull. У меня просто было push - диспатчер получал евенты и уже думал дергать какой UI или нет
ну и даже не про аудио/видео: просто когда появляется хоть пара значений, на которые нужно подписаться только если ≠ – то собирать эту инфу по всем неймспейсам в add-watch - такое себе удовольствие
>подписаться two way binding по сути же получается не? UI дергает изменения и подписывается на нове одноврменно
или у тебя есть сеть core.async каналов со всякими мультами и тд - хочется это в виде диаграмы видеть, а не глазами из кода выпаршивать
смотри, проблемы нахачить - нет, есть проблема наглядности. оно слишком многословно и размазано получается
ну вот значит да - слишком много всего и во все стороны что даж диаграму хочешь. Может как в redux/react - one way data binding?
подписки и add-watch уже попахивает
ну так 5 вочеров в 3 неймспейсах могут быть ван вэй, но их всёравно надо ходить собирать по проекту, и, в первую очередь, знать, что они вообще есть
а хочется как-то или табличку размером со страницу написать, или диаграмму надраг-дропать, и чтобы всё это говно сгенерилось за меня
сори, можешь еще раз развернуть почему один атом не канает у тебя?
в 1 атоме много полей. много полей = много подписок много полей = много ивентов "атом поменялся" не все подписки дешево звать каждый "атом поменялся" раз
хм, оно реально так медленно? в видео плеере у меня был 1 евент в секунду (таймер тикал) + иногда от юзера с десяток
но это фигня на фоне того, что этот граф зависимостей размазан по проекту всему, хотя там тупо 10-20 полей в атоме(атомах)
ээ, 10 полей и уже прям тяжело процу??
да не в процессоре дело йоптить, а в том, что я сижу и собираю эти несчастные 10 полей по 3 файлам
дак положи в один атом то епт 😄
нуууу, ну объясни для тупых почему не канает 🙂 Реально я не верю что перформанс просядет если в одном атоме все будет
мне важно, что я сижу и граф зависимостей собираю 40 минут, чтобы понять/вспомнить че ж там было то, когда мне нужно ветку к графу присобачить новую
дак это и решается как раз если одни атом будет нет? Все в одном файле, все видно
этот граф зависимостей с нюансами очень быстро разрастается, и перестает помещаться на страницу уже после 5 неудобных полей
+ если ты результаты вычислений складываешь в тот же атом - тебе на "клиенте" значения нужно дополнительно ≠ вызывать (чтобы то же видео бесконечно не перематывать например)
и вот твой атом протёк в компонент, который теперь должен не про значение знать, а про атом, чтобы смочь сравнить старое/новое значения
ну единсвенное что приходит в голову это сделать однопроходный апдейт, т.е. обновлять атом один раз и пересчитывать новый стейт один раз 1. Посчитать новое поле 1 2. Посчитать новое поле 2 3. Посчитать новое поле 3 на основе 1 и 2 4. Посчитать новое поле 4 на осное 3 Положить новый стейт в атом
т.е. может и будут хаки вида 5. Пересчитать поле 1 если поле 4 обновилось он оно будет в одном месте
ну а как ты хочешь? Если я тебя логика уже такая, либо явно монста этого описать (счас у тебя это не явно и в мозг не влезает) либо менять логику
почему?
можешь пример я плохо понимаю
меняешь ты звук, атом меняется, всем подписчикам надо решить делать что-то по этому поводу или нет
в итоге твои 1 2 3 4 количество ивентов "атом обновился" не уменьшают (ну может уменьшают, но гранулярности не добавляют всё равно)
ну вот, у тебя подписчики просто подписываются. А что если сделать что диспатчке обновляет стейт и потом уже сам дергает нужные контролы сам? Соответсвенно логика = будет в одном месте
и даже "чистые" подписки будут шум генерить, типа заставлять реакт пересчитывать равенства и тд, не говоря уже о сайд эффектах
a != b очень быстро работает так то 🙂
не везде дело только ≠ обходится же, и не везде нужно ниче не делать, если значение не обновилось, хотя то наверное уже про сайд эффекты, как ни крути
т.е. ака redux - контролы умеют слать евенты (юзер погроме захотел!) затем все уходит в диспатчер, тот обновляет стейт в один проход, пересчитыват новые поля (звук уже 100 и дальше can-increase-volume = false), обновляет стейт в атоме и затем решает (опционально ибо я думаю и так быстро будет) какие данные новые появились и дергает уже контролы с новыми данными (volume-control can-increas-volume=false)
вообще, я не сильно представляю, как написать убер функцию, которая весь атом пересчитывает, но при этом состоит из независимых обработчиков
ну котролы не должны делать сайд эффекты
по крайней мере напрямую, все диспатчер должен делать. Даже тотже HTMLVideoPlayer это mutable state и его должен менять только диспатчер
в подходе с 1 атомом получается, с т.з. подписчика на атом, бывает 3 причины получения ивента "атом обновился":
1. поменялось интересующее значение
2. кто-то тронул интересующее значение (для сайд эффектов полезно, типа "пойди базу синкни". (defn touch [a] (reset! a @a))
)
3. поменялось неинтересующее значение
а должно, как мне кажется, быть только 2 причины: 1
и 2
ага 2 это хак, по мне дак скрытое IO по сути, но ты и сам пишешь для сайд эффектов
при чем принимать решение "интересен ивент 1 или ивент 2" я хочу не на клиенте атома, а при создании графа, чтобы можно было втупую подписаться компонентом на атом, и смотреть только на значение, а не сравнивать старое и новое
@artemyarulin ну а как еще отделить чувака, который просит сайдэффект, и чувака, который его выполняет? не тянуть же корасинк ради единственного случая?
ну я уже писал - у меня весь IO в диспатчере просиходит, компоненты тупые и тока получают уже готовые нужные данные и иногда шлют экшены обратно в диспатчер когда юзер чо нажал
но это немного оффтопик, основная идея - я не хочу обрабатывать возможность 3
на клиентах
почему?
есть же отличный shouldComponentUpdate(a,b) { return a != b }
который отлично обрабывате ситуацию когда теже данные пришли
а теперь сижу и собираю по всему проекту кто на что подписан, и кто что когда меняет, с чего и начинал
@artemyarulin а как и куда в диспетчере полжить вот такое?
(add-watch !STATE ::audio-delay
(fn [k r o n]
(let [id (::episode-id n)]
(when (not= id (::episode-id o))
(reset! !AUDIO-DELAY-MS (audio-delay-by-episode-id! id))))))
это заменяется на ивент, но кто этот ивент вызовет? куда положить знание о том, что когда айди эпизода меняется - нужно передернуть подсчёт/фетч дилея?
типа наделать кучу ивентов для изменения конкретных атрибутов кнопками, и 1 ивент "пересчитать всё!" с огромным обработчиком, в котором каскадно весь стейт пересчитать?
ну ты уже почти сделал redux, actions у тебя уже есть (суть именованные евенты с доп данными), осталось изобрести reducers чтоб был не один большой хендлер а несколько малельнких
В данном конкретном случае я б сделал что контрол шлет :video-ends
-> video-control-reducer создает [:episode-ends :reset-audio-delay]
ну а playback-reducer уже обрабатывает :reset-audio-delay
и делает нужный IO
ну т.е. изолировать всю бизнесс логику которую тебе надо выполнять когда видео заканчивается в одном месте. В терминах redux это reducer, в ом-некст это вроде мутации, хотя я уже забыл. В других фреймворках по другому называется
кароче у меня пока что сложности с тем, куда запихнуть вызов ивентов "второго порядка", типа кто, когда и как будет следить за тем, что нужно вызвать каскадные изменения. типа внешний ивент запустил изменения внутри, которые хз как порождают дальнейшие изменения внутри
>куда положить знание о том, что когда айди эпизода меняется я думал это оно. Ну в общем ты позырь на редукс - он мелкий сам по себе, можно за часик на коленке такой-же делать. У меня старый проект был на ObjectiveC, тоже мешанина хер разберешся, сделал redux на коленке и все через него провел - полет отличный
а теперь как бы так сделать, чтобы после применения чистого ивент хендлера стало понятно, что нужно следом что-то еще поменять, и всё это перед тем, как закоммитить в атом?
Да немогу react-native run-android
запустить на реальном андройд девайсе. вроде все проходит и adb не падает, и на мобиле даже окно появляется но оно чего там долго ждет фигвил
@artemyarulin ну вот смотри: http://redux.js.org/docs/basics/UsageWithReact.html они фильтр визибл тудушек суют в компонент
я этого как раз хочу избежать и вынести в стейт, или в другой атом, который подписывается на стейт
и вот где мне в этом редуксе сказать, что после изменения вот этого поля стейта стрельни вот эти 3 ивента на пересчет остального?
не, в таком случае обработчик ивента должен будет знать, на кого он повлияет, а нужно чтоб не знал.
@misha В ре-фрейме есть такая штука, как подписки, которые тебе из события "что-то сменилось" делают события "поменялось a". Сложи их все в одно место, и навесь на их результат хэндлеры.
Кому тут хотелось Clojure в браузере? http://plasma-umass.github.io/doppio-demo/
@artemyarulin спасибо. вот только мне нужен swagger, а я пока подружить спеку, педестал и сваггер не смог
вот смотрю на https://github.com/metosin/spec-tools. Может эта штука поможет
сваггер тема да, но я начал юзать его уже после кложы, не могу сказать
>в редюсере после изменения стейта позвать диспатч? так это ж уже и/о, а не чистота
вся цепочка выглядит вот так control -> action -> [action-can-produce-new-actions] -> data -> reducer -> new state
. При таком подходе action это где все IO происходят, редьюсеры все чистые.
На самом деле это все фигня - главное найди одно место где весь IO у тебя будет происходить и все будет ок. Тока помни что мутирование переменной (атом) это тоже IO (хаскель FTW!). Как тока весь IO будет изолирован - дальше можно чо угодно делать ибо все остальное то чистое
@dottedmag сижу монстрю что-то подобное: мапа {[state-keys] callback}, которую засуну в 1 вочер, который будет по всем ключам проходиться, и если значение хоть одного из state-keys изменились - дергать колбэк, в котором просто (диспач ивент) лежит
потому что экшн - это тупо киворд, откуда ему знать, какие в итоге ключи в стейте поменяются?
action не меняет же стейт напрямую
он не знает про ключи в атоме
получается типа такого:
button -> action -> handler -> new state -> [maybe-new-actions] -> handlers -> new state -> [maybe-new-actions] -> handlers -> new state -> ...
у тебя ре-фрейм или руками все? Ре-фрейм же должен решить проблему стейта
да какой рефрейм, рум, но я хочу всё забацать так, чтобы весь стейт можно было в кложа-репле проверять, а компоненты все статическими сделать
аааа, рум как скала - умеет стейт хендлить как хочешь поэтому не умеет вовсе ::troll:
ну вот текущая имплементация - там размазано: половина в 1 атоме, половина в остальных, и еще немного в локальном, и песец
но рум же - просто вью либа, ты ж сам диктуешь как и чо. вот хочу перехачить так, чтоб можно было весь апп симулировать без компонент совершенно, а потом хоп и дописал компоненты
ну чисто redux 😄
ну еще ом-некст так умеет тоже, его возьми!
тут ксто юзает om-next? как оно вам?
Не понимаю я тебя, у нас в компонентах логики нет вообще, тупо f(data)->HTML
ну и в этом же фишка его, что не подсчеты в компонентах а в reducers. Тож самое с омом - контролы умееют тока наверх кидать эвенты, диспатчер их обрабатывает в одном месте и посылает если надо новые данные в контролы обрытно. One way data binding все дела
Reselect is a simple library for creating memoized, composable selector functions. Reselect selectors can be used to efficiently compute derived data from the Redux store.
оспади, 107 строк, я думаю ты осилишь
а в том, что у тебя редакс стор и редюсеры на одной странице, а вся эта дерайвед-дата-подсчет кухня - размазана по остальному проекту и компонентам
а я как раз всё о "что из чего вытекает, перетекает, зависит" хочу на 1 страницу как-то вывалить, чтобы в глаза поместилось
https://github.com/konukhov/redux-cljs Redux for ClojureScript based on core.async and transducers. во как, самый смак!)
хочу 1 структурой данных всю канализацию эту описать наглядно, и потом кода из неё сгенерить
ну ты писал чуть выше что гиганский диспатчер ты тоже не хочешь. Оно не будет размазано прям по всему проекту, это вполне себе конкретный слой, все рядом будет лежать
какие каналы в какой сливаются, где мультиплексор стоит, где входы, где стоки, какие трансдюсери промеж них
>и потом кода из неё сгенерить ловите кложуриста!
тут любят просто генерить 🙂
ну в общем я хз уже, ты как найдешь решение - скажи, мне уж самому интересно стало 🙂
надо в оникс посмотреть, там примерно такое же вроде: всё данными описано, но там слишком детально, а нужно на уровень-два выше
как Кишанов жаловался, что разрастается проект на рефрейме - вроде всё структурировано, а вроде уже и хрен пойми как оно выглядит "свысока"
вот такую беду для подписок пока налепил, нужно чуть поитерировать:
(def SUBSCRIPTIONS
"{[state-keys-to-watch] callback]}"
{[::paused?]
(fn [old-state new-state]
(if (-> new-state ::paused? (true?))
(dispatch ::pause!)
(dispatch ::play!)))
[::playback-rate]
(fn [old-state new-state]
(dispatch ::change-playback-rate!))})
(add-watch !STATE ::derivatives
(fn [k r o n]
(doseq [[ks f!] SUBSCRIPTIONS]
(let [ov (select-keys o ks)
nv (select-keys n ks)]
(when (not= ov nv)
(f! o n))))))
капс убери, не по джентельменски
>`(fn [k r o n]` да ты все по одной букве называй чо ты
кароче идея такая, что диспатч свапает стейт по экшн-киворду (надо ему ! дописать), и один вочер обслуживает все каскадные подписки
а !STATE
восклицательный знак в начале это чо значит? в конце обычно когда IO
получается, что диспатч дергают только ивент-хендлеры, типа он-клик, он-сик, и вот этот вот единственный add-watch
всем привет. а кто-нибудь уже использовал сие? https://github.com/jeaye/orchestra
фак зе тайп систем короче
@artemyarulin https://github.com/konukhov/redux-cljs какой-то многословный слишком, либо я еще не разобрался и не осознал степени гемора проблемы, либо там и правда личнего как-то дофига, например, зачем экшен - мап с одним полем всего, ну и всякого по-мелочи да и она заброшеная™
да ты погугли redux clojurescript выдает тысячи их, ты свой костыль велосипед свою реализацию сделай! 🙂
@misha аргумент у Рича? не знаю. эта либа все проверяет - спеку на:, входные, выходные параметры и fn спеку
@mike1452 это я понял, но там был годный аргумент, почему :fn и :ret не проверяются в спеке, только я его забыл
@misha :ret and :fn specs were originally validated by instrument, but this feature was removed because Rich et al thought it redundant, and that there were different (and arguably better) tools for validating :ret specs, e.g. check.
On Monday, July 11, 2016 at 10:01:05 AM UTC-4, Rich Hickey wrote: On Sunday, July 10, 2016 at 6:04:39 AM UTC-4, puzzler wrote: 1. No way to test function output specs. For documentation purposes, I want to have an output spec on my function. However, as far as I know, after instrumentation-triggered checking of output specs was removed a couple of alphas ago, the only way remaining to check against output specs is to use randomly generated tests. So if I can't make good generators, I have no way to confirm that my output spec works the way I think it does. My documentation could be totally out of touch with reality, and that displeases me. Running return-value instrument-style checking on whatever few hand-written tests you might have isn’t going to give you better coverage than a simple (even hardwired) generator that captures similar ranges. And you can directly exercise your :ret spec - it’s just another spec. You can also spec/assert on your return - the tests will disappear in production, although this is similarly as weak as instrument-triggered return checking, so I’m not going to help you do it, but you can do it yourself 🙂
ага, Миллер, когда объясня, делал упор не на "хз чо оно там натестит", а на "слишком жирно на каждый вызов функции запускать для неё генеративное тестирование - ласты склеятся"
@artemyarulin on it!
я почитал объяснения Ричи но все равно так и не понял зафега убрали эти проверки если честно. Перформанс тоже мимо ибо спеки тока в девелпменте работают же
@artemyarulin тогда просто, верь Ричу. Рич сказал, значит так надо. )))))))))
ну дада, иногда Ричи такую фигню задвинет что ужосужос, а через пол года дойдет тока 🙂
все помню как через пару недель с кложай - “в смысле я не могу поменять перменную, чозанах??111” 🙂