google-cloud

Google Cloud Platform: Clojure + {GAE, GCE, anything else on Google Platform}
qqq 2017-01-29T15:51:56.000534Z

anyone here half tempted to ditch clj/gae and use hy/python/gae ?

claudiu_03 2017-01-29T20:06:12.000535Z

@qqq have you tried setting up the env like this http://lambda-startup.com/developing-clojure-on-app-engine/ ?

2017-01-29T20:09:58.000537Z

@qqq just curious, is boot-gae unsatisfactory in some way?

qqq 2017-01-29T20:18:47.000538Z

@claudiu_03 : Yes, I actually have something setup based on that exact page.

qqq 2017-01-29T20:19:05.000539Z

@mobileink : I think boot-gae is pretty damn optimal given the choice of using clojure on jvm

qqq 2017-01-29T20:19:59.000540Z

but (1) Hy is really nice, (2) I want server side to be dumb, so I don't need full power of Clojure, (3) Hy/python doesn't require JVM warm start / keeping a server around at all times [if I want to avoid the JVM loadup + clojure class loading penalty]

2017-01-29T20:25:08.000541Z

yeah, startup time is an issue on gae/java, esp. when the clojure runtime is involved.

2017-01-29T20:26:35.000542Z

Hy looks interesting. Hats off to the dev - competing with Rich Hickey takes brass cohones.

2017-01-29T20:29:06.000543Z

myself, i haven't worked with python enuff to have a clue. people at work like it (data scientist types). the other day i mentioned i did dth in clojure and one of them actually said "I don't like all those parentheses." my heart sank.

2017-01-29T20:30:18.000544Z

curious again: why do you want the server side to be dumb? how dumb? statuc pages dumb?

2017-01-29T20:31:08.000545Z

i'm actually leaning in the other direction - move the processing off my mobile and into the cloud.

claudiu_03 2017-01-29T20:32:03.000546Z

@mobileink python is really really nice, but clojure is really something else.

claudiu_03 2017-01-29T20:32:59.000547Z

