This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-04-11
Channels
- # aleph (1)
- # architecture (18)
- # beginners (57)
- # boot (13)
- # cider (47)
- # cljs-dev (28)
- # cljsjs (13)
- # cljsrn (39)
- # clojure (258)
- # clojure-greece (16)
- # clojure-italy (2)
- # clojure-miami (1)
- # clojure-nl (9)
- # clojure-poland (15)
- # clojure-russia (369)
- # clojure-spec (53)
- # clojure-uk (49)
- # clojureremote (3)
- # clojurescript (135)
- # core-matrix (1)
- # cursive (11)
- # datascript (3)
- # datomic (4)
- # emacs (12)
- # figwheel (13)
- # hoplon (7)
- # interop (7)
- # jobs-discuss (33)
- # lumo (28)
- # off-topic (15)
- # om (7)
- # onyx (26)
- # pedestal (10)
- # perun (1)
- # planck (10)
- # re-frame (54)
- # reagent (16)
- # ring (5)
- # ring-swagger (50)
- # rum (2)
- # spacemacs (2)
- # unrepl (125)
- # untangled (12)
>И весь этот год я испытывал отвращение и не понимал идею stuartsierra/component. расскажи да, я все еще на этом этапе 🙂 Правда я на CLJS поэтому всякие db-connection у меня нету
компонент просто джавой очень пахнет, всё там понятно когда его использовать: есть сервисы, зависят от еще сервисов, общаются очередями, шарят пул соединений к базе/базам, нужно в одном очевидном месте это всё инициализировать, и с возможностью некоторые куски рестартовать без укладывания всего “монолита“. На джаве очень похожее на компонент писал, только не оформленное в библиотеку, а “инлайн“. Работает хорошо, но придя в кложу надеялся, что есть менее “корпоративный” что ли подход.
у меня впечатление от “компонента vs. самому на коленке” такие же как от “рефрейм vs. rum” – то ли юзкейса не было еще подходящего, то ли проект еще не достаточно огромный, то ли “инлайн” решения хватает. Это как джавах паттерны, потому что код к глаза не умещается, а в функциональных языках - просто функции.
@misha у тебя ж вроде CLJS + RN проект да?
в смысле бросил или пишешь на CLJC?
но как бэ компонент же -ортогонален этому всему - как только тебе нужно подружить кучу мелких блоков - так или иначе у тебя будет абзац/страница кода, который это всё инициализирует
переключался на подпроект на пару месяцев. сейчас перевожу что есть c cljs на cljc, читаю, че там понаписывал, более явно отделяю стейт/логику от вьюх
последние пару месяцев задумываюсь об ивент сорсинге и пытаюсь себе его продать, пока не особо получается
ха, я почти сразу начал писать свой RN на CLJC, тоже доставляет что не нужны эмуляторы/браузеры и репл шустрее на 10 миллисекунд работает 🙂
ну я на подпроекте чутка подраздуплился в repl-driven-development’е, (пришлось когда таба браузера начала захлебываться на 40-60к датомах жатаскрипта 🙂 ), и понял, что нужно и возможно логику в хорошем кложа-репле отдебажить, может даже спекой покрыть, а не бесконечно перелистывать десктопы с IDE на браузер и обратно, и дебажить принтами, потому что в курсиве кложаскрипт репл такой себе
сразу оно не особо очевидно. Сразу на всём стеке писать полезно, чтобы понять ограничения, узкие места, где и на сколько больно становится, чтобы потом легче выбор делать: "тут можно навалить, а тут лучше сразу отдельный репо как либу". прямо как премачур оптимизейшн, только не кода, а процесса
>пришлось когда таба браузера начала захлебываться на 40-60к датомах жатаскрипта “а теперь попытаемся со всем этим взлететить“(с) У тебя ифончик то не взорвется от напруги? 🙂
то было не для айфончика. но для айфончика в итоге у меня соизмеримые масштабы, но там сложнее базу наполнить сходу: больше работы по выпаршиванию из интернетов. зато для айфончика 2 позитивных момента:
1) пока я доберусь до прайвет беты даже - наверное уже 5ые айфона отомрут 2) датаскрипт я уже там сложил в отдельный javascriptcore процесс и нахлобучил кеш в основном javascriptcore процессе в виде {id entity} с синхронизацией, откуда вьюхи берут данные по цене хешмапы
про “захлебываться на 60к датомах” - это не про запросы/пулы. на тот момент мне надо было чистить и бекапить эту базу, и на каждое телодвижение нужно было упаковывать/распаковывать транзитом, еще и в файл класть. делать это табой браузера -
дойдут когда руки, хотел перфоманс тесты на датаскрипт на основе этого датасета написать: ветвистость данных в разумных пределах, и их достаточно много.
Под НГ я пил что-то крепкое с любителям хаскеля, и он мне сказал прямым текстом: что вот концепция exceptions (популярная в джаве, питоне, руби и много еще где) вообще не очень классная. И вообще является не composable и с ней сложно жить. Новый год закончился, я об этом как то забыл, хотя и поверил товарищу на слово. Вот собственно теперь когда у меня питоновское приложение покрылось кучей try-except на разных уровнях функций, превратилось и продолжается превращаться в сложно читаемое месиво, я бы хотел вернуться к этому вопросу и узнать если не exceptions то как? Дано: сложная stateful интеграция с travel провайдером с кучей последовательных вызовов и перехватами ошибок которые по различному перезапускают процесс. Сейчас это куча try-except на разных уровнях, и очень неудобно все это читать. Вопрос: как сделать если не вот этими try-except как выглядит haskell-way, clojure-way, whatever-way без try:except?
Страшное слово на букву M. Не очень страшное слово Promise (которая по сути монада)
ну или как в go https://blog.golang.org/error-handling-and-go
Без error as value точно не обойтись. А когда оно есть далее уже можно композить все это дело
ваат? Главный наезд на го как раз что ошибки просто значения и никакие не монады, т.е. композить ошибки ты никоим образом кроме как if err не можешь
ну т.е. если if считать как способ композиции, то да…. очень грубо говоря 🙂
У промиса есть then, что является монадическим bind
Promise.resolve(10) .then(do-a) .then(do-b) .then(do-c)
Вообще там просто
Left identity:
return a >>= f
≡
f a
Right identity:
m >>= return
≡
m
Associativity:
(m >>= f) >>= g
≡
m >>= (\x -> f x >>= g)
У нас в кложе активно используется Either, удобная штука
получается промис - частный случай респонса вида [result, error] в го, который если дополнительно оформить в тип с then’ами - получится монада?
дада, получится монада Either как раз 🙂
@roman01la а вы через какую либу типо котов или сами написали?
Своё. То же самое в сущности)
грустно что из коробки ничего такого в кложе нету, былоб круто
left, right, fmap, flat-map, on-realized вполне хватает для нормальной работы
@asolovyov когда понадобится что-то для зависимостей - я с него и начну. а он неявностью не сильно ограничивает? там были претензии к этому, и юрту написали.
а чем cljc лучше? есть что почитать?)
чем cljs
дак просто если например бизнесс логика тока, то поднимать RN, эмулятор да и просто даже браузер с фигвилом иногда лень. То круто просто заюзать CLJС заместо CLJS и юзать clojure-mode грубо говоря
хм, так поди cider проще юзать, да?
мне еще нравится что я могу синхронные HTTP реквесты кидать
(->> (io/http "")
parse-xml
do-a
do-b)
с CLJS (JS) такое не сделаешьну понятно что такое чисто в репле поиграться, в код оно не идет, но дебажится всякие парсинги диких JSON на ура
надо будет взять на заметку, спасибо)
в свое время мне очень хотелось такое в CLJS заполучить, чтоб в репле я мог эвалить такое в том числе, т.е. асинхронное вычесления поддерживать но чота не осилил как оно вообще работает там(
пытался такое в PureScript репле тоже сделать омг, в этом хаскеле коде не понял даже где начать 😄
Это для react native специфично? Или для браузера? Какой соотношение кода получается cljs к cljc?
неа, RN тут не особо причем думаю. Просто если если много бизнесс логики на клиенте и ее можно вынести в отдельный модуль то почему бы и нет. Хотя может и мобильные клиенты толще средних веб приложений где фронт тупой по большой части и все на беке. На мобильных часто бека нет и весь процессинг на девайсе
если все завязано не ре-фрейм то это не бизнесс логика как по мне, а чисто UI логика, там я думаю смысла нет. А вот если есть четкое разделение где бизнесс логика/парсинг может какой, энтити всякие и прочие расчеты то само то
Ну вот мое, но у меня тут монорепо с кучей всего
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
все от приложения зависит
@artemyarulin: clock.pl же
cloc да
он много чего покажет, а я не хочу вам говорить сколько у меня XML в моем могорепо 😛
@misha в разрезе reframe vs rum ты за rum?
@mike1452 да, даже если я себе ивент сорсинг продам - то не рефрейм, а, либо порт его на ром, либо что-то другое, возможно даже какого-то самописного выкидыша будет достаточно
я вот посмотрел презу Никиты по Rum и решил свой пет проект на Rum попробовать. Уж очень мне simplicty в Rum понравилась
меня пугает объем доков для рефрейма, который же вроде всего лишь ивент сорсинг кажется, что там уже далеко не только ивент сорсинг (а пересаживаться на фреймворк - не очень охота)
но я его не знаю: не читал, но осуждаю, кароче, особо не прислушивайся к моему мнению на этот счет
мне рефрейм напоминает редакс: вроде просто, но документация закидывает словами типа ко-эффекты и тд
я вот посмотрел на rum, и реагент мне кажется проще) там вообще ниче понимать не надо особо)
а в рефрейме просто доки разжеваны, так что тупой разберется)
но с другой стороны, если в приложении нет нужды применять разные походы к стейт-менеджменту компонента и реагентовскийй подходит, то easier здесь обретает хороший смысл
@savelichalex ту же еще зависит и от уровня юзера: джуниору с одного проще начать, поопытнее чуваку - с другого. потому кложе уже 10 лет, а средний стаж программера всё еще не меньше 10 лет. олдфаги сразу уловили весь кайф, и скила хватило перейти даже на сырую инфраструктуру. а молодым сложно
да дело то не в этом. я может просто не уловил плюсов rum-а, мне просто охота писать приложеньку, а не сидеть с либой разбираться. просто в reagent-е именно так и происходит, 5 минут доку прочитал и погнал делать
я бы лучше сказал практичный 😄
в rum секцию с примерами наглядней чуть сделать - тоже за 5 минут с нуля можно будет нахлобучивать
вопрос еще в том, знаешь ли ты когда упрешься в ограничения библиотеки, и упрёшься ли в них вообще?
я так далеко не заглядываю) так можно долго себя мучать вопросами о масштабируемости решения) вот упрусь тогда и подумаю, пока с лихвой хватает)
Я re-frame 3 дня читал, и так и не понял до конца с эффектами/коэффектами, зачем event handler делать pure? Только для тестирования?
@ilevd для композиции же!
просто после 7го рефрэйма понятно зачем коэффекты)
@savelichalex так а чо за коэффекты?
Ну там пример приводится, запрос делается и в event handler и там же subsribe на succes и error, что в этом плохого?
Я в разработке фронтенда еще не участовал. Опыта пока мало. Пока для себя сделал следующие выводы: 1) следуя идеологии clojure (где-то в презах было) что clojure простая, а runtime JavaScript - "доставляет". то есть он установлен на миллионах девайсов. Таким образом появилась возможность писать на "простой" clojure приложения в разных рантаймах. 2) По моим наблюдениям от деления фронт - бэк мы потихоньку движемся к равноправным приложениям на мобиле и сервере, которые обмениваются данными. То есть разработка полноценных приложений на фронте становится очень похожей на разработку толстых клиентов или RIA где надо стейтом управлять и куча асинхронных событий. 3) у clojure и clojurescript есть подходы, как управлять стейтом и как бороть асинхронность. 4) в Rum задействован подход управления стейтом на механизмах clojure. Или на простых атомах или в datascripte. 5) у реагента и ре-фрейма атомы свои, чуть-чуть подтюненные. более того ре-фрейм больше похож на фреймворк. Таким образом в начале разработки, потенциально я имею выигрыш на рефрейме. Но если приложения разрастется, то фиг знает, как оно там выйдет. Особенно если подтюненные атомы начнут глючить. Или фреймворк начнет накладывать ограничения.
@misha ну типа сайд эффекты всякие исполнять) просто раньше например это все в одних хэндлерах делалось, и ты к примеру делаешь запрос к серваку
(register-handler
:fetch-smth
(fn [db _]
(fetch ...)
db ;; <- вот тут нужно было обязательно вернуть
))
пока такие мысли
а теперь ты можешь нормально сделать хэндлер в котором сайд эффект вернешь и сможешь закомпозить если надо. хотя мне конечно пока ни разу не нужно было композить
@savelichalex кароче - еффекты - чистые хендлеры, коэффекты - хендлеры с сайдэффектами, так?
offtop: http://blog.timac.org/wp-content/post-images/Facebook87/GrandPerspective_small.png зацените в приложении ФБ RN js.bundle 12и метровый
ну типа того, просто чтобы хэндлеры были чистыми и можно было композить их
Коэффект - то что приходит в хендлер грязное, эффект - сайд эффект то что этот хендлер производит
это чтобы даже самому дятлу было понятно как юзать 🙂
@artemyarulin На фоне 136-мегового FBSharedFramework теряется как-то.
@misha Эффекты - это stateful действия, которые хэндлер порождает. Коэффект - это stateful-действие, результат которого требуется хэндлеру для работы.
что-то это противоречит тому, что @savelichalex одобрил 🙂
@misha В общем, эффект - это описание результата, а коэффект - описание аргументов.
@misha у тебя параноя 😄
так коэффекты/эффекты это монада или апликативный функтор? или ни то ни другое? 🙂
@savelichalex ты же уже на рефрейме нахлобучиваешь, пора было и разобраться
я просто из монад только maybe
и either
знаю, не силен я в этих вещах 😄
@savelichalex а можешь привести пример композиции эффектов и зачем это может быть надо?
@ilevd не, я же говорил, мне пока не пригодилось это) но так как просто мапа возвращается из функции, то считай можно ее менять потом как угодно
А там же эффект-handler зависит только от данных что вернет event-handler и только от этого? Можно сразу мапу поменять в event-handler, тогда
по поводу компонента я набросал страничку вводного текста, без этого будте сложно понимать дальнейшее там есть возможность оставлять комментарии https://docs.google.com/document/d/1oMt4vuAfM7PHGTBTm_pSsOkz-0RZbSdoOxNq5sqWnc0/edit
про компонент я напишу позже
>Для моделирования сущностей я применял map вида {:user/name “John”, :user-presentation/posts-count 3}. Проблема в том, что не понятно какого типа эта запись, что в ней, и никакого полиморфизма.
вот почти сразу - сам Ричи как раз говорил что типы не нужны ибо user как тип вещь статичная, а кложа динамичная и :user/name
может находится где угодно в 100500 разных мапах, поэтому спека описывает ключи аля :user/name
отдельно и если очень надо то отдельно мапу
если честно я в этих протоколах/reify/multimethod/interface полный нуб в кложе, один раз в жизни мультиметод заюзал и как-то все. >проникся протоколами, типами, reify, я на другой кложе пишу да 🙂
по поводу :user/name есть юзер, а есть админ по идее админ это тот же юзер и имя у него будет :user/name но у них разный алгоритм рассчета зарплаты или еще чего т.е. с точки зрения ооп мира удобно объявить протокол расчета ЗП и админ и юзер его реализуют, но по своему как это сделать не указывая тип в этой мэпе я не знаю
оно конечно кому как привычнее, я бы сделал просто явно
(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
берется, из самой мапы или откуда еще это уж дело вызывающего кодахм, а я всегда считал что чем меньше deftype
в кложе коде тем лучше, типа есть набор типов, с которыми хорошо работает стандартная библиотека и на них все строить. хотя иногда удобно конечно для полиморфизма
я б даже сделал вот так, чтоб даже асоциацию ключей и калькуляторов данными сделать
(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))
@artemyarulin
это рашение в стиле стуктур данных, я упомянал об этом в тексте
но как найти этот user-type?
ну прилетает в api запрос
дай зарплату пользователя, вот его id - :user/id
как дальше делать?
ну а каким магическим образом ты это сделаешь с рекодрами/мультиметодами? Где-то ассоциация то будет
покаж пример как ты бы сделал
(defprotocol CalcSalary
(calc-salary [_])
(defrecord User [name]
CalcSalary
(calc-salary [_] 0)) ;; работает бесплатно
(defrecord Admin [name]
CalcSalary
(calc-salary [_] 100500))
причем, если есть разбивка по слоям, то можно расшинить уже существующий тип протоколом
ну это понятно, ты ж грил что вот прилетает в апи запрос с :user/id
или у тебя будет прилетать типизированный user
?
ну у меня юзер тоже ничо не знает про зарплату, у меня собстно и юзера то нету
(def user (->User "John"))
(def admin (->Admin "Admin")
(def hander [id]
(let [user (get-user-by-id id)]
(calc-salary user)))
а мне больше другое интересно, вот у мапы есть куча методов, ну хотя бы тот же get
, если у тебя есть тип User
как у него выполнить эти методы?
появится еще тип пользователя просто добавляется тип и реализация протокола ничего остальное не меняется append-only программирование
@savelichalex там надо defrecord вместо deftype
так а что меняется?
Ну вот мой вариант
(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
и все в запроса все, ты в (get-user-by-id id)
это делаешь
как это работает :thinking_face:
ну в общем у меня явно все данные, у тебя через дефрекорды, понял ага
@artemyarulin (get-user-type - что там внутри?
дак я хз, ты ж сам сказал что приходит в запросе тока user-id. Может в базу надо будет сходить узнать тип юзера, может еще куда
дак а я не понимаю как ты то это решишь, вот тебе пришло такое-же в запросе как ты сырые данные к своим дефрекордам замапишь?
давай)
просто пример реализации, не факт, что в конкретной ситуации надо так делать и User и Admin сохраняются в одну таблицу в этой таблице есть поле тип когда мы по id достаем, мы смотрим тип и создаем правильный рекорд
ну да
не понимаю зафега мне дефрекорды в таком случае вообще ибо у меня оно явно везде юзается
а как работать с
{:user/name "super admin", :admin/rank 3, :superadmin/last-login ...}
я не понимаюдак ты его сам достаешь из базы
вот почти сразу - сам Ричи как раз говорил что типы не нужны ибо user как тип вещь статичная, а кложа динамичная и :user/name
может находится где угодно в 100500 разных мапах, поэтому спека описывает ключи аля :user/name
отдельно и если очень надо то отдельно мапу
(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 делает как раз этода блин 🙂
т.е. тебя дефрекорды защитят от такого запроса чтоле?
{:entity/type :superadmin, :user/name “super admin”, :admin/rank 3, :superadmin/last-login ... }
[:superadmin {:user/name "super admin" :admin/rank 3 :superadmin/last-login ...}]
а так уже не понятно?
ну дак я к этому и веду как раз
дак в любом случае будет где-то маппинг сырых данных к либо нужному defrecord либо просто будет каким-либо образом искаться явно тип юзера
ну дак понятно что мапа с типом это круто
еще б при компиляции оно проверялось и вааще ах
дада я к этому и веду что кложа динамична и в этом ничо плохого нету
в общем я считаю что это вопрос стиля, явно тип как данные или неявно в рекордах
В общем что бы понять компонент, нужно сначала понять рекорды, протоколы что бы его нормально испльзовать, нужно понять полиморфизм
а ну окей, мне тогда еще долго до него 😄
Хмм, я вот использую, и мне наоборот, если бы было без defrecord было бы удобней, наверное
ты про компонент?
А так пишешь, все на обычных, мэпах, потом встречается где-нибудь протоколы/defrecord/multimethod что ты не используешь, ступоришься, читаешь, делаешь, через месяц забываешь, через месяц опять с этим сталкиваешь и т д
если сделать рекорд без полей
(defrecord Foo [])
то можно мэпу эмулировать
(-> (->Foo) (asssoc :foo/bar 1))
Я бы с case сделал, как @artemyarulin пример показывал)
В кложе есть протоколы. И я рад этому. Это очень крутая штука. Она позволяет решить проблему. Если у вас есть объекты, то вы можете легко добавлять новые типы, но вам сложно добавлять новые функции, если у вас есть структуры данных, то вам тяжело добавлять новые типы, но легко добавлять новые функции.
Тут понятия объект и структура данных концептуальные. В java все оъект, но с помощью java объектов можно моделировать структуры данных(struct).
Протоколы позволяют легко добавлять новые типы и новые функции, т.к. можно расширить тип протоколом, а можно протокол типом.
это старая проблема (как там называется кто помнит?)
но вопрос то - что чаще добавляется функции или новые типы?
т.е. фишка протоколов не нужно менять существующий код при добавлении новой функциональности в виде новых типов ИЛИ новых функций
да неа, вот же у тебя
(defrecord User [name]
CalcSalary
(calc-salary [_] 0))
Если ты добавишь новый тип Boss то ничего менять не надо. Если ты добавишь новую функцию CalcHolidays тебе надо будет обойти все типыExpression problem
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.
http://stackoverflow.com/questions/3596366/what-is-the-expression-problem ггг, в коментах 3 ответа как решается оно на кложе и один на хаскеле 🙂
особенно постоянно утрамбовывать мапы в рекорды, чтобы поддержать протоколы. ты типа “логику” нигде не будешь менять, зато сантехнику по всему проекту будешь обновлять
если всё уже на мапах нахачено, и спекой покрыто, то можно вполне case или мультиметод. протоколы должны что-то более фундаментальное/абстрактное решать, их годно продумать сложнее, чтобы потом весь клей не переписывать на кажды коммит
Whereas in functional languages, it's easy to add new operations but difficult to add new types:
по мне дак (на моих проектах, они все разные да) типы обычно в начале более менее известны и редко добавляются в процессе. Т.у. меня мейл клиент, у меня есть message/contact и еще пачка. А вот функционала добавляется чем дальше тем больше для этих “типов”но я, конечно, всё еще жду какой-нибудь супер туториал от Рича и тусовки по протоколам, чтобы осенило наконец-то
ну и спека кладется на мапы легче да
чота мне кажется код легче читать
думаешь если кода много то диаграмма из него будет внезапно маленькой?:)
просто жпеги - это дичь, нужен html, в котором по наведению выделяются/затемняются куски релевантные
я так либу и не дописал, чтобы можно было всякое такое “оживлять“: спеки, схемы датомиков, мапы, аст всякие, etc.
ну graphviz вон в свг могет, так что выглядит не сложно это http://www.graphviz.org/doc/info/output.html
в svg также можно стили переназначить
ховеры всякие делать
я писал на реакте, с прицелом динамические диаграммы строить, чтобы их минимальным кол-вом телодвижений можно было условно в админку превращать. Но там очень чётенько нужно продумать модель данных, апи всякие, чтобы не получился клубок очередной, годный для 1граничного юзкейса какого-то
… а продумать все чотко чтоб космический корабль мог туда влезть! “лучше идеально и никогда, чем кое-как и когда-нибудь“(с)
хотя честно сказать я похожее тоже хотел сделать
не знал что graphiz умеет svg, круто
так вот у graphviz как раз таки апи продуманное)
@andrewboltachev @rmuslimov @razum2um @artemyarulin @misha дописал про компонент https://docs.google.com/document/d/1oMt4vuAfM7PHGTBTm_pSsOkz-0RZbSdoOxNq5sqWnc0/edit
оопешненько
я никак не найду презентацию Льва Валкина у него там слайд был ФП надо сравнивать с императивным а OOP и DSL строятся поверх ФП или императивщины только в ФП DSL часть больше , чем в императивном
Я как раз перед этим про mount читал - понравилось, в следующем приложении его, наверное, буду использовать. Попроще и много оберточного кода не надо писать, как в компоненте.
https://github.com/tolitius/mount/blob/master/dev/clj/app/www.clj вот здесь conn
внедряется в nyse-app
По идеи дальше можно как в подходе с компонентом сделать middleware для routes чтобы явно не ссылаться в обработчиках запросов
http://puredanger.github.io/tech.puredanger.com/2014/01/03/clojure-dependency-injection/
после java мне тоже в начале хотелось везде вставлять рекорды, протоколы etc... по-тихоньку вроде отпускает 🙂
скорее всего это из-за того, что пет проджекты маленькие и не сталкивался со сложностями
я никогда не писал на java я 5 лет пишу на ruby есть набор проблем, который помогает решать SOLID и паттерны оно обкатано, разобрано, проверено понятно, что есть те, кто любят переусложнять и не понимают принципы @just.sultanov можешь дать ссылку на что-то похожее по авторитетности для решиния проблем? я ничего другого не видел. Может быть есть пример больших приложений на clojure, где люди сталкивались со сложностями и успешно их решали? тот же автор компонента работает в когнитект, наверное это о чем то говорит
@kuzmin_m я бы сам с радостью получить такие ссылки 🙂
приходится по крупицам собирать инфу там сям
просто мне доставляют подобные комментарии есть неявная критика, а предложения решения нет
https://cleancoders.com/videos я наконец-то понял SOLID
есть еще какая-то метода, котороя показывает как строить приложнеия легко изменяемыми?
хм, а тут наоборот не оч о SOLID отзывается автор http://www.yegor256.com/2017/03/28/solid.html
я вот после кложы сходил в мир хаскеля и понял что много проблем из-за того что все 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 то явно компонент не решение проблемы, она в другом@savelichalex Егор (по ссылке) тролль знатный.
к нам Николай Рыжиков в пятницу на конфу приедет будет как раз рассказывать про архитектуру 😃
@ilevd я один раз использовал component. потом пересел на mount и не разу не пожалел.
Егор256 пургу какую-то пишет. Боб придумал хорошую аббревиатуру для того, что по частям было раскидано.
@dottedmag да он сам признался на последнем jpoint. так и так, каждый сам видит свою роль. моя - провоцировать обсуждение. мол процесс лучше идет ))
@dottedmag может разберем SOLID? мне интересно закрепить свое понимание, может что-то новое узнаю
S - делайте связные внутри себя куски кода. O - делайте расширяемый код, который не нужно править. L - если у вас есть субтипы, то пользуйтесь ими по делу. I - не валите в кучу несвязанные функции. D - не надо зависеть от конкретных деталей, надо зависеть от интерфейсов.
@kuzmin_m component буквально заставляет делать так представлено в презентации или документации - делаем рекорды, стартуем system. В общем это микрофреймворк с запахом ООП. Везде где будет стейт он обязывает заворачивать в компонент по всему приложению. если часть приложения не в компоненте, то будут проблемы. то есть использовать или нет компонент крайне желательно до начала кода. mount на мой вкус больше clojure way. разрешение зависимостей и старт производится средствами самого clojure. потом в mount мне очень нравится reload функциональность, частичный старт системы. с mount у меня функции с 2мя видами arity. если например при вызове функции первым не указан db, то берется по умолчанию db текущего неймспейса под управлением mount. если при вызове функции db указано, то используется оный.
короче проще с mount и нет навязывания как в компоненте.
@dottedmag https://8thlight.com/blog/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html
And this gets to the crux of the Single Responsibility Principle. This principle is about people.
да он подошел в разных приложениях. в общем я ни разу не сталкивался с ситуацией чтобы возвращаться к компоненту.
@kuzmin_m Вот более полезная формулировка: "Gather together the things that change for the same reasons. Separate those things that change for different reasons."
да и пробрасывать этот стейт не особо сильно надо было. то есть если у меня есть неймспейс для работы с базой и там лежат функции, в начале файла собственно стартует state под управлением mount.
этот стейт собственно только и нужен был этим функциям. однажды было что пробрасывал на 1 или 2 уровня вверх. но это максимум
все-таки на С надо запретить писать сервисы и приложения. на этом языке сколько не пиши, одни дыры. тот же postfix будь он исполняемый на JVM и написан в стиле data driven подхода, сколько бы потенциальных дыр удалось избежать. А на С что ни парсер, то потенциальная дыра
понятно дело что не запретишь )))
просто С очень не безопасный код. кто пишет на нем должен быть очень аккуратным и кучу вещей в голове держать.
а вот prepor из решетки автозека в защиту C не побоялся выступить (ссылка проскакивала)
по моему он как раз наоборот там рассуждает про ошибки из-за этого самого стейта.
а это во второй серии https://youtu.be/6Lx4vFovGbw?t=3m23s " - с нахер, - нет.. тем не менее.."
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
есть такой сайт, на котором соревнуются написать на С как можно невинный понятный код, но со скрытым смыслом
да, точно"
кстати обсуждение про компонент будет неполным если не рассказать вот про эту штуку: https://github.com/weavejester/reloaded.repl в комбинации с danielz/system и хоткеем получается рабочий релоад с минимальный кол-вом действий