This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-09-12
Channels
- # aleph (11)
- # aws-lambda (1)
- # beginners (158)
- # boot (19)
- # cider (14)
- # clara (23)
- # cljs-dev (3)
- # clojars (4)
- # clojure (133)
- # clojure-dev (57)
- # clojure-dusseldorf (1)
- # clojure-finland (2)
- # clojure-gamedev (31)
- # clojure-greece (15)
- # clojure-ireland (1)
- # clojure-italy (3)
- # clojure-russia (8)
- # clojure-spec (149)
- # clojure-uk (51)
- # clojurescript (88)
- # community-development (1)
- # component (5)
- # cursive (17)
- # datomic (3)
- # emacs (6)
- # fulcro (142)
- # graphql (1)
- # juxt (15)
- # lein-figwheel (1)
- # luminus (3)
- # lumo (6)
- # off-topic (11)
- # om (8)
- # onyx (5)
- # portkey (6)
- # proton (2)
- # protorepl (3)
- # quil (6)
- # re-frame (14)
- # reagent (9)
- # shadow-cljs (226)
- # specter (11)
- # testing (96)
- # uncomplicate (5)
- # unrepl (8)
- # vim (11)
So, I’ve had a few people recently ask about a lein template. I went ahead and made a bare-bones template for lein. It has no real features: just a full-stack app with as little as possible (easy server, stupid UI, one query, one mutation).
lein new fulcro boo
and i18n extract/generate from a Makefile…so, it is a decent starting point for a project, just with very limited code.
is there a way to return a field as ident in networking? Let's say I have a call that returns children of an element such as {:id 3 :name "Name" :parent 5}
. Since I already have the parent, I changed my network call implementation to modify the return to {:id 3 :name "Name" :parent [:meds-by-id 5]}
. Unfortunately this doesn't seem to work.
what I get is: :parent [[:meds-by-id :fulcro.client.impl.om-plumbing/not-found] [:meds-by-id :fulcro.client.impl.om-plumbing/not-found]]
@roklenarcic seems like quite a bit of extra complexity for speed boost 🙂 have you tried just returning :parent-id: 5
and updating the state in a post mutation ?
Of course I can do that.
@roklenarcic So, I see you continually trying to pre-normalize data before merge. This is never going to work. Normalization happens for you on returns. As @claudiu said, you can use a post mutation, but I think you’re still playing with recursion. You’re making your life quite a bit harder than it has to be, I think because load-field
won’t work for your case; however, load
will. Here’s the basic outline:
1. Recursive queries can’t use load-field
because the field is just ...
: E.g. (defui BulletItem static IQuery (query [this] [:id :checked :value {:subitems '...}]))
. A load-field
would end up sending the query [{:subitems '...}]
, which is lacking critical information. You can’t strip out the parent’s fields, because those are also the child’s fields.
2. Normalization does work for recursive queries. You just have to issue the right load to the server. The load you want is (load [:meds/by-id 5] Med {:params {:depth 1}})
or something similar. Make the server stop the recursion at the depth you desire for your initial load.
3. When you want to load the recursive elements, just use the same load, but with a deeper depth.
I think the issue is that many times I am aware of what ident I need at a certain spot in the tree, but then I need to construct and put denormalized data there, just to have om normalize it right after that
well for that example, when loading children of an element, I know who the parent id is.
but how do you know the client has it??? This is a distributed system. You’re asking for trouble if the server assumes things like that
because the children load is the result of clicking on the parent
therefore I know I have it
I know it's not completely kosher
but if you just re-issue a load on that parent (and tolerate the fact that you “refresh” a few bytes of data), it works seamlessly
as you could have someone issue that load without having the parent
unless you’re loading a boat-load of data for each med, in which case perhaps you need to normalize that “heavy” chunk into another component that can be normalized (and demand-loaded) separately.
well it results in 2 extra queries for each child clicked after that load
because the load-ancestors call loads all ancestors
even though I have them
I'll need to pass app
into my network, so I can look up state and see if I can skip loading some things
Again, why are you worried about not re-loading some things in your graph? How big are they?
small, but they create a noticable delay on the UI
you mean they disappear and reappear, or that your networking is 2g and is super slow?
I am on the same gigabit ethernet as my server and it's about 450ms on chrome network graph to do 3 trivial rest calls
1.5kb
total
and the query is select by ID
so I'm not sure, maybe server is too slow
and why can’t you just interface with the database and use a real api instead of REST?
I'll need to see how many queries I need to implement
not even sure why I would use for SQL
what*
it's just so many things to learn
I haven't even started with forms yet
Yes, it is a lot to learn. Using REST with it out of the gate makes it about 10x harder.
cause now you’re having to do a bunch of backflips to get things into the right shape in the middle of the entire plumbing
well I was trying to skip writing my own backend, when it's already written
and there's no guarantee that I won't have same problem with nested datastructures even without REST
so what do you use for SQL then
So, if your SQL schema is relatively sane, then fulcro-sql will do the graph queries for you
my fear with things that support 95% of cases is that I will have one case that is in the 5% and I'll have to change everything
@roklenarcic You’re covered there
fulcro-sql is a query interpreter that you call. If there is a case it doesn’t supports, then you hand-write the query
At my former job we were getting our data from a REST endpoint, but rather than trying to get a parser working directly with REST we broke the problem into two subproblems - 1 - downloading the data into a local database in a format that was easily queryable for Fulcro (pretty easy background jobs), 2 - building a Fulcro app on the happy path. I’d recommend trying that if you absolutely *need* the data to come from the REST endpoints (though sounds like you maybe don’t).
It's a hobby/sideproject that using existing data/services that I have at work
it's not a production thing, so I can't change things that are "real" services
I'm basically learning the stack while piggybacking on existing "ecosystem" so to speak
but I can write my own backend of course
I just thought I would use test instance of the one that is running in production
which is your usual spring boot+hibernate thing
you mean the hibernate+spring tech stack?
It's what everyone uses now in Java world
Spring + Hibernate + REST is more popular than Jesus right now
Hey I don't like it either, but gotta earn the money somehow
all the clojure jobs are in the states or London with a few berlin ones sprinkled in
I actually still like Java quite a bit…but man has that stack gotten hideously complex
People like it because it's easy (but complex)
You add one annotation like @EnableAuthorizationServer
and it automatically spawns like 20 beans that configure a bunch of OAuth2 things with smart defaults and connect your server to OAuth server and magically insert spring security filters into your REST servlets and configure them
of course if something goes wrong you are gonna be debugging for a week
Yep…then something goes wrong and you spend 20 days figuring out that you can’t fix it
exactly
well it's 150ms * 3
But yes I hate it, but all the management (also dev managers) love easy solutions, big frameworks, things they can put on Candidate Requirements, and they are all afraid of homebrew frameworks, they want something that you can find employees that know it
they deem anything not industry standard as a liability
Big companies with deep pockets can afford the overhead, and want “cogs” they can plug into seats.
but if you’re playing with Fulcro, then you’re interested in something different that has a promise of better: drink the entire cup of cool-aid and try it as designed 😉
exactly.. less ambitious employees love knowing Spring because that's what gets you hired, employers love Spring because that's what you can get people for
I'm the only one in this shop that is doing something else than Java, JS or Typescript
and i also do Rust
I'll have a look at that java backend to see how big it is
and I will probably try full stack fulcro
no reason not to, as I have unlimited time, so to speak
Every time I’ve looked at the kind of Java back-end you’re talking about, it is 9 parts complexity, and 1 part functionality.
there's a lot of things that are completely orthogonal to what you're trying to do
sadly this particular backend is one of the better ones, one of the larger apps here has DB Table inheritance model
Some genius said: Patient, Doctor, Nurse, Employee, User should all "extend" the same table with basic columns like first name and last name, so now any query involving those has additional joins (since each table also has *_versions table). Even many to many connector tables are versioned. Not only is that in conflict with Liskov's substitution principle, figuring out a doctor's name and his org. unit from his username is a 15 table join.
It is acutally, you just tell hibernate what you want and hibernate generates a 3 page SQL for you
easy and slow
I did a talk on Hibernate…about how it fails at every possible database operation you want
and "generated 3 page SQL" is not an exaggeration
funny thing is that 95% of these services never need ORM's change/dirty tracking, they just push what came in POST into DB
If anyone (you or lurkers) are interested, here are the slides: https://docs.google.com/presentation/d/1kp5a7uX0VQqNIGtD0AP1OwitNqKLHWWDEFqb2mxcs-s/edit?usp=sharing
you bet
schema: spread out all over classes…is that indexed? How does that FK relate? CRUD: fail fail fail fail The only thing it is “good for” is very simple single-class form input, but the setup to even get there is crazy
5 years ago I was using MyBatis, before I was forced to switch to full ORMs
Your real hard task in most databases is reporting, and it really really fails there. Everyone either hand-writes real SQL, or does the super-stupid thing and uses Hibernate to bring in a ton of objects into memory so they can hand-munge them.
I was ok with MyBatis, it had some templating and help for commas and opening and closing parenthesis and for snippets, otherwise you wrote your own queries so you knew what was executing when, and it had resultset -> object or map mapping, which was useful
I heard good things about jooq
I have to look into it someday
one thing that hibernate does address that is useful is hibernate dialects, it makes it easy to port to different databases. When you are selling a product rather than running your own production stack it becomes important to be able to run on multiple DB vendors
That sounds right, until you realize how limiting that is. Now your reporting must be done strictly via Hibernate HQL and in-memory joins. I guess if you’re willing to take that cost…but really, is it that hard to have a much simpler API to provide that isolation layer?
I always write my database stuff as a very thin injectable layer. There aren’t that many SQL databases that real people use. From a market-analysis standpoint in business, I’d imagine covering MySQL, PostgreSQL, MSSQL, and Oracle would get you 99%
The new lein template doesn't work out of the box for me. Here's what I get when running lein deps: rkwofford@rkwofford-W840SU-Series:~/code/rkw$ lein deps Could not find artifact org.clojure:clojurescript:jar:1.9.915 in central (https://repo1.maven.org/maven2/) Could not find artifact org.clojure:clojurescript:jar:1.9.915 in clojars (https://clojars.org/repo/) This could be due to a typo in :dependencies or network issues. If you are behind a proxy, try setting the 'http_proxy' environment variable.
oh shoot…my bad, that was prob a local build I made, which would work for me, but isn’t on clojars 😜
looking at the server side... does anyone have an example of a boot build?
Looking at your lein template tony, :cljsbuild
only has one build defined, production. Is this OK?
oh right, cljsbuild is defined further down for dev
gotta say this lein template is so much more impressive than anything I've done build-wise