Fork me on GitHub
#clojure-russia
<
2017-04-11
>
razum2um03:04:14

@kuzmin_m ну расскажи, заинтриговал

artemyarulin04:04:33

>И весь этот год я испытывал отвращение и не понимал идею stuartsierra/component. расскажи да, я все еще на этом этапе 🙂 Правда я на CLJS поэтому всякие db-connection у меня нету

misha05:04:39

компонент просто джавой очень пахнет, всё там понятно когда его использовать: есть сервисы, зависят от еще сервисов, общаются очередями, шарят пул соединений к базе/базам, нужно в одном очевидном месте это всё инициализировать, и с возможностью некоторые куски рестартовать без укладывания всего “монолита“. На джаве очень похожее на компонент писал, только не оформленное в библиотеку, а “инлайн“. Работает хорошо, но придя в кложу надеялся, что есть менее “корпоративный” что ли подход.

misha05:04:53

у меня впечатление от “компонента vs. самому на коленке” такие же как от “рефрейм vs. rum” – то ли юзкейса не было еще подходящего, то ли проект еще не достаточно огромный, то ли “инлайн” решения хватает. Это как джавах паттерны, потому что код к глаза не умещается, а в функциональных языках - просто функции.

artemyarulin05:04:23

@misha у тебя ж вроде CLJS + RN проект да?

misha05:04:45

да, но я последние полгода почти эмулятор не запускал даже

artemyarulin05:04:08

в смысле бросил или пишешь на CLJC?

misha05:04:56

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

misha05:04:24

переключался на подпроект на пару месяцев. сейчас перевожу что есть c cljs на cljc, читаю, че там понаписывал, более явно отделяю стейт/логику от вьюх

misha05:04:59

последние пару месяцев задумываюсь об ивент сорсинге и пытаюсь себе его продать, пока не особо получается opieop

artemyarulin05:04:35

ха, я почти сразу начал писать свой RN на CLJC, тоже доставляет что не нужны эмуляторы/браузеры и репл шустрее на 10 миллисекунд работает 🙂

misha05:04:13

ну я на подпроекте чутка подраздуплился в repl-driven-development’е, (пришлось когда таба браузера начала захлебываться на 40-60к датомах жатаскрипта 🙂 ), и понял, что нужно и возможно логику в хорошем кложа-репле отдебажить, может даже спекой покрыть, а не бесконечно перелистывать десктопы с IDE на браузер и обратно, и дебажить принтами, потому что в курсиве кложаскрипт репл такой себе

misha05:04:07

а потом накидать отдельно вьюх что для веба, что для мобилочек.

misha05:04:48

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

artemyarulin05:04:54

>пришлось когда таба браузера начала захлебываться на 40-60к датомах жатаскрипта “а теперь попытаемся со всем этим взлететить“(с) У тебя ифончик то не взорвется от напруги? 🙂

misha05:04:46

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

misha05:04:59

1) пока я доберусь до прайвет беты даже - наверное уже 5ые айфона отомрут kappa 2) датаскрипт я уже там сложил в отдельный javascriptcore процесс и нахлобучил кеш в основном javascriptcore процессе в виде {id entity} с синхронизацией, откуда вьюхи берут данные по цене хешмапы

misha05:04:03

про “захлебываться на 60к датомах” - это не про запросы/пулы. на тот момент мне надо было чистить и бекапить эту базу, и на каждое телодвижение нужно было упаковывать/распаковывать транзитом, еще и в файл класть. делать это табой браузера - eew

misha05:04:17

дойдут когда руки, хотел перфоманс тесты на датаскрипт на основе этого датасета написать: ветвистость данных в разумных пределах, и их достаточно много.

rmuslimov05:04:32

позвольте начать новую тему

rmuslimov05:04:46

Под НГ я пил что-то крепкое с любителям хаскеля, и он мне сказал прямым текстом: что вот концепция exceptions (популярная в джаве, питоне, руби и много еще где) вообще не очень классная. И вообще является не composable и с ней сложно жить. Новый год закончился, я об этом как то забыл, хотя и поверил товарищу на слово. Вот собственно теперь когда у меня питоновское приложение покрылось кучей try-except на разных уровнях функций, превратилось и продолжается превращаться в сложно читаемое месиво, я бы хотел вернуться к этому вопросу и узнать если не exceptions то как? Дано: сложная stateful интеграция с travel провайдером с кучей последовательных вызовов и перехватами ошибок которые по различному перезапускают процесс. Сейчас это куча try-except на разных уровнях, и очень неудобно все это читать. Вопрос: как сделать если не вот этими try-except как выглядит haskell-way, clojure-way, whatever-way без try:except?

artemyarulin06:04:12

Страшное слово на букву M. Не очень страшное слово Promise (которая по сути монада)

artemyarulin06:04:12

Без error as value точно не обойтись. А когда оно есть далее уже можно композить все это дело

misha06:04:05

@kishanov так это ж и есть монады, грубо говоря

artemyarulin06:04:49

ваат? Главный наезд на го как раз что ошибки просто значения и никакие не монады, т.е. композить ошибки ты никоим образом кроме как if err не можешь

artemyarulin06:04:09

ну т.е. если if считать как способ композиции, то да…. очень грубо говоря 🙂

misha06:04:39

