Fork me on GitHub
#hoplon
<
2016-02-27
>
levitanong03:02:56

@numberq: server errors also happen if your server isn't running properly. Have you tried a REPL and evaluated your whole API? Usually that tells me that my database initialization went wrong.

thedavidmeister11:02:34

if I have (defc foo 1) is there any way to get at the foo cell inside a cell=, or can i only get at the value 1?

dm312:02:26

not that I know of. Why would you want to do that?

dm312:02:40

cell= derefs the cells used inside

dm312:02:59

you can have nested cells though

dm312:02:29

although it then becomes very hard to reason about the program (and easy to have memory leaks)

thedavidmeister12:02:53

because i have a datascript connection as a cell

thedavidmeister12:02:20

and i want to pass the connection around rather than use a global connection or pass the db

dm312:02:00

having cells kind of presumes that you have a root cell somewhere with the value that gets set there

dm312:02:37

so for a cell-based API I'd expect to have a cell with the value of the db

thedavidmeister12:02:46

that’s what i did

thedavidmeister12:02:57

that’s what the problem is

dm312:02:05

why is it a problem?

thedavidmeister12:02:14

because if the value of the cell is the db

thedavidmeister12:02:19

that means the cell is the connection

thedavidmeister12:02:34

so if i want to work with the connection, i can’t just have the db value

thedavidmeister12:02:07

like, if i want to do (d/transact! conn tx)

dm312:02:16

you want to do that inside the cell?

dm312:02:27

cell that reacts by transacting?

dm312:02:49

I have conn a separate variable, actually a Mount defstate

thedavidmeister12:02:59

well no, i’m not doing that atm

thedavidmeister12:02:10

but i am running queries against it

dm312:02:10

then I have a root cell that is set to :db-after value on every transaction

thedavidmeister12:02:28

i wanted to have a consistent usage of conn throughout the functions i wrote to wrap my queries

thedavidmeister12:02:55

rather than passing a db for reads and a conn for writes

thedavidmeister12:02:59

that seemed weird to me

dm312:02:09

I wouldn't pass anything

dm312:02:29

just have one var with a conn and a cell with a db in a db namespace

dm312:02:42

then say (db/transact! datoms)

thedavidmeister12:02:17

but if i pass the conn around, i can easily write tests

thedavidmeister12:02:44

and make a bunch of different conns on the fly during the tests

dm312:02:21

you can also do with-redefs in clojurescript I think

dm312:02:55

I mean you can probably do it your way, only it doesn't really play well with the concept of cells

thedavidmeister12:02:56

yeah, i have some complicated logic resulting in a transact! but the actual transaction is pretty simple

thedavidmeister12:02:15

so i have a test where I pass in the situation(s) that would result in a transact

thedavidmeister12:02:48

then compare the conn after the change, to a fresh db using with to get at the end-state

thedavidmeister12:02:26

i might try just wrapping the conn cell in another cell, for usage in cell=

thedavidmeister12:02:35

hopefully that doesn’t break everything

dm312:02:07

