Fork me on GitHub

Morning 🌞


How's it going?


I'm up late because my wife's flight from the East Coast is delayed... so I have to pick her up from SFO at 2:20am 😞


But it's been a fun weekend, helping folks on the Clojurians Slack, playing with Clojure stuff, listening to music I haven't heard in ages 🙂


And eating curry. Jay doesn't like curry, so I only get that when she's out of town.


This week I'll be working on the beginnings of a new Clojure web app to replace an old CFML app so that'll be nice.


What's on your schedule for the week @dominicm ?


I thought you seemed to be up quite late, that's very unfortunate! Sounds like a very relaxed weekend :). I'm hoping to be close to wrapping up my reporting export by the end of the week. And I'm going to try get my head around a new client's project so I can help out. I largely want an uneventful week after a busy week behind me.


@seancorfield I always assumed world singles was a monolith. Do you still many services in CFML?


We have three CFML apps: the main dating app, the admin internal app, and a small affiliate/partners dashboard app. We're about halfway through migrating our sites to the new Clojure REST API with a React.js/Redux front end (and Clojure apps for login, auth, billing, and the SEO Geo content for search engines).


We should be all migrated in another few months and then we can shut down the big CFML app. We are starting the admin rewrite now. We'll rewrite the affiliate dashboard as well, maybe this year, maybe next.


We've migrated nearly all our English-only sites to Clojure/React.js. We're working on our non-English sites now -- translations has been the delay...


(since the text is different from our old CFML apps so we need a lot of stuff re-translated)


Luckily, this round of migrations doesn't involve much work on the database side -- we're only migrating paid memberships to a new system (one of the new Clojure apps). Last time we did a big migration (2012) we migrated from SQL Server to an all-new schema on MySQL. That was... entertaining...


We're also in the process of writing a new chat/messaging back end system (in Clojure of course).


Lots to consider at once 😮. How do you handle translations from a high level? I've seen a few versions, and I've liked some far more than others.


For relatively short strings we have a table of locale / key-name / translation. For long-form text, we have another table that is indexed by site ID as well as locale and key-name (since each site might have different "page" text).


We have an admin that uses role-based permissions to allow translators to login and see all English translations and write access to just their locale to edit/add new translations.


Are the keys things like "homepage-welcome-text" or are they "Hello, ${name}"?