так а промис тогда каким образом монада?

artemyarulin06:04:29

У промиса есть then, что является монадическим bind

artemyarulin06:04:49

Promise.resolve(10) .then(do-a) .then(do-b) .then(do-c)

artemyarulin06:04:31

Вообще там просто

Left identity:	
return a >>= f
≡	
f a
Right identity:	
m >>= return
≡	
m
Associativity:	
(m >>= f) >>= g
≡	
m >>= (\x -> f x >>= g)

roman01la06:04:38

У нас в кложе активно используется Either, удобная штука

misha06:04:54

получается промис - частный случай респонса вида [result, error] в го, который если дополнительно оформить в тип с then’ами - получится монада?

artemyarulin06:04:31

дада, получится монада Either как раз 🙂

misha06:04:45

сказал же “грубо говоря“ 🙂

artemyarulin06:04:27

@roman01la а вы через какую либу типо котов или сами написали?

roman01la06:04:06

Своё. То же самое в сущности)

artemyarulin06:04:56

грустно что из коробки ничего такого в кложе нету, былоб круто

roman01la06:04:26

left, right, fmap, flat-map, on-realized вполне хватает для нормальной работы

asolovyov07:04:25

@misha mount очень клевый

misha07:04:55

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

asolovyov07:04:44

мы юзаем со средины лета и я ни разу не почувствовал боли

asolovyov07:04:54

никто ни на что тоже не смог пожаловаться

savelichalex07:04:59

а чем cljc лучше? есть что почитать?)

fmnoise07:04:31

лучше чем что?

artemyarulin07:04:21

дак просто если например бизнесс логика тока, то поднимать RN, эмулятор да и просто даже браузер с фигвилом иногда лень. То круто просто заюзать CLJС заместо CLJS и юзать clojure-mode грубо говоря

savelichalex07:04:20

хм, так поди cider проще юзать, да?

artemyarulin07:04:21

мне еще нравится что я могу синхронные HTTP реквесты кидать

(->> (io/http "")
   parse-xml
   do-a
   do-b)
с CLJS (JS) такое не сделаешь

artemyarulin07:04:54

ну понятно что такое чисто в репле поиграться, в код оно не идет, но дебажится всякие парсинги диких JSON на ура

savelichalex08:04:54

надо будет взять на заметку, спасибо)

artemyarulin08:04:09

в свое время мне очень хотелось такое в CLJS заполучить, чтоб в репле я мог эвалить такое в том числе, т.е. асинхронное вычесления поддерживать но чота не осилил как оно вообще работает там(

artemyarulin08:04:46

пытался такое в PureScript репле тоже сделать омг, в этом хаскеле коде не понял даже где начать 😄

ilevd08:04:01

Это для react native специфично? Или для браузера? Какой соотношение кода получается cljs к cljc?

ilevd08:04:25

Или если например там на re-frame завязано?

artemyarulin08:04:06

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

artemyarulin08:04:42

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

ilevd08:04:44

У меня обычно c cljc один файл utils с парой функций получается)

artemyarulin08:04:58

Ну вот мое, но у меня тут монорепо с кучей всего

bash-3.2$ find {lib,app} -name "*.cljs" | wc -l
      31
bash-3.2$ find {lib,app} -name "*.cljc" | wc -l
      47
bash-3.2$ find {lib,app} -name "*.clj" | wc -l
      14

artemyarulin08:04:36

все от приложения зависит

ilevd08:04:12

Спасибо, интересно

misha08:04:03

(Или cloc?)

misha08:04:40

А то мало ли, какого у тебя размера файлы

artemyarulin08:04:58

он много чего покажет, а я не хочу вам говорить сколько у меня XML в моем могорепо 😛

misha08:04:05

Нерелевантное спрячь же, ну

mike_ananev09:04:51

@misha в разрезе reframe vs rum ты за rum?

misha09:04:00

@mike1452 да, даже если я себе ивент сорсинг продам - то не рефрейм, а, либо порт его на ром, либо что-то другое, возможно даже какого-то самописного выкидыша будет достаточно

mike_ananev09:04:13

я вот посмотрел презу Никиты по Rum и решил свой пет проект на Rum попробовать. Уж очень мне simplicty в Rum понравилась

misha09:04:23

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

misha09:04:16

но я его не знаю: не читал, но осуждаю, кароче, особо не прислушивайся к моему мнению на этот счет

roman01la09:04:16

мне рефрейм напоминает редакс: вроде просто, но документация закидывает словами типа ко-эффекты и тд

savelichalex09:04:50

я вот посмотрел на rum, и реагент мне кажется проще) там вообще ниче понимать не надо особо)

savelichalex09:04:08

а в рефрейме просто доки разжеваны, так что тупой разберется)

ul09:04:31

reagent is easier, rum is simpler

ul09:04:18

но с другой стороны, если в приложении нет нужды применять разные походы к стейт-менеджменту компонента и реагентовскийй подходит, то easier здесь обретает хороший смысл

ul09:04:57

ды re-frame и rum из разных уровней, не?

ul09:04:02

как вы их сравниваете?

misha09:04:37

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

savelichalex09:04:40

да дело то не в этом. я может просто не уловил плюсов rum-а, мне просто охота писать приложеньку, а не сидеть с либой разбираться. просто в reagent-е именно так и происходит, 5 минут доку прочитал и погнал делать

