Fork me on GitHub
#re-frame
<
2019-01-04
>
caleb.macdonaldblack00:01:13

What are peoples strategies for making dynamic app-db paths reusable? I have a path like this: [:app/local-storage :app/users 001 :app/devices 002 :device/some-key] After refactoring it I've broken a whole lot of my app. To avoid this in future, anything that alters (events) any level of that path takes a customised rf/path interceptor, and anything that queries (sub) any level takes a number of different input signals for each level. Prior to this change, each event and sub repeatedly reconstructed the path. Other options I've considered are a function that takes the dynamic segments, builds and returns the path. Also while all this makes my production less fragile to path changes, my tests are still very fragile because the datastructures are hardcoded into them. This leads me to think that perhaps the structure of app-db should be well thought out in advanced to avoid structure changes just as a relational database would. So maybe the solution is not investing too much time into allowing it to change (implementing input-signals, path functions/interceptors) but thinking ahead to prevent it changing in the first place. Thoughts?

caleb.macdonaldblack00:01:46

So should I accept that app-db structure changes are unavoidably painful or is there an awesome solution I haven't thought of?

rutledgepaulv02:01:56

do you have a validator on your db? so you get errors as soon as something appears in it with unexpected structure? That’s recommended here: https://github.com/Day8/re-frame/blob/master/docs/ApplicationState.md#create-a-leveragable-schema

caleb.macdonaldblack02:01:33

@rutledgepaulv I know it existed but I always felt there was more overhead in managing that spec than time spent debugging those problems

caleb.macdonaldblack02:01:39

For example after that refactor I spent very little time debugging problems as my failing unit tests were giving me all the information I needed.

caleb.macdonaldblack02:01:47

What are your experiences specing the app-db? Would you recommend it? Do you think it's worth the overhead? I've never actually tried it on a real project so it's hard to make a comparison

rutledgepaulv02:01:53

I took a slightly different approach than spec with an interceptor.. I just define a schema and attach a validator to the db atom

rutledgepaulv02:01:56

(set-validator! db/app-db (let [original @db/app-db] (fn [db] (if-not (identical? original db) (boolean (s/validate common/AppDBSchema db)) true))))

rutledgepaulv02:01:04

I’ve found it helpful while building my project.. helps me detect when I’ve failed to update something somewhere

rutledgepaulv02:01:12

but my app db isn’t huge yet

rutledgepaulv02:01:30

though I’d guess maybe the value increases the larger it gets? It gives me confidence I wouldn’t otherwise have

caleb.macdonaldblack02:01:32

That's a good solution over the interceptor I think. I wouldn't have to pass interceptors into events or wrap the reg-event-* functions

rutledgepaulv02:01:51

right. it lowered the barrier for me a little

rutledgepaulv02:01:06

though I guess wrapping a function shouldn’t be a big deal either 😛

caleb.macdonaldblack02:01:28

And it look a lot cheaper to implement than interceptors too.

caleb.macdonaldblack02:01:01

Do you run it in production or just development?

caleb.macdonaldblack02:01:30

It's probably just a log right? Does it throw errors or anything?

rutledgepaulv02:01:39

as written that throws

rutledgepaulv02:01:54

for now, both. but it’s not performance sensitive since it’s an internal admin app

rutledgepaulv02:01:05

certainly wouldn’t be hard to toggle behind a flag

rutledgepaulv02:01:10

or to only log

rutledgepaulv02:01:32

but i like the peace of mind the hard errors offer

caleb.macdonaldblack02:01:55

Yea nothing unexpected that way

rutledgepaulv03:01:00

yep. you can use the schemas for more than leaf validation too - like enforcing invariants across sections of the db

caleb.macdonaldblack03:01:45

I'm not familiar with the terminology you just used. When you say "leaf validation" are you talking about simple validation on single attributes in the tree? And when you say "enforcing invariants across sections of the db" is that cross checking/validation of multiple attributes?

rutledgepaulv03:01:26

yep exactly. like if you have a collection of things that point at something in another section of the db - you could encode that as a constraint in the schema and so receive errors / warnings when your db breaches that contract

caleb.macdonaldblack03:01:52

Ah okay nice. And yea that is really handy. I'm going to spec my db with your approach as it seems like a lot less overhead that interceptors.

rutledgepaulv03:01:28

good luck! in case it wasn’t clear - that bit about checking identity in the snippet I pasted was just to avoid the validator throwing when it’s attached since i was running that at the top level before the db has been initialized

rutledgepaulv03:01:49

otherwise you’d have to specify that a valid state of your db is also {}

victorb13:01:24

hello reframers! I'm using reframe10x, wondering if there is a way I can avoid the debug window to appear by itself?

victorb14:01:11

ah, a little snippet magic of localStorage.setItem("day8.re-frame-10x.show-panel","\"false\"") in the index.html before loading re-frame solves the issue

Jacob Haag15:01:11

I am trying to do some computation with two subscriptions in which I pass two parameters too but I can't seem to get the syntax. Any ideas?

kaosko19:01:05

if value-db-path is already a vector you just need to (conj value-db-path :value)

WhoNeedszZz22:01:11

Still waiting on a response to this.

lilactown23:01:58

@whoneedszzz I would suggest creating a github issue

WhoNeedszZz23:01:57

Wait, why did you delete the link?

WhoNeedszZz23:01:50

In any case I'm not a fan of creating issues without suggesting actual code to support the issue. I was simply asking if it would be possible because I don't know 10x's code and if it would be possible then I would try to create a PR for it when I'm not swamped unless someone else was also interested in the same (which it appears so from the issue you had linked). The issue you linked and the one linked from there talk about different approaches that don't save any time or effort than what I'm currently doing of popping it out and having to close it between each reload.

WhoNeedszZz23:01:59

I'm suggesting adding a button next to the pop out button that simply collapses it like a Material-UI drawer

lilactown23:01:50

I deleted it because it was a link to an issue that wasn’t actually related to what you’re asking 🙂

WhoNeedszZz23:01:57

Well it is actually

WhoNeedszZz23:01:13

It's the same issue, but different approach to solving it

WhoNeedszZz23:01:32

It's especially frustrating on mobile

WhoNeedszZz23:01:43

That a drawer would solve very well

WhoNeedszZz23:01:21

I don't think hiding it by default is a good idea as that tends to lead to forgetting about its existence