(although for initial rounds of translations, we often send out a spreadsheet of key-name, English, <insert other language> if that's what the translator wants instead)


We have names like "homepage-welcome" and the en_US version might be Hello, {1}! and the code will call (i18n/get-resource "homepage-welcome" "en_US") to get the string and then (i18n/format-string the-string [(:username member)]) to format it.


Although we have that integrated into Selmer so in an HTML template, we would have {% resource homepage-welcome @member.username %}


We also support Arabic so we have a whole bunch of logic to add RTL formatting to everything, which is an extra level of complexity.


I've always found naming the keys in a consistent way to be completely impossible. Keys tend to shift meaning over time.


Yeah, naming is hard. Here's a brief look at the translation admin app


aboutUs welcomeToHomepageName. I'm seeing an easy naming convention here 😄


Luckily we have staff that can read, write, and speak most of the languages we use so we can do a lot of the translation in-house 🙂


I've started taking the approach of using the english string as the key. I never have to name things again, and when the English string changes, it automatically creates a void for strings to be re-translated.


Morning beautiful people


For a bit of fun, here's the Arabic string that explains browser compatibility -- note the {1} for the actual target of the link which is passed as an argument.


Note that the text box switches to RTL for text entry in Arabic!


That's very cool.


@dominicm We track when translations are updated and we have a job that runs every night that sends a list of outdated translations to admins who have subscribed to that.


I've never thought about how HTML tags would be represented in a RTL scenario. Seems funny to see href as href instead of ferh when everything around it is RTL simple_smile


And in French;locale=fr_FR so you can see how everything swaps around.


(that's the current CFML version of the platform)


This is the new React.js/Redux app with Clojure REST API behind it


And, to link it back to something UK-specific 🙂


something about mixed latin & arabic alphabets makes me chuckle.


I feel very grateful that management let us bet on Clojure back in 2011 and we definitely feel we can make changes a lot faster now than with our old system -- and the resource usage seems to be much lower (and everything runs faster too).


Any particular reason you chose not to go down the Clojurescript route?


Well, we took a run at cljs for an internal project some years back... and the tooling was very fragile and awkward (and changing very fast). It wasn't ready for prime time. So when we started to plan for the new front end and look at hiring developers to build it, we took another look and it really still wasn't ready for what we needed to do -- both in terms of the size of the system, the (updated) tooling, and mostly in terms of actually hiring developers when looking at JS vs cljs.


To put it in perspective, we started the new front-end in September 2015.


cljs tooling (and cljs itself) has come a long way in the last two and a half years.


That's about how long I've been doing clojure 😮. Can confirm, clojurescript is a lot better to work with now. Although "size" isn't something I've needed to (or tried to) tackle particularly.


I can't remember when we'd tried cljs before... digging around in our BitBucket repo isn't helping me because we deleted all the cljs exploration stuff and I can't find a branch or tag that contains that particular project. Maybe it was 2013?


Or maybe 2014, based on the om-sente repo I just found in my personal GitHub account... I think we used some of that as the basis for our exploration internally. We were certainly using Om and Sente at first, then rewrote it to use Reagent.


There's definitely a sense at work that we might try cljs for a future SPA since our JS devs are interested in learning it (and one of them has been playing with Clojure for a while already).


Maybe when we replace the affiliate/partner dashboard, we'll use cljs for the SPA on the front end. Who knows.


Looks like I'll be heading out to the airport soon -- despite taking off over an hour late, the wife's flight is now scheduled to land only 30 mins late (just before 2am).


"soon" = "in about 30 mins" I think 🙂


@dominicm How's your clj / tools.deps stuff going? I see a few people are putting together uberjar-building things for the new CLI tools now.


@seancorfield depstar is interesting, because it takes a different approach to me, it's more like leiningen's uberjars. I think there's space to improve on lein's uberjars though, so I'm confident pack will is a better choice for most people. My real difficulty is figuring out what I want the API to look like.


Yeah, I was curious as to the multiple options offered by pack -- capsule and jcl -- and also why you needed to specify the deps.edn file to consume?


@seancorfield I initially did JCL, which is a more traditional java approach to nesting jars inside jars, then realised it was GPL, so quickly found an alternative. Capsule has some neat future possibilities, it's a trampoline (like lein), so you can specify things like default JVM opts ahead of time (so you can put the memory constraints) if you choose. It also supports caplets, which let you do neat things like fetching dependencies on startup from maven. You specify the deps.edn to consume because really all pack needs is a classpath, so the deps.edn file can be anywhere on your disk. It means I don't have to worry about the dependencies of pack colliding with that of the host project. I'll probably explore the idea of automatically picking it up from cwd at some point though.


Thanks for the insight and background. I haven't tried it yet, nor depstar. I'm still looking at what it would take to migrate us to the new deps.edn format at work (instead of the custom format we have)... and that's not as high on my list as several other things 🙂


I like the apparent simplicity of depstar but I don't have a sense for the real world practicality of either it or pack right now.


(I think it's kind of amazing that depstar is only 200 lines of Clojure)


depstar has to handle horrible things like file conflicts. Which pack avoids by using a classloader. It's two diverging philosophies - fiddle with classloaders, or try and merge files you find on the disk. I have a suspicion that LICENSE file dropping violates BSD-2 and APLv2, so I avoided it. @seancorfield pack had a lot of inspiration from our discussions previously, so you should find it quite suitable for you.


Each pack output rocks up at around ~150 loc too. I haven't got any shared code between outputs yet, so that's a good metric at this time 😮


a not so good morning from the train.... I am stuck in Delft at the moment....


Obviously for not-lambda, I pull in Capsule which is a java class file of some size. So relatively I guess it's big 🙂


@thomas hope your commute and day improve


@otfrom... I hope so as well, thank you.... I had to go back to the hague and I am now going by metro to rotterdam... talking about a convoluted journey.


How early is too early for a snack?


No, I meant 10pm the night before 😉


made it to work... yeah finally


Morning all


Hello All 🙂


Does anyone in here know how I might turn an instant back into a string-representation of a date..?


My Google-Fu is failing me...


Better still if anyone has the slightest clue how to go straight from Instant to


I may have to drop my database and re-work my insert code to use for the dates, but I expect that they will still come back out as Instants (as under the hood it is a java.sql.Timestamp), in which case I am still going to have to convert them in order to do calendar-maths on them...


(TLDR; if I can convert the instants that come out of the database to string-based date representations, then I can create representations that are good for calendar maths, of which I have a LOT, so Instant to string is the easiest route to what I need)


@maleghast is

=> (str (java.time.Instant/now))
not what you want?


It might be... Let me try...


Perfection! Thanks @sundarj - sometimes it's the obvious thing you just haven't tried...


no problemo 🙂


Yep, I am pretty sure that nails it... Basically the API I am working with communicates dates (in JSON) as strings yyyy-MM-dd. I have to make them into Instants to safely insert them in the database, but when they come out I want to do calendar maths on them, and that requires, so I needed a way to take the strings into that space do the maths and then get the new strings out for sending to the API.


Talk about headache!


Really helped me out there ^^ so thanks @sundarj


Of course now my app has just suddenly stopped working... 😞


@dominicm - Is there an obvious "answer" to a message like this from an Edge app:

java.lang.IllegalStateException: Attempting to call unbound fn: #'edge.noaa-ncdc/noaa-ncdc-stations-harvester-job


Ignore that @dominicm - Rainbow Parens to the rescue - I had moved an entire function inside another (defn ... ) sexp so that's what that was, but I could see visually that it was wrong, so all's well that ends well 🙂 Sorry to tag you on it, but I was wondering if it was a "known" Edge error... Just PBCaK... 😉


@maleghast I recommend parinfer for avoiding these bugs.


Parinfer? Is that an Emacs library that I can pull into my setup, or is it a Clojure thing..?


I already use an Emacs setup with Paredit set up, but it does not stop me from yanking and pasting in stupid ways.


Paredit is more powerful than what I use it for, I know that, but I just use it to have some powerful shortcuts and to make sure that whenever I open ( [ or { I get a closing one right away.


I will, thanks 🙂


There is an emacs thing btw


I like paredit and aggressive indent (along with rainbow-parens)


which looks like it does parinfer like things via other means