misha09:04:09

нетерпеливый opieop

savelichalex09:04:40

я бы лучше сказал практичный 😄

misha09:04:57

в rum секцию с примерами наглядней чуть сделать - тоже за 5 минут с нуля можно будет нахлобучивать

misha09:04:53

вопрос еще в том, знаешь ли ты когда упрешься в ограничения библиотеки, и упрёшься ли в них вообще?

savelichalex10:04:04

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

ilevd10:04:04

Я re-frame 3 дня читал, и так и не понял до конца с эффектами/коэффектами, зачем event handler делать pure? Только для тестирования?

dottedmag10:04:30

только для тестирования, хаха.

savelichalex10:04:49

@ilevd для композиции же!

savelichalex10:04:06

просто после 7го рефрэйма понятно зачем коэффекты)

misha10:04:54

@ilevd эка тебя императивщина потрепала kappa

misha10:04:40

@savelichalex так а чо за коэффекты?

ilevd10:04:14

Ну там пример приводится, запрос делается и в event handler и там же subsribe на succes и error, что в этом плохого?

ilevd10:04:40

Чтобы по науке сделать там надо еще что-то подключить, какую-то зависимость

mike_ananev10:04:53

Я в разработке фронтенда еще не участовал. Опыта пока мало. Пока для себя сделал следующие выводы: 1) следуя идеологии clojure (где-то в презах было) что clojure простая, а runtime JavaScript - "доставляет". то есть он установлен на миллионах девайсов. Таким образом появилась возможность писать на "простой" clojure приложения в разных рантаймах. 2) По моим наблюдениям от деления фронт - бэк мы потихоньку движемся к равноправным приложениям на мобиле и сервере, которые обмениваются данными. То есть разработка полноценных приложений на фронте становится очень похожей на разработку толстых клиентов или RIA где надо стейтом управлять и куча асинхронных событий. 3) у clojure и clojurescript есть подходы, как управлять стейтом и как бороть асинхронность. 4) в Rum задействован подход управления стейтом на механизмах clojure. Или на простых атомах или в datascripte. 5) у реагента и ре-фрейма атомы свои, чуть-чуть подтюненные. более того ре-фрейм больше похож на фреймворк. Таким образом в начале разработки, потенциально я имею выигрыш на рефрейме. Но если приложения разрастется, то фиг знает, как оно там выйдет. Особенно если подтюненные атомы начнут глючить. Или фреймворк начнет накладывать ограничения.

savelichalex10:04:55

@misha ну типа сайд эффекты всякие исполнять) просто раньше например это все в одних хэндлерах делалось, и ты к примеру делаешь запрос к серваку

(register-handler
    :fetch-smth
    (fn [db _]
      (fetch ...)
      db ;; <- вот тут нужно было обязательно вернуть
    ))

mike_ananev10:04:57

пока такие мысли

savelichalex10:04:12

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

misha10:04:15

@savelichalex кароче - еффекты - чистые хендлеры, коэффекты - хендлеры с сайдэффектами, так?

misha10:04:43

а че там 100500 страниц доков-то делают тогда?

artemyarulin10:04:47

offtop: http://blog.timac.org/wp-content/post-images/Facebook87/GrandPerspective_small.png зацените в приложении ФБ RN js.bundle 12и метровый

savelichalex10:04:48

ну типа того, просто чтобы хэндлеры были чистыми и можно было композить их

ilevd10:04:15

Коэффект - то что приходит в хендлер грязное, эффект - сайд эффект то что этот хендлер производит

savelichalex10:04:21

это чтобы даже самому дятлу было понятно как юзать 🙂

dottedmag10:04:29

@artemyarulin На фоне 136-мегового FBSharedFramework теряется как-то.

dottedmag10:04:20

@misha Эффекты - это stateful действия, которые хэндлер порождает. Коэффект - это stateful-действие, результат которого требуется хэндлеру для работы.

misha10:04:37

а я тут ссу лишний кб в иконке заинклюдить opieop

dottedmag10:04:43

Эффект - UPDATE purchases WHERE, коэффект - SELECT FROM purchases WHERE

misha10:04:27

что-то это противоречит тому, что @savelichalex одобрил 🙂

dottedmag10:04:18

Не вижу.

dottedmag10:04:35

@misha В общем, эффект - это описание результата, а коэффект - описание аргументов.

dottedmag10:04:38

А хэндлер чистый.

misha10:04:43

теперь понятно, почему там столько доков

dottedmag10:04:18

Потому что автор явно хочет по зауми достичь хаскелистов.

misha10:04:53

ну и вот где гарантия, что в потрохах там не без такой же зауми в ущерб продукту?

savelichalex10:04:40

@misha у тебя параноя 😄

savelichalex10:04:10

так коэффекты/эффекты это монада или апликативный функтор? или ни то ни другое? 🙂

misha10:04:44

@savelichalex ты же уже на рефрейме нахлобучиваешь, пора было и разобраться kappa

savelichalex10:04:02

я просто из монад только maybe и either знаю, не силен я в этих вещах 😄

ilevd10:04:32

@savelichalex а можешь привести пример композиции эффектов и зачем это может быть надо?

savelichalex10:04:44