I am switching from python to clojure 🙂 (although python still has it's uses for scripting, fast startup time)

2017-01-29T20:33:01.000548Z

@qqq how big of a deal is it for you that we do not have nice clojure wrappers over gae services?

claudiu_03 2017-01-29T20:33:56.000549Z

Found this yesturday https://shaunlebron.github.io/parinfer/ exactly like python, focus on indent and it will take care of the parentheses 🙂

2017-01-29T20:34:51.000550Z

@claudiu_03 you can say that again. i just have to figure out how to convey this msg to my pythonista colleagues without frightening them. 😉

claudiu_03 2017-01-29T20:36:58.000551Z

it's a hard sell for clojure vs python. The biggest selling point for me was clojurescript. The fact that I can reuse the code between backend & frontend.

2017-01-29T20:38:37.000552Z

@claudiu_03 parinfer looks useful. i'm an emacs guy, have tried several similar packages. in fact, i think getting people to even consider switching tools (editors) may even be a bigger issue than language. i know i would never even think of switching from emacs.😬

2017-01-29T20:39:36.000553Z

yeah, cljs is awesome! core.async too, but that's a little arcane.

2017-01-29T20:41:47.000554Z

nowadays i'm adding boot as a major factor. nothing else even comes close - and I've tried just about everything else. absolutely no comparison. it's the kilker app for clojure.

claudiu_03 2017-01-29T20:43:10.000556Z

@mobileink haven't tried boot yet, still to new sticking to lein since most tutorials are with it

claudiu_03 2017-01-29T20:43:30.000557Z

https://shaunlebron.github.io/parinfer/#editor-plugins

claudiu_03 2017-01-29T20:43:46.000558Z

it's not a editor, just a nice plugin. I use it with neovim

2017-01-29T20:44:51.000559Z

luv lein, cut my clojure teeth on it, but boot is in a different league altogether. the boot channel is very helpful, fwiw.

claudiu_03 2017-01-29T20:45:55.000561Z

I feel your pain. I'm tried at my current workplace. We're rebuilding the website, and tried to sell clojurescript for frontend but no luck 😞

claudiu_03 2017-01-29T20:47:16.000562Z

think people are just way to attached to the skills they learned (js, webpack, etc..) and don't really want to start from scratch all over again.

2017-01-29T20:51:00.000563Z

i've had some success getting mindshare at work by writing some boot tasklibs (like boot-gae) that look magical. you can do stuff with boot that just ain't gonna happen with other tools, at least not nearly as fast. easy to support java too. pyrhon i'm not so sure about but why not?

2017-01-29T20:53:02.000564Z

i'm actually toying with the idea of a boot tasklib for C projects. having recently suffered thru the ordeal of dealing with Scons (which is python) i think there is a real opportunity there.

claudiu_03 2017-01-29T20:55:03.000565Z

sounds really nice, really curious about boot now. Will definitely take a close look after I get my head around om.next 🙂

qqq 2017-01-29T20:57:14.000566Z

@mobileink (1) I'm already heavily invested in Hy. I want to use Tensorflow/Numpy, which Java has no match for. Therefore, all my data analysis / machine learning / AI code is written in Hy. This also means almost all of my Google Compute Engine (for heavy data science work) is all written in Hy as well. (2) I want "GAE Handler" to be dumb -- as dumb as possible. It should be stateless, it should (a) take a client request, (b) check if the client has permission, and (c) do the right thins to datastore / task queue and (d) return to the client. There should be nothing complicated going on here. (3) Given how heavily I'm already invested in Hy, and how much nicer GAE-Python is than GAE-JVM-Clojure, it seems like a obvious choice. (4) -- If I did not have to already use Hy for data analysis -- I'd stick with pure clojure. But I already have to use Hy, and I like it.

2017-01-29T20:58:23.000567Z

@claudiu_03: one thing to keep in mind: boot is not a build system. it would be more accurate to call it a Job Control Language - that's right, JCL, done right. Old mainframers like me will understand. :simple_smile:

2017-01-29T21:03:56.000568Z

@qqq so your number crunching hy/python is on Compute Engine, and you're thinking about GAE as a front-end of some kind?

qqq 2017-01-29T21:05:01.000571Z

front-end is in clojurescript/re-frame -- most of the "smart" logic" is there -- GAE is literrally meant to be a dumbass "security checker" which decides whether the client has the right to update the database in a certain way

qqq 2017-01-29T21:05:16.000572Z

I think this is also more secure -- complicated server side code scares me -- I want server side to be as short and simple as possible

2017-01-29T21:09:49.000573Z

i guess you could use clojuescript/node on Google Cloud, but i don't think that's (yet) possible on GAE Standard Env.

qqq 2017-01-29T21:10:33.000574Z

I think you're in the mindset of "use clj/cljs everywhere" whereas I'm in the mindset of "I'm already using Hy for all my data anslysi; the incremental cost of using it for gae is very small, especially given how small I expct my gae code to be"

2017-01-29T21:11:24.000575Z

well, sth lispy, anyway. :simple_smile:

qqq 2017-01-29T21:11:41.000576Z

what does sth stand for? I see you using it all the time, but I'm also guessing at the word

2017-01-29T21:12:30.000577Z

sorry, sth = something, sb = somebody. comes from lexicography.

qqq 2017-01-29T21:12:58.000578Z

I should setup those up as emacs abbrevs

qqq 2017-01-29T21:13:15.000579Z

I'm currently naming all my file names in such a way that helm can uniquely identify them within 3 keystrokes

qqq 2017-01-29T21:13:26.000580Z

that's my main criteron for "what to name this file/function"

2017-01-29T21:13:30.000581Z

you madman!

2017-01-29T21:14:10.000582Z

or madwoman. qqq doesn't say. 😉

2017-01-29T21:14:22.000583Z

madsth!

qqq 2017-01-29T21:14:45.000584Z

madman

2017-01-29T21:15:45.000585Z

i gave up on emacs customization years ago after i realized that was all i was doing.

qqq 2017-01-29T21:19:16.000586Z

I'm betting full emacs. I have C-8 = helm auto ocmplete on all the .org files I have (3 key strokes to pick), then when I pick a .org file, it fires up helm-auto complete on the subheadings of the file, thus C-8 three-keystrokes ENTER three-keystrokes = reaches any section of any file I care about

qqq 2017-01-29T21:19:28.000587Z

C-8 three-keystrokes ENTER three-keystrokes ENTER sorry, forgot the 2nd enter

2017-01-29T21:20:16.000588Z

i repeat: you madman! luv it.

2017-01-29T21:21:28.000589Z

anyway, sounds like you want an ultra lightweight frontend etc. clojure on gae, maybe not the best choice. sth in aws might be more optimal

qqq 2017-01-29T21:22:28.000590Z

(1) gae datastore, with entity groups, and transactions, I think beats Aurora/SQL, DhynamoDB, and SimpleDB (2) gae tooling just seems so much better than AWS. I tried AWS everything seems laggy as heck, gae -- even when i get errors is snappy and prompt with what I'm doing wrong.

2017-01-29T21:23:29.000591Z

problem is i could not possibly keep all that emacs stuff in my head. i have my 15 favorite keystrokes, after thst, stack overflow.

qqq 2017-01-29T21:24:06.000592Z

with helm/hydra, you don't have to -- it displays all possible completions and narrows it as you type

2017-01-29T21:24:11.000593Z

re aws, intersting. i've never used it in anger.

qqq 2017-01-29T21:24:20.000594Z

I tried setting up aurora, was a huge pain.

2017-01-29T21:25:15.000597Z

gae datastore is awesome. the native java api is daunting. but it's just a big map!

qqq 2017-01-29T21:25:35.000598Z

I think it's just "server side datastcript / datomic"

qqq 2017-01-29T21:25:46.000599Z

you have entity - attribute - value

qqq 2017-01-29T21:25:49.000600Z

then you have indexes over it

qqq 2017-01-29T21:25:58.000601Z

it's bascially the datascript model

2017-01-29T21:28:32.000602Z

i've only briefly looked at datascript, but it looks to me like datastore is actually much simpler.

2017-01-29T21:30:35.000603Z

it's almost a perfect fit for clojure. entities are just maps with a distinguished key. so the whole shmear can be presented in pure clj. no "defentity" needed.

qqq 2017-01-29T21:38:31.000604Z

but now, how do we query things? to ahve efficient queries, we want indexes so we don't have to linearly scan all entries -- and datascript/datomic/datastore basically use the same model

qqq 2017-01-29T21:38:45.000605Z

I deeply suspect (having not done this myself) one can get the same query langauge to work for both datascript & datastore

2017-01-29T21:45:22.000606Z

i'd have to study datascript/datamic some more, but i suspect you're right. one major diif: there is only one datastore, no creation of databases, no "conn", etc. just keys to a map.

qqq 2017-01-29T21:46:28.000607Z

I spent sometime working through https://github.com/halgari/odin -- where tim baldridge walks the user through creating a basic logic langauge, then implementing a "datomic light" (basically none of the server / persistence) -- just the data model / index / query language

qqq 2017-01-29T21:46:36.000609Z

after that, all three of these sorta look the same

2017-01-29T21:46:43.000610Z

i'm thinking the db id in datascript/datomic would just map to an ancestor key in ds.

2017-01-29T21:47:20.000611Z

a database is just a map under a key, iow.

2017-01-29T21:52:39.000612Z

odin looks interesting. but i do not think we need special db dsls or query languages. everything we need is already there in clojure.

qqq 2017-01-29T21:53:21.000613Z

I agree. The argument is not "we need a custom special db dsl" -- the sidepoint was "sometime ago, I studied odin ;; and after doing that, all three of dbs look really similar when I squint."

qqq 2017-01-29T21:53:34.000614Z

It was just fasicnating seeing how stuff gets implemented under the hood.

2017-01-29T21:53:43.000615Z

true!

2017-01-29T21:55:23.000616Z

the thing is, the only diff between a clj map (for example) and a map in a db is a couple of operations: save, and fetch.

2017-01-29T21:58:00.000617Z

in migae.datastore i tranlate this into 2 ctors: entity-map! and entity-map*. they're both ctors even tho we may not normally think of them like that. the "!" ctor constructs and saves. the "*" fetches and constructs.

2017-01-29T22:00:20.000620Z

think of a query as a constructor.

2017-01-29T22:00:35.000621Z

or a co-constructor.

2017-01-29T22:03:37.000622Z

iow, operations like "get" and "save" are bogus.

2017-01-29T22:04:18.000623Z

they are implementation details leaking into the language.

2017-01-29T22:07:48.000624Z

or look at it like this: (let [m {:foo 1].. ) involves an implicit "save" - save to memory. we don't make that explicit here, why should we need to make it explicit if we're saving to a db instead of memory?

2017-01-29T22:08:06.000625Z

you got me going, you madman.

qqq 2017-01-29T22:08:50.000627Z

sorry, slack is distracting, was afk coding

qqq 2017-01-29T22:08:52.000628Z

reading msgs now

2017-01-29T22:10:37.000629Z

no prob, i actually called off the coding a few hrs ago when i got clojure/alexa/gae working. i am now enjoying a beverage at the corner bar. hey, it's sunday here!

qqq 2017-01-29T22:11:33.000631Z

hang on, let me read through https://github.com/migae/datastore/search?p=2&q=defn+entity-map%5C%21&type=Code&utf8=%E2%9C%93 a bit to see how this entity-map magic works

qqq 2017-01-29T22:12:39.000635Z

hmm, looks like you ahve a entity-map! for each type

2017-01-29T22:14:23.000636Z

what do you mean "for each type". only one entity-map, just like hash-map: an implemenation of map.

qqq 2017-01-29T22:15:22.000637Z

@mobileink : in your docs, "constructor == smaller pieces -> bigger piece", "co-constructor == big piece --> smaller pieces" ?

2017-01-29T22:16:12.000638Z

oh crap, i'm going to have to read my docs.

qqq 2017-01-29T22:18:34.000641Z

okay, the examples are clear

qqq 2017-01-29T22:18:48.000642Z

I know what you mean by co-constructors, Haskell defines them automatically when you have constructors w/ named fields

2017-01-29T22:18:55.000643Z

think ctor. when you do e.g (def m {:foo 3}) you construct a map, on the surface. but behind the curtain clj ctors a hashmap, or whatever, in memory.

qqq 2017-01-29T22:18:59.000644Z

theyr'e sorta like "selectors" or "projections" <-- what you're referring to as co-constructor

qqq 2017-01-29T22:19:48.000645Z

and keylinks == namespsaced keywords, keychain == path == list of namespaced keywords

qqq 2017-01-29T22:20:10.000646Z

dogtag is last elemen of keychain -- lol

2017-01-29T22:20:31.000647Z

and clj can move that stuff around, your code does not need to know, clj hides that.

qqq 2017-01-29T22:21:24.000648Z

question about gae, not boot-migae-datastore -- are datastore "kinds" really the same as "buckets" -- because basically, two objects of the same "kind" don't ahve to be similar at all, so really it's just some bag that we throw stuff into

qqq 2017-01-29T22:22:10.000649Z

(def em1 (entity-map! [:Foo] m)) ;; kind="Foo", id is autogenned.
(def em2 (entity-map! [:Foo] m)) ;; em1 and em2 have different key ids
(def em2 (entity-map! [:A/B :C/D :Foo] m)) ;; long keychains ok too
^^ this looks interesting, so entity-map! is auto-enning datastore ids -- this is useful!

2017-01-29T22:22:41.000650Z

so when you ctor an entity-map, similar, except we unavoidably must expoes the persistence. so we have a "push" ctor that constructs the clj thing but also saves it to ds. the pull ctor is dual: pull the thing from ds, then construct the clj thibgie.

qqq 2017-01-29T22:23:17.000651Z

(entity-map* [])        ;; fetch all entities
 (entity-map* [:A/B])    ;; fetch unique entity with key :A/B
 (entity-map* [:A])      ;; fetch all entities with kind :A
 (entity-map* [:A/B :C]) ;; fetch all entities with kind :C and ancestor :A/B
 (entity-map* :pfx [:A/B :C/D]) ;; fetch all entities with keychain prefix (i.e. ancestor) [:A/B :C/D]
^^ this for retrieval is interesting, it's almost like we're "dereferecing a path"

2017-01-29T22:23:32.000652Z

auto-enning?

qqq 2017-01-29T22:23:38.000653Z

auto genning

qqq 2017-01-29T22:23:47.000654Z

auto generating an id

2017-01-29T22:25:34.000655Z

yes, if you give an "improper" keychain (one whose last element is not a namespaced kw) to a ctor it will autogen.

2017-01-29T22:27:05.000656Z

re "kinds" - i think of them as tags. they have no type- or schema-related importance.

2017-01-29T22:31:58.000657Z

i rather like the syntax: (entity-map* <spec>) essentially means "fetch the zero or more ('*') ds entities described by <spec>, and construct the corresponding clj datum (entity-map) for each.

2017-01-29T22:32:37.000658Z

hence "pull ctor".

2017-01-29T22:33:49.000659Z

the multiple entity-map fns are just for convenience.

qqq 2017-01-29T22:35:15.000660Z

this is very nice for kv access

2017-01-29T22:35:19.000661Z

but i see there's an error in the last example you cited above.

qqq 2017-01-29T22:35:21.000662Z

is there a way to make this support querying?

qqq 2017-01-29T22:35:39.000663Z

because with indexes, I can ask questions like "give me all people with last name Turing"

2017-01-29T22:37:05.000664Z

(entity-map* :pfx [:A/B :C/D]) ;; fetch all entities with keychain prefix (i.e. ancestor) [:A/B :C/D]
this should fetch/co-ctor the unique entity with that keychain. oops!

2017-01-29T22:39:23.000665Z

re: queries: last time i worked on this i had lots of good ideas about query syntax, but i'll have to review to get back up to speed. the critical point: query is a bad concept in FP!

2017-01-29T22:41:13.000666Z

there are no "queries", only expressions and predicates. when's the last time you heard a logician talking about "queries"?!

2017-01-29T22:44:29.000668Z

that's why i say "pull ctor", when i could have said "query". actually "co-ctor" would prolly be better.

qqq 2017-01-29T22:45:05.000670Z

what do you mean? I consider prolog/datalog "very functional" lanuages

qqq 2017-01-29T22:45:15.000671Z

yet datalog is all about querying, and prolog search is sorta like queries

2017-01-29T22:48:08.000672Z

that's only because people feel comfortable with the concept "query". in logic there is no such thing. it's effectively a narketing slogan. not evil, but also not accurate.

qqq 2017-01-29T22:54:58.000674Z

if datalog is not a "query" language, what is datalog?

2017-01-29T22:59:52.000675Z

a "query" is really a predicate, and making/sending a "query" really means "satisfy this predicate, if you can".

2017-01-29T23:00:43.000676Z

i have only briefly looked at datalog, but i suspect it is a kind of logic language.

2017-01-29T23:02:44.000677Z

so that's the point of having push and pull ctors in migae/datastore. no queries, just predicates.

2017-01-29T23:04:36.000678Z

the notion of "query" presumably derives from natural language interactions, and that is prolly why is is so successful. think SQL. but we should not be held back by that.

2017-01-29T23:14:02.000679Z

in (traditional, and most modern) logic, there is no concept of asking a question. all you can do is assert statements.

2017-01-29T23:18:00.000680Z

so if you want to retrieve all ds entities with keychain [:Foo/bar], you don't ask a question, you make a claim: (def x (entity-map* [:Foo/bar]), which states a fact.

2017-01-29T23:20:52.000681Z

that is, "x denotes the list of entity-maps whose keychains are [:Foo/bar]".

2017-01-29T23:21:37.000682Z

it's up to the implementation to make the claim true.

2017-01-29T23:22:20.000683Z

which could mean null.

qqq 2017-01-29T23:24:44.000684Z

I don't get it. How do you express something like find me all X where father(x) = abraham, mother(X) = safah?

2017-01-29T23:31:15.000685Z

well, logically (and mathematically), you never say "find all ...". you say sth like "let x denote all ...". so your example just describes a set. there is no "query" there, only a fact: X is in fact the kid whose father is Abe and whose mother is safah. the predicate may be u satisfiable, of course.

qqq 2017-01-29T23:32:23.000687Z

sure sure, say I'm writing a tree program, and I want to find all people whose father = Abraham, and Mother = Sarah

qqq 2017-01-29T23:32:32.000688Z

this isn't the type of thing I can pull of using just a key path

2017-01-29T23:32:37.000689Z

the point being that all this "get" stuff is an implementation detail

2017-01-29T23:34:54.000691Z

we cannot entirely avoid it, but we can avoid polluting our language with such detail, at least in principle. this is just what clj does by e. g. hiding the implementation of map.

2017-01-29T23:36:30.000692Z

ok, wait, dealing with a tree like that, and dealing with persistent storage are different ideas.

2017-01-29T23:42:29.000693Z

ok, you've motivated me. i need to spend some serious time thinking about how to explain this, because it is a fairly major departure from the usual way of thinking.

2017-01-29T23:44:07.000694Z

re: your example: [:Father/Abraham

2017-01-29T23:48:13.000695Z

crap, try again; do you mean amybody whose dad is Abe AND whose mother is Safah? or dad Abe OR mother Safah?

2017-01-29T23:49:35.000696Z

you can do this in various ways in gae ds, either using keys or fields.