(with-redefs [db/db (cell (test-db))
             db/conn (new-conn)]
     (logic!)
     (is (= @db/db (db/with (test-db) ...)))
something like that?

dm312:02:32

only nicely wrapped into some helper function

dm312:02:16

I'd have to do it like that if I wrote any tests simple_smile

thedavidmeister12:02:40

haha, i like to refactor

thedavidmeister12:02:42

so i write tests

dm312:02:48

I like to refactor

dm312:02:50

so I don't simple_smile

dm312:02:18

(I do write tests for scary parts though)

thedavidmeister12:02:34

i’m always surprised by what i manage to break

thedavidmeister12:02:43

especially when I’m sure I won’t break anything

thedavidmeister12:02:36

the only reason I picked up on this issue that I’m now asking about is because of a test i wrote 😛

thedavidmeister12:02:56

@dm3 maybe it’s not so bad to do db for reads and conn for writes

thedavidmeister12:02:40

i think the point you make about transact! inside cell= is pretty much right

thedavidmeister12:02:50

i do want to keep the functions that work on conn and db only working with the arguments they take

thedavidmeister12:02:24

i can already see that i might want two or more different dbs to track the state of different things

thedavidmeister12:02:00

so if i do that, i might also want functions that can operate equally well on the different dbs

dm312:02:45

I find that the best structure is when you have ns'es that encapsulate your state and logic fully from the views

dm312:02:26

so you have you defelems and whatever which make calls to users/..., orders/.. both for queries and for "transactions"

dm312:02:29

(ns cart.view
   (require [cart.state :as cart]))

(defelem cart [...]
   (div :click #(cart/remove! @%)
       (text "~cart/status")))
something like that

thedavidmeister12:02:45

yeah, i’m slowly working towards that

thedavidmeister12:02:47

i think i might need one state that persists and one that doesn't

thedavidmeister12:02:58

for tracking things like “keys pressed"

dm312:02:39

you can have that as cells in the view ns

dm312:02:43

or locally to the element

dm312:02:14

I have a bunch of states managing different concerns, some of them in datascript db, some in cells

dm312:02:40

very easy to reason about if all of the logic is contained in a single ns

thedavidmeister12:02:11

i’ll try it out

thedavidmeister12:02:37

but i suspect it will be good to have a “state that persists” which is basically the user’s data

thedavidmeister12:02:54

and “state that tracks transient things” which is the user’s input

thedavidmeister12:02:18

which would actually be bad to accidentally persist

thedavidmeister12:02:09

@dm3 i got inspired by the select-id cell from the other night 😉

thedavidmeister12:02:34

i want to take this (and (not @id) (which-key/pressed? :backspace %)) (reset! select-id (-> @state:sorted last first)) from the keyup

thedavidmeister12:02:55

and turn it into something that just uses the information about what was pressed from an existing cell

thedavidmeister12:02:06

but I don’t want to put too much in the one PR >.<

thedavidmeister13:02:13

but yeah… it helped me write some tests that i hadn’t figured out how to write previously

thedavidmeister13:02:41

i didn’t know how to easily get at selected text, or the cursor position in selenium

thedavidmeister13:02:53

but writing tests against the value of a cell is easy simple_smile

thedavidmeister13:02:07

what are Om and Reagent like

thedavidmeister13:02:10

have you used them?

dm313:02:36

yes, they're like biting your nails off when you need to integrate third party JS

dm313:02:16

also a lot of ceremony around component states

dm313:02:19

and lifecycles

dm313:02:43

Reagent seems simple but you have to know there are 3 (!) forms of components that you can create

dm313:02:19

even though the difference is undiscoverable at first sight

dm313:02:47

the only tricky thing that Hoplon has is loop-tpl. React + Reagent/Om has dozens

dm313:02:19

(I mean tricky as in the effect of the code on DOM is hard to reason about without knowing the implementation details)

thedavidmeister13:02:33

considering i’m learning cljs as i go

thedavidmeister13:02:42

glad i chose the least complicated option

dm313:02:02

I think React is only needed if you're planning on using React Native

dm313:02:23

or you have a huge team and then React+Om.Next gives a nice UI + server architecture

dm313:02:28

out of the box

thedavidmeister13:02:36

i do not have a huge team

dm313:02:36

with Hoplon you have to kinda discover it yourself

thedavidmeister13:02:51

there is a lot of discovery going on, lol

thedavidmeister13:02:03

but not sure how much of that is me and how much is the framework

thedavidmeister13:02:02

what are the advantages of the different components in reagent?

dm313:02:27

not the advantages, you have to know that you need to use one way over the other in different contexts

dm313:02:45

like look at the last point: https://github.com/Day8/re-frame/wiki/Creating-Reagent-Components#appendix-a---lifting-the-lid-slightly and compare with what you get in Hoplon - a function that will create a DOM element. That's it.

thedavidmeister13:02:07

is Hiccup a templating language?

thedavidmeister13:02:01

wah, that refactor just took me 13 days to wrap up but fixed 4 tx, two of which i had no idea how to tackle otherwise, and paves the way for another 5 tx that i didn’t really know how to do either

thedavidmeister13:02:09

thanks again for helping me @dm3

dm313:02:31

no problem simple_smile

thedavidmeister13:02:47

i’ve been trying to show people hoplon

thedavidmeister13:02:56

but it’s really hard to explain to someone who doesn’t know any clj

alandipert13:02:19

@thedavidmeister: re: cell w/ db in it, have you considered using a lens?

alandipert13:02:49

it exists for the case when you want to export a cell value and also export a particular way of updating it, without exposing too much about what contributes to the cell value

thedavidmeister13:02:23

@alandipert: i haven’t looked at lenses yet

thedavidmeister13:02:07

i need to learn how they work first

alandipert13:02:20

hehe of course 😄

thedavidmeister13:02:43

if you think it’s worth looking at, i’ll set aside some time to investigate

dm313:02:49

I think in this case instead of transact! you'll be able to (reset! db txs)

alandipert13:02:17

right - the lens cell can have the db update logic inside it

alandipert13:02:33

@dm3: thanks for the kind words on HN

thedavidmeister13:02:51

hmm, so i could make a lens version of transact!?

thedavidmeister13:02:16

and just work with the db everywhere

thedavidmeister13:02:22

and not worry about the conn?

dm313:02:34

unless you need to listen! and such

thedavidmeister13:02:16

i could still listen to the conn if i referenced it directly?

thedavidmeister13:02:32

or once i make a lens-transact! i am stuck?

dm313:02:40

yes, the lens would only proxy the transact! call

alandipert13:02:52

the particular case that lenses address are situations like these

dm313:02:23

@alandipert - someone needs to promote the work simple_smile

thedavidmeister13:02:31

ok, from what i read, i might need listen to get the data into something like datomic later

alandipert13:02:41

(def root (cell {:x 123}))
(def num (cell= (root :x)))

(defn inc! [c]
  (swap! root update :x inc))

alandipert13:02:22

so imagine we created num because we only want to expose :x to some consumer, or component within our app

alandipert13:02:35

because the more about the structure of root we expose, the more coupled to it dependent cells become

alandipert13:02:46

so num is a "line in the sand" so to speak

thedavidmeister13:02:12

yeah, for me, num would be the query i’m running

alandipert13:02:40

so where num is this effort to narrow what's exposed to consumers, inc! stands in contrast

alandipert13:02:45

as it takes the root cell

alandipert13:02:09

so the way a component would view and a way it would update are not symmetrical

thedavidmeister13:02:25

that’s exactly what i ended up with

thedavidmeister13:02:48

but in datascript language it is conn for write and db + a query for reads

thedavidmeister13:02:21

i didn’t mean to do that, it just sort of happened

thedavidmeister13:02:26

i think it’s ok

thedavidmeister13:02:56

i only have one query and one loop-tpl atm

thedavidmeister13:02:03

so i’m kind of over-analysing 😛

thedavidmeister13:02:18

i’ll let you know if something comes up that i didn’t think of

alandipert13:02:32

it's really awesome what you're doing btw

alandipert13:02:43

i'm not aware of anyone going as far w/ the datomic ideas and cells

thedavidmeister13:02:35

haha, it’s only because i suck at clojure

thedavidmeister13:02:42

i think i’ll find it easier to deal with a db

thedavidmeister13:02:54

than mess around with raw clj data

alandipert13:02:07

that's still mindblowing though

alandipert13:02:13

building a reactive network of databases... in the browser?

alandipert13:02:33

i would also refute that you suck lol

thedavidmeister13:02:20

ok, well let’s say that clj is my least-good language >.<

alandipert13:02:50

@dm3: have you used reframe btw?

dm314:02:34

I also built something like re-frame with Om before that

dm314:02:39

but it sucked

dm314:02:26

and I now have a weird mix of Javelin-based state, Datascript and event-based sync with backend

dm314:02:40

in a Hoplon app

thedavidmeister14:02:16

what is the difference between "Reactive-Atom” and a cell?

thedavidmeister14:02:20

Hoplon gets mentioned a lot

thedavidmeister14:02:51

but I don’t understand the problem that Hoplon has that this is solving?

dm314:02:51

doesn't use React I think

dm314:02:07

and uses weird build tooling (boot) simple_smile

thedavidmeister14:02:09

so they picked a framework, and it made a problem

dm314:02:11

I think the implicit argument is that they "need to" use React for whatever reason

thedavidmeister14:02:23

and the framework “at it’s best” is close to Hoplon

thedavidmeister14:02:43

and the solution is… 20 pages of stuff

dm314:02:48

maybe they did hit a perf bottleneck with Hoplon at the time the re-frame was born

thedavidmeister14:02:11

and this diagram

thedavidmeister14:02:39

perf issues in Hoplon?

dm314:02:23

I haven't, but I've heard Colin Yates complain when he added ~20k things to his app (whatever those things were)

dm314:02:31

didn't work with Hoplon, worked with React

thedavidmeister14:02:17

i don’t think i’ll need 20k

thedavidmeister14:02:34

is there any low hanging fruit for perf in Hoplon

thedavidmeister14:02:40

or is it about as good as it will get?

thedavidmeister14:02:20

@alandipert: happy to make changes, but i’d need some guidance to go much further than i did on the PR

micha14:02:05

@thedavidmeister: i think there is a lot of opportunity for perf improvements

micha14:02:45

we haven't put much effort there so far

thedavidmeister14:02:26

@micha: ok cool, good to know simple_smile

micha14:02:33

have you run into anything?

micha14:02:47

like have you had to work around any performance issues?

thedavidmeister14:02:51

actually, i keep expecting to, but i don't

thedavidmeister14:02:04

i’ve had to work around race conditions that were really confusing me

micha14:02:12

haha yeah that's why we haven't spent much time on profiling

thedavidmeister14:02:14

but the solution was to just keep making things more abstract

thedavidmeister14:02:27

until i could no longer reproduce the issue

micha14:02:47

not having perf optimizations allows us to keep the code more high level

micha14:02:57

so it's easier to add features or change things

thedavidmeister14:02:20

i’m a big fan of knowing what you could optimise, but only optimising once you have a problem

micha14:02:35

the only perf optimizations i've really done is to remove little used features

micha14:02:45

that were part of the hot section

thedavidmeister14:02:54

perf stuff often makes things complicated and buggy

micha14:02:01

like keeping the number of things hoplon needs to do when the page loads to a minimum

micha14:02:07

yeah exactly

micha14:02:31

i think javelin is pretty much stable now, so that might be a place to look for perf

micha14:02:43

we haven't added or removed anything in over a year i believe

micha14:02:49

maybe more than that even

thedavidmeister14:02:54

that sounds pretty stable

thedavidmeister14:02:18

to the point where the repo kind of looks abandoned 😛

micha14:02:27

that's how we like it simple_smile

micha14:02:36

that means it's well factored

micha14:02:01

like i think the priority-map implementation could perhaps be shaved a bit for perf

micha14:02:17

that would speed up javelin, and hoplon would benefit from that

thedavidmeister14:02:38

yeah, that’s the way all projects probably should work

thedavidmeister14:02:41

but i gotta say it’s weird

micha14:02:34

i have a perf test harness for javelin i think

thedavidmeister14:02:40

ah, i found something to nitpick

thedavidmeister14:02:49

you could have a cache in your travis setup

thedavidmeister14:02:05

it would go like 10s faster

micha14:02:42

what's your github user?

micha14:02:55

i just sent a github invite

thedavidmeister14:02:39

i should put up a PR then simple_smile

thedavidmeister14:02:46

actually… it’s nearly 2am

micha14:02:07

talk to you later!

micha14:02:26

you should have access to push travis changes etc

thedavidmeister14:02:55

awesome, but i’ll still test on my account before i change anything

micha14:02:37

feel free to push changes to those repos, just things that add or change the api maybe should be done with community input

micha14:02:06

but like tests, CI, things like that, fire at will

thedavidmeister14:02:25

I do actually want to stick up a bunch of basic tests for hoplon

thedavidmeister14:02:38

like, just checking that all the elements actually render the right HTML

micha14:02:54

mynomoto made some tests i believe

thedavidmeister14:02:15

on a particular branch?

micha14:02:27

he devised the setup for doing the async tests etc

micha14:02:36

in a separate repo

thedavidmeister14:02:09

but then how do you review the tests before rolling a new release?

micha14:02:11

the cljs testing stuff has improved a lot since then

thedavidmeister14:02:14

you’d have to go back to the other repo each time

micha14:02:22

it was a proof of concept

micha14:02:45

might be useful to look at though

thedavidmeister14:02:16

yeah, i’ll look at it when i have time for sure

thedavidmeister14:02:03

it’s good to get in the habit of writing tests as you find/fix bugs, at the least

thedavidmeister14:02:22

even if you don’t go for comprehensive coverage, at least you know the stuff that tripped you up in the past won’t come back

micha15:02:06

yeah javelin has hundreds of tests

micha15:02:19

we haven't had any regressions that i can remember

thedavidmeister15:02:33

the way i see it, is writing 10 tests upstream saves 100 tests in my projects 😛

thedavidmeister15:02:44

and browser testing stuff is tougher than just asserting data out of functions

micha15:02:02

and the model is more open ended too

thedavidmeister15:02:12

so i’d like to know the browser stuff is rock solid from the framework, and i can just test my data in my project

micha15:02:21

javelin is all factored out, so it's easy to test it

thedavidmeister15:02:33

yeah, it’s the right approach for that

micha15:02:33

hoplon is a little more vague because there is setup involved

micha15:02:47

and setup phase uses the things you're testing

thedavidmeister15:02:18

i guess it depends what you’re testing

micha15:02:23

we can definitely do it tho

thedavidmeister15:02:39

making sure that (div) spits out a div and not a dov

thedavidmeister15:02:49

that we can lock down easy simple_smile

micha15:02:16

a macro could emit all of those tests, too

micha15:02:27

so we'd only need to maintain one test for all the elements

thedavidmeister15:02:41

that sounds cool

thedavidmeister15:02:45

you’ll have to show me how to do that

thedavidmeister15:02:24

i haven’t written my own macros yet 😉

thedavidmeister15:02:28

just been using regular functions

micha15:02:03

basically if you find yourself cutting and pasting code in the editor, a macro is an option

micha15:02:12

because macros generate code for you

thedavidmeister15:02:28

ah ok, i copy and paste data, but not code

thedavidmeister15:02:34

i usually refactor code

micha15:02:42

yeah like for tests:

micha15:02:21

(emit-primitive-tests div span a p ...)

micha15:02:36

that would expand into all the individual test clauses

thedavidmeister15:02:12

i often split my tests into 2 functions

thedavidmeister15:02:25

1 just holds all the setup and expected outcomes

micha15:02:26

yeah i think in this case you could use a funtion actually

thedavidmeister15:02:30

and the other does the “stuff"

micha15:02:00

because you need div as both a symbol (so you can read the name) and as a function

micha15:02:27

like if you had a function that would loop over the things and test them you'd need to do:

micha15:02:46

(test-primitives
  div 'div
  span 'span
  ...

micha15:02:56

which is still not bad

micha15:02:12

but a macro could do that for you

thedavidmeister15:02:32

most of the tests i’ve written were in PHP

thedavidmeister15:02:39

you probably don’t want to know how it works there 😉

micha15:02:12

oh i know, unfortunately

micha15:02:34

although i can't say we had too many tests for the 250K lines of PHP in that application

micha15:02:42

maybe 2 lol

micha15:02:10

i had to make my own repl

thedavidmeister15:02:14

you can just run your strings as functions

micha15:02:16

there was no php repl that worked

thedavidmeister15:02:30

aw, i use psysh at work

thedavidmeister15:02:33

it’s pretty good

thedavidmeister15:02:39

not sure how old it is though

micha15:02:01

when i looked around none of them could handle global variables correctly

micha15:02:17

because they all evaluated code in a function context

micha15:02:36

because of the way they did the error catching

micha15:02:46

my repl works at the global context

micha15:02:58

the app i was working on had tons of global variables

micha15:02:05

and require() and so on

thedavidmeister15:02:42

thankfully, if you ever find yourself back in PHP world, there’s a lot less of that going on now, with PSR and composer being common

thedavidmeister15:02:52

and there are REPLs that work

micha15:02:10

i remember looking at the facebook repl

micha15:02:14

it was the worst

micha15:02:28

and i realized that facebook is populated by true php programmers

micha15:02:33

they don't use anything

micha15:02:43

it was the most naive thing ever

thedavidmeister15:02:42

then they went on to re-invent php7, before it was released

thedavidmeister15:02:53

fb do weird things sometimes

micha15:02:26

yeah i have not seen a single thing from them that isn't terrible

micha15:02:49

i can only imagine the environment their developers work in

thedavidmeister15:02:14

i had enough clients get mad at me over the years because fb silently dropped/changed/added/blocked something i was using...

thedavidmeister15:02:32

and their docs always are wrong/missing

micha15:02:58

they remind me of like the "chavs" i think they call them in england

thedavidmeister15:02:23

well, i barely get to write code at work any more

thedavidmeister15:02:29

and all my evening stuff is in cljs

thedavidmeister15:02:45

so i might be slowly kicking the PHP

micha15:02:43

lol meet the fb team

thedavidmeister15:02:54

on that note, i really have to leave

micha15:02:06

later dude!