@ilevd не, я же говорил, мне пока не пригодилось это) но так как просто мапа возвращается из функции, то считай можно ее менять потом как угодно

ilevd10:04:57

А там же эффект-handler зависит только от данных что вернет event-handler и только от этого? Можно сразу мапу поменять в event-handler, тогда

kuzmin_m12:04:22

по поводу компонента я набросал страничку вводного текста, без этого будте сложно понимать дальнейшее там есть возможность оставлять комментарии https://docs.google.com/document/d/1oMt4vuAfM7PHGTBTm_pSsOkz-0RZbSdoOxNq5sqWnc0/edit

kronos_vano12:04:26

про компонент я напишу позже troll

artemyarulin12:04:57

>Для моделирования сущностей я применял map вида {:user/name “John”, :user-presentation/posts-count 3}. Проблема в том, что не понятно какого типа эта запись, что в ней, и никакого полиморфизма. вот почти сразу - сам Ричи как раз говорил что типы не нужны ибо user как тип вещь статичная, а кложа динамичная и :user/name может находится где угодно в 100500 разных мапах, поэтому спека описывает ключи аля :user/name отдельно и если очень надо то отдельно мапу

kuzmin_m12:04:01

да, пока времени только на это хватило плюс интересна обратная связь

artemyarulin12:04:04

если честно я в этих протоколах/reify/multimethod/interface полный нуб в кложе, один раз в жизни мультиметод заюзал и как-то все. >проникся протоколами, типами, reify, я на другой кложе пишу да 🙂

kuzmin_m12:04:39

по поводу :user/name есть юзер, а есть админ по идее админ это тот же юзер и имя у него будет :user/name но у них разный алгоритм рассчета зарплаты или еще чего т.е. с точки зрения ооп мира удобно объявить протокол расчета ЗП и админ и юзер его реализуют, но по своему как это сделать не указывая тип в этой мэпе я не знаю

misha12:04:47

Не ясно ни о чем, ни к чему

artemyarulin12:04:10

оно конечно кому как привычнее, я бы сделал просто явно

(defn calc-user-salary [user] ...)
(defn calc-admin-salary [user] ...)
(defn calc-boss-salary [user] ...)

(defn calc-salary [user-type user]
  (case user-type
    :boss calc-boss-salary
    :admin calc-admin-salary
    calc-user-salary)
  user)
А откуда user-type берется, из самой мапы или откуда еще это уж дело вызывающего кода

savelichalex12:04:11

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

artemyarulin12:04:08

я б даже сделал вот так, чтоб даже асоциацию ключей и калькуляторов данными сделать

(defn calc-user-salary [user] ...)
(defn calc-admin-salary [user] ...)
(defn calc-boss-salary [user] ...)

(def calculators
  {:boss calc-boss-salary
   :admin calc-admin-salary
   :default calc-user-salary})

(defn calc-salary [user-type user]
  ((get calculators user-type :default) user))

kuzmin_m12:04:48

@artemyarulin это рашение в стиле стуктур данных, я упомянал об этом в тексте но как найти этот user-type? ну прилетает в api запрос дай зарплату пользователя, вот его id - :user/id как дальше делать?

artemyarulin12:04:57

ну а каким магическим образом ты это сделаешь с рекодрами/мультиметодами? Где-то ассоциация то будет

artemyarulin12:04:12

покаж пример как ты бы сделал

kuzmin_m12:04:11

(defprotocol CalcSalary
  (calc-salary [_])

(defrecord User [name]
  CalcSalary
  (calc-salary [_] 0)) ;; работает бесплатно

(defrecord Admin [name]
  CalcSalary
  (calc-salary [_] 100500)) 

kuzmin_m12:04:55

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

artemyarulin12:04:08

ну это понятно, ты ж грил что вот прилетает в апи запрос с :user/id

kuzmin_m12:04:12

т.е. юзер может и не знать, что ему ЗП считают

artemyarulin12:04:25

или у тебя будет прилетать типизированный user?

misha12:04:35

быгыгы

artemyarulin12:04:03

ну у меня юзер тоже ничо не знает про зарплату, у меня собстно и юзера то нету troll

kuzmin_m12:04:34

(def user (->User "John"))
(def admin (->Admin "Admin")

(def hander [id]
  (let [user (get-user-by-id id)]
    (calc-salary user)))

kuzmin_m13:04:04

ну обычный полиморфизм подтипов troll

savelichalex13:04:30

а мне больше другое интересно, вот у мапы есть куча методов, ну хотя бы тот же get, если у тебя есть тип User как у него выполнить эти методы?

kuzmin_m13:04:06

появится еще тип пользователя просто добавляется тип и реализация протокола ничего остальное не меняется append-only программирование troll

kuzmin_m13:04:49

@savelichalex там надо defrecord вместо deftype

savelichalex13:04:08

так а что меняется?

kuzmin_m13:04:14

а, там как раз defrecord

kuzmin_m13:04:24

да, можно (:name user)

kuzmin_m13:04:28

(:name admin)

artemyarulin13:04:34

Ну вот мой вариант

(defn process-request [req]
  (let [user-id (get-user-id req)
        user-type (get-user-type user-id)]
    (calc-salary user-type user-id)))
вот у меня будет явно get-user-type вызываться и там будет как раз высчитываться/искаться user-type. А как ты будешь с деврекордами то это делать? Ты ж сам гришь приходит :user-id и все в запрос

kuzmin_m13:04:04

(get-user-type - что там внутри?

artemyarulin13:04:06

а все, ты в (get-user-by-id id) это делаешь

savelichalex13:04:12

как это работает :thinking_face:

kuzmin_m13:04:36

рекорд реализует java интерфесы, что и PersistentMap

artemyarulin13:04:38

ну в общем у меня явно все данные, у тебя через дефрекорды, понял ага

kuzmin_m13:04:55

@artemyarulin (get-user-type - что там внутри?

artemyarulin13:04:29

дак я хз, ты ж сам сказал что приходит в запросе тока user-id. Может в базу надо будет сходить узнать тип юзера, может еще куда

kuzmin_m13:04:06

ну я к тому

{:user/name "super admin", :admin/rank 3, :superadmin/last-login ...}

kuzmin_m13:04:14

и как понять тип?

kuzmin_m13:04:57

и как потом выбрать реализацию алгоритма расчета зп?

artemyarulin13:04:09

дак а я не понимаю как ты то это решишь, вот тебе пришло такое-же в запросе как ты сырые данные к своим дефрекордам замапишь?

kuzmin_m13:04:28

хороший вопрос))

kuzmin_m13:04:41

сейчас отвечу

kuzmin_m13:04:54

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

kuzmin_m13:04:34

т.е. тип должен быть

artemyarulin13:04:55

не понимаю зафега мне дефрекорды в таком случае вообще ибо у меня оно явно везде юзается

kuzmin_m13:04:00

а как работать с

{:user/name "super admin", :admin/rank 3, :superadmin/last-login ...}
я не понимаю

kuzmin_m13:04:07

у тебя типа нет

kuzmin_m13:04:17

в мэпе должно быть поле тип

artemyarulin13:04:18

дак ты его сам достаешь из базы

kuzmin_m13:04:41

ну так - да

kuzmin_m13:04:50

просто выше была цитата

kuzmin_m13:04:05

вот почти сразу - сам Ричи как раз говорил что типы не нужны ибо user как тип вещь статичная, а кложа динамичная и :user/name может находится где угодно в 100500 разных мапах, поэтому спека описывает ключи аля :user/name отдельно и если очень надо то отдельно мапу

artemyarulin13:04:23

(defn process-request [req]
  (let [user-id (get-user-id req)
        user-type (get-user-type user-id)]
    (calc-salary user-type user-id)))
ну вот мой код и представь что get-user-type делает как раз это

kuzmin_m13:04:29

и если нет типа, то непонятно, как выбирать рализацию

kuzmin_m13:04:37

а как он это делает?

kuzmin_m13:04:44

{:user/name "super admin", :admin/rank 3, :superadmin/last-login ...}

kuzmin_m13:04:52

вот какого оно типа?

artemyarulin13:04:53

да блин 🙂

artemyarulin13:04:14

т.е. тебя дефрекорды защитят от такого запроса чтоле?

kuzmin_m13:04:17

{:entity/type :superadmin, :user/name “super admin”, :admin/rank 3, :superadmin/last-login ... }

kuzmin_m13:04:23

вот так понятно какого

artemyarulin13:04:23

[:superadmin {:user/name "super admin" :admin/rank 3 :superadmin/last-login ...}] а так уже не понятно?

kuzmin_m13:04:00

так понятно

artemyarulin13:04:13

ну дак я к этому и веду как раз

kuzmin_m13:04:20

я к тому, что если есть просто мэпа без типа, то не понятно как с ней работать

kuzmin_m13:04:47

т.е. мапа с типом и мультиметодом, это то же, что и рекорд с протоколом

kuzmin_m13:04:59

а мене интересно что, мапа без типа

artemyarulin13:04:11

дак в любом случае будет где-то маппинг сырых данных к либо нужному defrecord либо просто будет каким-либо образом искаться явно тип юзера

artemyarulin13:04:47

ну дак понятно что мапа с типом это круто

artemyarulin13:04:00

еще б при компиляции оно проверялось и вааще ах troll

kuzmin_m13:04:28

ну тогда надо в жаву))

artemyarulin13:04:53

дада я к этому и веду что кложа динамична и в этом ничо плохого нету

artemyarulin13:04:23

в общем я считаю что это вопрос стиля, явно тип как данные или неявно в рекордах

kuzmin_m13:04:33

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

artemyarulin13:04:47

а ну окей, мне тогда еще долго до него 😄

ilevd13:04:40

Хмм, я вот использую, и мне наоборот, если бы было без defrecord было бы удобней, наверное

artemyarulin13:04:56

ты про компонент?

ilevd13:04:36

По сути там старт и стоп функции к кускам данных

kuzmin_m13:04:55

можно сделать компонент на мэпах

kuzmin_m13:04:03

но тогда в мэпе должен быть тип

kuzmin_m13:04:06

и мультиметод

kuzmin_m13:04:19

который выбирает реализацию по этому типу

kuzmin_m13:04:01

я не вдавался

ilevd13:04:07

Ну да, и ничего страшного бы не было, как мне кажется

kuzmin_m13:04:09

но там что-то про мэпы и мультиметоды

kuzmin_m13:04:28

ну это же эквивалентные подюходы)

kuzmin_m13:04:35

просто рекорды быстрее

ilevd13:04:07

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

kuzmin_m13:04:52

по факту мультиметод один фиг - интерфейс так же как и протокол

ilevd13:04:07

А так пишешь, все на обычных, мэпах, потом встречается где-нибудь протоколы/defrecord/multimethod что ты не используешь, ступоришься, читаешь, делаешь, через месяц забываешь, через месяц опять с этим сталкиваешь и т д

kuzmin_m13:04:52

если сделать рекорд без полей

(defrecord Foo [])
то можно мэпу эмулировать
(-> (->Foo) (asssoc :foo/bar 1))

kuzmin_m13:04:02

но с поддержкой протоколов

ilevd13:04:38

Я бы с case сделал, как @artemyarulin пример показывал)

kuzmin_m13:04:02

В кложе есть протоколы. И я рад этому. Это очень крутая штука. Она позволяет решить проблему. Если у вас есть объекты, то вы можете легко добавлять новые типы, но вам сложно добавлять новые функции, если у вас есть структуры данных, то вам тяжело добавлять новые типы, но  легко добавлять новые функции.
Тут понятия объект и структура данных концептуальные. В java все оъект, но с помощью java объектов можно моделировать структуры данных(struct).
Протоколы позволяют легко добавлять новые типы и новые функции, т.к. можно расширить тип протоколом, а можно протокол типом.

ilevd13:04:36

Дак зачем это все?

kuzmin_m13:04:41

т.е. что бы добаввить новый тип, нужно переписать ВСЕ функции

artemyarulin13:04:13

это старая проблема (как там называется кто помнит?)

kuzmin_m13:04:19

но что бы добавить новую функцию, ничего переделывать ненадо

kuzmin_m13:04:26

я тоже не понмню

kuzmin_m13:04:31

вот протоколы ее решают

kuzmin_m13:04:34

эту проблему

artemyarulin13:04:35

но вопрос то - что чаще добавляется функции или новые типы?

kuzmin_m13:04:39

и мультиметоды

kuzmin_m13:04:55

и то и то) как бизнес скажет

kuzmin_m13:04:54

т.е. фишка протоколов не нужно менять существующий код при добавлении новой функциональности в виде новых типов ИЛИ новых функций

artemyarulin13:04:37

да неа, вот же у тебя

(defrecord User [name]
  CalcSalary
  (calc-salary [_] 0))
Если ты добавишь новый тип Boss то ничего менять не надо. Если ты добавишь новую функцию CalcHolidays тебе надо будет обойти все типы

kuzmin_m13:04:25

есть extend-protocol

kuzmin_m13:04:39

в моем случае да

kuzmin_m13:04:43

нужно поменять

artemyarulin13:04:06

Expression problem

artemyarulin13:04:09

The idea is that your program is a combination of a datatype and operations over it. The problem asks for an implementation that allows to add new cases of the type and new operations without the need for recompilation of the old modules and keeping static type safety(no casts or runtime type checks).

It's interesting to notice that in functional programming languages it's easy to add new operations, but hard to add cases to the datatype. While in an OO language it's the other way round. This is one of the big conceptual differences between the two programming paradigms.

kuzmin_m13:04:17

т.е. тип отдельно протоколо отдельно реализация отдельно

misha13:04:16

ну такие себе примеры

artemyarulin13:04:23

http://stackoverflow.com/questions/3596366/what-is-the-expression-problem ггг, в коментах 3 ответа как решается оно на кложе и один на хаскеле 🙂

misha13:04:57

особенно постоянно утрамбовывать мапы в рекорды, чтобы поддержать протоколы. ты типа “логику” нигде не будешь менять, зато сантехнику по всему проекту будешь обновлять

misha13:04:20

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

artemyarulin13:04:13

Whereas in functional languages, it's easy to add new operations but difficult to add new types:
по мне дак (на моих проектах, они все разные да) типы обычно в начале более менее известны и редко добавляются в процессе. Т.у. меня мейл клиент, у меня есть message/contact и еще пачка. А вот функционала добавляется чем дальше тем больше для этих “типов”

misha13:04:30

но я, конечно, всё еще жду какой-нибудь супер туториал от Рича и тусовки по протоколам, чтобы осенило наконец-то

artemyarulin13:04:34

ну и спека кладется на мапы легче да

artemyarulin14:04:19

чота мне кажется код легче читать

misha14:04:31

смотря, наверное, сколько его

artemyarulin14:04:09

думаешь если кода много то диаграмма из него будет внезапно маленькой?:)

misha14:04:51

нет, но, непосредственно в этом примере, – смотри как перелинкованы спеки между собой

misha14:04:15

просто жпеги - это дичь, нужен html, в котором по наведению выделяются/затемняются куски релевантные

misha14:04:14

я так либу и не дописал, чтобы можно было всякое такое “оживлять“: спеки, схемы датомиков, мапы, аст всякие, etc.

misha14:04:11

если кто вместо меня сделает - будет збс kappa

savelichalex14:04:43

ну graphviz вон в свг могет, так что выглядит не сложно это http://www.graphviz.org/doc/info/output.html

misha14:04:04

ну он же шевелиться не будет?

savelichalex14:04:34

в svg также можно стили переназначить

savelichalex14:04:43

ховеры всякие делать

misha14:04:45

типа там он-клики всякие, хаверы, динамическое редактирование

misha14:04:39

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

artemyarulin14:04:36

… а продумать все чотко чтоб космический корабль мог туда влезть! “лучше идеально и никогда, чем кое-как и когда-нибудь“(с) troll

artemyarulin14:04:10

хотя честно сказать я похожее тоже хотел сделать

misha14:04:10

ну я пару подходов к снаряду сделал уже

artemyarulin14:04:25

не знал что graphiz умеет svg, круто

misha14:04:58

а кое-как - это вон в js поищи - там этого г хватает

savelichalex14:04:04

так вот у graphviz как раз таки апи продуманное)

misha15:04:34

тоже на графвизе

artemyarulin16:04:40

оопешненько

kuzmin_m16:04:34

я никак не найду презентацию Льва Валкина у него там слайд был ФП надо сравнивать с императивным а OOP и DSL строятся поверх ФП или императивщины только в ФП DSL часть больше , чем в императивном

ilevd16:04:30

Я как раз перед этим про mount читал - понравилось, в следующем приложении его, наверное, буду использовать. Попроще и много оберточного кода не надо писать, как в компоненте.

kuzmin_m16:04:00

маунт только про управлением стейта

ilevd16:04:08

Ну там это вручную делается

ilevd17:04:34

https://github.com/tolitius/mount/blob/master/dev/clj/app/www.clj вот здесь conn внедряется в nyse-app

ilevd17:04:43

По идеи дальше можно как в подходе с компонентом сделать middleware для routes чтобы явно не ссылаться в обработчиках запросов

ilevd17:04:34

Коду поменьше получается чем с компонентом

kuzmin_m17:04:31

смотря что ты делаешь

kuzmin_m17:04:54

если это хобби проект, то посмотри одну релализацию, другую

kuzmin_m17:04:05

посмотри ссылки, которые я привел в тексте

just.sultanov18:04:49

после java мне тоже в начале хотелось везде вставлять рекорды, протоколы etc... по-тихоньку вроде отпускает 🙂

just.sultanov18:04:43

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

kuzmin_m18:04:08

я никогда не писал на java я 5 лет пишу на ruby есть набор проблем, который помогает решать SOLID и паттерны оно обкатано, разобрано, проверено понятно, что есть те, кто любят переусложнять и не понимают принципы @just.sultanov можешь дать ссылку на что-то похожее по авторитетности для решиния проблем? я ничего другого не видел. Может быть есть пример больших приложений на clojure, где люди сталкивались со сложностями и успешно их решали? тот же автор компонента работает в когнитект, наверное это о чем то говорит

just.sultanov18:04:47

@kuzmin_m я бы сам с радостью получить такие ссылки 🙂

just.sultanov18:04:07

приходится по крупицам собирать инфу там сям

kuzmin_m18:04:50

просто мне доставляют подобные комментарии есть неявная критика, а предложения решения нет

kuzmin_m18:04:20

из того чем я могу поделиться

kuzmin_m18:04:45

https://cleancoders.com/videos я наконец-то понял SOLID

kuzmin_m18:04:56

что это, нафига и как что дает

kuzmin_m18:04:21

интересно, кто-нибудь смотрел эти видео?

kuzmin_m18:04:57

есть еще какая-то метода, котороя показывает как строить приложнеия легко изменяемыми?

savelichalex18:04:48

хм, а тут наоборот не оч о SOLID отзывается автор http://www.yegor256.com/2017/03/28/solid.html

kuzmin_m18:04:49

да, дядя Боб зарабатывает на видео и книжках

kuzmin_m18:04:13

ок, возьмем пределение S - single resoponsibility

kuzmin_m18:04:27

автор не так его понимает

kuzmin_m18:04:45

судя по Мартину это про роли на проекте

kuzmin_m18:04:04

изменения должны исходить от одной роли

kuzmin_m18:04:22

если это шлюз к базе, то изменения исходят тольок от DBA

kuzmin_m18:04:47

если это изменения методики расчета зп - то это от бухгалтера

kuzmin_m18:04:10

изменения стиля отчета - от дизайнера

kuzmin_m18:04:17

и все это разные комопоненты

artemyarulin18:04:00

я вот после кложы сходил в мир хаскеля и понял что много проблем из-за того что все IO кидают где не попадя, т.е. даже из примера

(defn foo [config queue db-conn arg1] 
  ...use config, queue, db-conn... )
(defn bar [config queue db-conn arg1 arg2] 
  ...use config, queue, db-conn... )
2 функции еще ок, можно и явно ж передать конекшен. А если их 200 то явно компонент не решение проблемы, она в другом

andmed18:04:05

@savelichalex Егор (по ссылке) тролль знатный.

kuzmin_m18:04:34

к нам Николай Рыжиков в пятницу на конфу приедет будет как раз рассказывать про архитектуру 😃

kuzmin_m18:04:47

поедет кто в Ульяновск на стачку?

mike_ananev18:04:57

@ilevd я один раз использовал component. потом пересел на mount и не разу не пожалел.

kuzmin_m18:04:56

@mike1452 а просто для сравнения, какие были проблемы на компоненте?

nicola19:04:29

В четверг в 10 хэнгаут

dottedmag19:04:17

Егор256 пургу какую-то пишет. Боб придумал хорошую аббревиатуру для того, что по частям было раскидано.

dottedmag19:04:29

Переименовал? Ну и ладно. Зато SOLID'но 😄

dottedmag19:04:16

Про Open/Closed Principle его претензия вообще не по адресу.

andmed19:04:39

@dottedmag да он сам признался на последнем jpoint. так и так, каждый сам видит свою роль. моя - провоцировать обсуждение. мол процесс лучше идет ))

misha19:04:58

что-то сегодня джавы в чятике™ больше, чем за прошлый месяц

andmed19:04:36

извини, не хотел обидеть

kuzmin_m19:04:13

@dottedmag может разберем SOLID? мне интересно закрепить свое понимание, может что-то новое узнаю

dottedmag19:04:30

А чего там разбирать? Егор написал норм, если откинуть претензии 🙂

dottedmag19:04:43

S - делайте связные внутри себя куски кода. O - делайте расширяемый код, который не нужно править. L - если у вас есть субтипы, то пользуйтесь ими по делу. I - не валите в кучу несвязанные функции. D - не надо зависеть от конкретных деталей, надо зависеть от интерфейсов.

kuzmin_m19:04:13

S - не совсем

kuzmin_m19:04:21

там идея от ролей

kuzmin_m19:04:43

есть роли, которые могут требовать изменения

mike_ananev19:04:52

@kuzmin_m component буквально заставляет делать так представлено в презентации или документации - делаем рекорды, стартуем system. В общем это микрофреймворк с запахом ООП. Везде где будет стейт он обязывает заворачивать в компонент по всему приложению. если часть приложения не в компоненте, то будут проблемы. то есть использовать или нет компонент крайне желательно до начала кода. mount на мой вкус больше clojure way. разрешение зависимостей и старт производится средствами самого clojure. потом в mount мне очень нравится reload функциональность, частичный старт системы. с mount у меня функции с 2мя видами arity. если например при вызове функции первым не указан db, то берется по умолчанию db текущего неймспейса под управлением mount. если при вызове функции db указано, то используется оный.

mike_ananev19:04:10

короче проще с mount и нет навязывания как в компоненте.

kuzmin_m19:04:12

@mike1452 главное, что бы жить было проще) если mount подошел - почему нет 😃

kuzmin_m19:04:25

And this gets to the crux of the Single Responsibility Principle. This principle is about people.

mike_ananev19:04:31

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

dottedmag19:04:51

@kuzmin_m Вот более полезная формулировка: "Gather together the things that change for the same reasons. Separate those things that change for different reasons."

mike_ananev19:04:52

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

mike_ananev19:04:10

этот стейт собственно только и нужен был этим функциям. однажды было что пробрасывал на 1 или 2 уровня вверх. но это максимум

mike_ananev19:04:17

все-таки на С надо запретить писать сервисы и приложения. на этом языке сколько не пиши, одни дыры. тот же postfix будь он исполняемый на JVM и написан в стиле data driven подхода, сколько бы потенциальных дыр удалось избежать. А на С что ни парсер, то потенциальная дыра

misha19:04:01

запрети kappa

mike_ananev19:04:57

понятно дело что не запретишь )))

mike_ananev19:04:51

просто С очень не безопасный код. кто пишет на нем должен быть очень аккуратным и кучу вещей в голове держать.

andmed19:04:32

а вот prepor из решетки автозека в защиту C не побоялся выступить (ссылка проскакивала)

andmed19:04:36

ага, он в какой-то момент отвечает уклончиво на наезд на С, порадовало помню

mike_ananev19:04:31

по моему он как раз наоборот там рассуждает про ошибки из-за этого самого стейта.

andmed19:04:57

в целом да, конкретно по С и про запретить писать -- нет

andmed19:04:38

а это во второй серии https://youtu.be/6Lx4vFovGbw?t=3m23s " - с нахер, - нет.. тем не менее.."

andmed20:04:00

формат зачетный, формат класс просто

dottedmag20:04:57

Sun JVM тоже на C написан

andmed20:04:06

плюсах, ну да

andmed20:04:21

kernel все железки...

andmed20:04:33

вот говоряд embedded java есть.. я не встречал

dottedmag20:04:46

Что-то эксплоиты для древнего говна только.

misha20:04:53

на чипованой твоей дебетной карте жава эмбедед

misha20:04:30

найти не могу пруф

andmed20:04:59

да, я встпомнил, была такая тема

misha20:04:33

https://en.wikipedia.org/wiki/Java_Card https://en.wikipedia.org/wiki/Smart_card Java Card refers to a software technology that allows Java-based applications (applets) to be run securely on smart cards and similar small memory footprint devices

misha20:04:26

на сим картах, получается, тоже жава может быть

mike_ananev20:04:07

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

andmed20:04:58

С -- завораживающий мир undefined behavior

mike_ananev20:04:15

да, точно"

rmuslimov21:04:20

кстати обсуждение про компонент будет неполным если не рассказать вот про эту штуку: https://github.com/weavejester/reloaded.repl в комбинации с danielz/system и хоткеем получается рабочий релоад с минимальный кол-вом действий