This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # aleph (1)
- # aws (3)
- # beginners (75)
- # boot (1)
- # bristol-clojurians (2)
- # clj-kondo (18)
- # cljs-dev (5)
- # cljsrn (10)
- # clojure (64)
- # clojure-dev (15)
- # clojure-europe (3)
- # clojure-india (2)
- # clojure-italy (9)
- # clojure-madison (1)
- # clojure-nl (9)
- # clojure-norway (9)
- # clojure-spec (11)
- # clojure-uk (206)
- # clojurescript (30)
- # copenhagen-clojurians (1)
- # data-science (1)
- # datascript (2)
- # datomic (27)
- # emacs (1)
- # events (1)
- # fulcro (12)
- # gorilla (1)
- # jobs (2)
- # kaocha (2)
- # leiningen (4)
- # lumo (7)
- # malli (1)
- # off-topic (2)
- # pathom (14)
- # pedestal (5)
- # quil (3)
- # re-frame (8)
- # reitit (3)
- # remote-jobs (16)
- # ring-swagger (1)
- # shadow-cljs (70)
- # tools-deps (7)
- # vim (5)
- # vrac (1)
Hey, it means you get to chat with me before I go to bed in California @dharrigan! 🙂
Well, only thing to report is that I'm looking to deploy clojure code into our live environment for the first time EVAR today
I'm hopeful that in a few years time, I'll look back at that codebase and think - ehhh? what was I thinking? Since I hope my skills/experience will have improved by then 🙂
I no longer remember our very first production deploy that included Clojure... 2011... Spring... Clojure 1.3 Alpha 7 or 8, embedded into our legacy apps. But we had a lot of other stuff going on that meant Clojure was sort of the least of our worries back then.
The MD is interested to see how this goes. I'm having to maintain a functionally equivalent Kotlin version, you know, just in case....
I'm hopeful I won't need it - as my tests show that my Clojure version produces the same results as the Kotlin version
I guess it would be far too much (imposing) for him to give a small 30 minute talk to London Clojurists whilst here?
I'm looking forward to the transcript/video of his History of Clojure talk from that. I know he's been researching it heavily for a while -- Alex has been reaching out to folks to confirm historical details etc.
I've reached out to Cognitect to see if there might even be a possibility of a small meetup chat from Rich
If there was one thing you could say to your younger self, as you embarked upon writing production Clojure code, what would that be? Any particular style, methodology, functions to really learn?
Hell yeah: avoid global data! Pass all that shit through the call chain instead!
We figured, back in 2011, we only have a fixed set of data sources so we'll just stick them in atoms in
and initialize them at startup. That was a terrible idea.
We built huge call chains on top of that where the data sources are implicit, and only hardwired into the bottom layer.
When we started to want to switch code from the master to the slave, or to a different DB account so we could leverage different access permissions, we got into a world of hurt.
And we did it with our caching layer too -- but that wasn't so painful: we have only ever needed one set of caching logic and we built in multiple named caches from the get-go so... yay, us.
I've spent a lot of the last several weeks refactoring code to remove those globals. I'm still only partially done.
In my codebase, I have one atom, that's when I define the datasource. I keep it in it's own namespace
txi.higgins.db and all SQL queries etc., all go through that namespace.
Fine for MVP launch. Won't scale. So plan to refactor away from that pattern before your code gets any more complex.
Sure, I'll look to refactor definitely - it's as much a learning experience for me as getting a MVP out to prove Clojure can be used at work 🙂
Funnily enough, Clojure has given us a "magic power" that no one expected: the ability to apply critical patches to live, running, production processes with zero downtime 🙂 Via a Socket REPL into production. Not something we'd really planned on -- and not something we do very often.
Most of our processes are clustered so a rolling, automated redeploy is our normal procedure.
Does the socket repl need to be running when the application is launched? It's not like you can "attach" to already running Clojure application magically?
But we have one app that is used internally and downtime is a major issue during work hours -- so being able to patch that via a REPL is amazingly convenient.
Well, you actually can attach a REPL to a process that was started without one -- but that's a security problem and you should have it disabled (Bing for "jvm attach security").
so, having a switch (say environmental, or runtime configuration) that would create a listening socket repl on the server application (if appropriate) is the answer - i.e., only enable listening if the computer says yes.
So we have a JVM options file that is picked up by our daemon script that starts/stops services and we add a Socket Server option to that as needed. Some processes have that enabled all the time, others only when we need debugging (and we're happy to restart a process).
Socket REPL is built into Clojure -- no dependencies. You can start a Socket REPL in any Clojure process (or Java app that includes Clojure as a dependency!) just by adding a JVM option.
We used to start nREPL with middleware in some of our processes but I always hated having that as a dependency.
I was super happy when we dumped all of that and switched to a basic Socket REPL -- for both dev and production.
i.e., run my app in a docker container, expose the port, enable the socket repl (via a feature toggle on the app startup) and see what I can do 🙂
I use Atom/Chlorine so a Socket REPL is all I ever need. My team mate uses Emacs and, I think, inf-clojure mode or something similar so he also avoids nREPL.
so, say you want to redefine a function on running code, you
in-ns '.... to the namespace and redefine the function (or def...)?
Yeah... I mean, Chlorine does that behind the scenes, so I can just put my cursor into an updated version of the code in that file and
ctrl-; B and it evals the top-level block (form) into the Socket REPL which, yeah, does the
in-ns and the
And I can use RCFs containing code to explore/debug things in a production context.
For me, production is identical to (local) development in that respect -- and so is our QA/showcase server since it also runs Socket REPLs.
so no difference between your editor and the clojure code on your machine, and your editor and the clojure code 1,000 miles away in some data centre.
The only difference is that locally I run my REPL in a context that has the
add-lib branch of t.d.a. so I can load new dependencies on-the-fly.
add-lib lands in a non-alpha context, I'll probably run that in production too... just in case I ever need to make a code change that requires a new dependency be added.
(but I'd prefer a rolling deploy via our automated system with an updated uberjar!)
Given that we can have a change committed to git be deployed to production in just a few minutes already...
so, if you make a change to production code, and it works, you then commit that code into your repo and shortly afterwards your application in production is updated with the fixed code (officially)
We have one legacy app that is not all Clojure and that still requires a manual deploy process 😐
So, I have a very small chance of introducing Clojure/ClojureScript on our team, for whitelisting. We whitelist people and services (e.g., allowing one service to call another) using properties of SSL certs (emailAddress, OU). Right now we're manually writing this data structure in JSON, but it's too easy to make a mistake. Was thinking of suggesting a small bit of Clojure, using Spec to validate the relationship between all of the moving parts (access groups, consumers, etc.). We'll probably end up doing this in Node or Scala, but spec seems like a big advantage. Another possible one: can you use something like cljc to generate both a JVM library and a Node library from the same code?
there are of course environment differences you may need to be conscious of when targeting both jvm and js - e.g. single thread on js
I don't think it needs to be complicated -- it's just a big, nested map, where you have to validate that the whitelisted entries or the service you are whitelisting have been defined in another part of the big, nested map. Or that you have no orphan nodes (access groups that aren't used anywhere, or services defined that are then not whitelisted for anything). Stuff like that.
sounds like something which could straightforwardly be written to target both jvm and js... i've no idea how good spec is at validating the sort of distant constraints you are wanting though
might it be cheaper to just leave it in JSON and write a script for your CI pipeline (possibly in Clojure) to validate it?
Yes, we still want JSON output. At a minimum, it's human readable and in an emergency can be edited manually. The whitelist is just a JSON file that's read by many (eventually all) our services from an S3 bucket and cached for a short period. It's a simple system, but the trouble is it's easy to make a mistake. Validating it as JSON is the simplest problem. Validating that the JSON makes sense is a bit harder.
Following on from the conversation I had with Sean this morning (vvvvvery early this morning). I tried launching my Clojure process with the JVM arg running a socket repl listening on port 55555. Anyone had experience of doing this within a docker container? Even although I'm mapping the ports, when I telnet (to kick the tyres) to the local port, I don't get a connection
@dharrigan have you done a
kubectl execto login to your container and check if the port is open directly ?
Hi - yes works locally (it's how I connect for my editor), JVM options shows the
-D.... setting being applied (same as local setup) and not using kubectl 🙂
I'm not familar with docker swarm, but can you use something like
docker ps and then
docker exec ... (Need to double check the syntax for that)
txi-higgins_1 | Exception in thread "main" java.lang.NumberFormatException: Invalid number: 0.0.0.0 txi-higgins_1 | at clojure.lang.EdnReader.readNumber(EdnReader.java:224)
I've officially reached the end of my tether with windows / c# / powershell
o/ Do any of you guys know of companies with open positions for a QA engineer? An excellent QA I've previously worked with is looking for immediate employment in London.
Thanks! I'll ask about the location. It's less of a question of willingness (which there is) and more of school/childcare hours.
The potential opening for Clojure in my team (described above) came to naught. We'll do something with Python instead. I'd love to try to interest some people in our team to try Clojure, because I think they would like it, but there's an immediate, knee-jerk reaction to lisp syntax that I can't seem to overcome. Does anyone have any success stories about getting Clojure adopted by a team? What kind of project did you try first? We're a Scala (back)/React (front) team and I think that might have something to do with it -- adopting both was a big deal and took quite a long time. Clojure, on the other hand, you could learn 90% of it in a day or two and the Scala developers (we write it purely functionally) would understand most of the other 10%.
In terms of project, the one I'm getting into our production is a very isolated, read from kafka, write to database application
I also wrote up use-cases where it fits into what we do (we process large amounts of data per day)
and hyping on about immutability, easy concurrency/parallelism etc.. basically the selling points of clojure
One of the issues for us is that the gap between Scala and Clojure is a bit smaller -- we already do functional, immutable data and have quite high-volume concurrent services. I'm working on a 10%-time project (we can work on whatever we want one day every two weeks), but it's quite a big project and it'll take me months. So, I'm happy (I get to work on Clojure), but I do think Clojure could solve some of the problems we're having -- like on-boarding new developers into Scala. It's a real bear of a language.
isn't the clojure/python Bridge very much alive and kicking? Karin Meier keeps tweeting about it
My own opinion of course, but I think Scala is sorta spining atm until Dotty comes out
Those Scala/Clojure races seem to come down to culture, you can write impenetable spaghetti code in both languages but it seems more acceptable to the Scala community to do so
if you've got people getting hung up on syntax that's a hard problem - i've encountered that before and it's not generally a rational objection, which makes it very hard to counter with a rational argument
yeah, it's possible I've actually poisoned the waters a bit too -- I'm the only Emacs user amid a sea of Intellij/VS Code users (so strike one), have a greying beard (strike two) and have showed people various features I've added to Emacs over the decades (strike three). Lisp? Yeah, that's something Santa Claus uses...
I'm not suggesting for a minute that they use emacs -- it's just that's the only time they've ever seen lisp code. In a 35-year-old editor.
@eamonn.sullivan Yeah, I think the historical bias in favor of Emacs within the Clojure community is a double-edged sword. It has great Clojure support and it's where a lot of effort is spent by Clojurians on improving that support, but it does act as a barrier to entry for non-Emacs users wanting to learn Clojure, especially given most beginners are recommended to read Brave and True which starts off by walking folks through Emacs installation and setup...
Santa Claus is efficient (he sees all the good little boys and girls - billions of them each year), he's parallel and concurrent - he's always predictable and reliable and he's good fun!
@eamonn.sullivan: > Does anyone have any success stories about getting Clojure adopted by a team? Sure. About 6 years ago I joined a startup with an existing ruby code base; and convinced the CTO to do the heavy lifting on the JVM (mainly because the best libraries for our eco-system existed in java), and because ruby was slow for handling large quantities of data, and that farming out jobs to remote external services was creating ops problems we didn’t need at our scale. i.e. we were using job queues because we wanted concurrency which ruby is poor at, not because we needed distributed computing & parallelism. Also he knew I had a lot of clojure experience anyway and had used it in many previous projects, and he was a geek and was convinced by rich hickey’s arguments etc.. fp, lisp, immutability etc. So we wrote some backend stuff in clojure; which worked really well and is still operational and under development today. And have written gradually more and more apps, libraries, tools and services in it. We’re now using it for almost everything, and have about 10 people coding clojure full time. Legacy ruby app is now being rewritten and replaced. We use clojurescript too for most but not all front end work. Regarding the syntax objections; syntax I’ve usually successfully argued with people that syntax is much less important than semantics and simplicity. Once they agree to that; then you explain the semantics of clojure syntax (takes about 10 minutes for most of it (clojure 1.0 syntax at least - the syntax has grown a bit more in recent years; but still fundamentally the same). I’ve never encountered anyone who hated the syntax after having such a discussion; and also being shown the capabilities it enables, e.g. paredit/smartparens/macros etc.
Thanks for sharing, I'm evangelising all I can, exploring use-cases and developing PoCs - no bites yet, but my fingers will remain crossed
completely true, but i do know apparently smart people who irrationally reject the parens
@eamonn.sullivan Macros are, in my experience, the best way to get people to realise that clojure (or more widely, lisp), syntax is not just perfectly fine, but the absolute best way to do things. Once people grok the whole, "code is just data, and data is malleable", they fall in love with the syntax quick-sharp. Depending on the organisation culture, you might want to consider putting a little internal, "fans of clojure" group together, or propose some kind of "show and tell" thing. People generally respond this this very well, particularly when you end it with a github link that they can peruse and play with in their own time.
I mentioned macros to someone recently and they said they know a Clojure developer who has only ever written two macros. And he's regretted one of them. In Elisp, I've created several macros and liked each one (well, most of them). I guess it depends on your view of "dangerous" features in a language (like pointers in C/C++). You could avoid using them entirely, but you wouldn't really be using the language as it was designed to be used.
@eamonn.sullivan Absolutely right, you should write macros rarely. I too have not written that many. It's not entirely the point though. Macros make the beauty of the syntax clear even if you never actually use them. It's a bit subtle, but I think it is true.
I’ve probably written more macros than most. The standard advice is true, you should certainly avoid writing macros if you can; though very few of the non-toy macros I’ve written I’ve regretted. I’d say they’ve all been very useful. Whilst I 💯 agree with the advantages of using data over macros; the problem with that approach is that you end up writing an interpreter rather than leveraging the existing compiled language you already have. Again there are some huge advantages in doing this; but it’s often a lot less work to just write the macro with the limitations it has. I’m currently looking at porting a datalog/datascript like query language I wrote from macros to a data representation, and it’s a lot more work than the version 1 I wrote that used macros. If I didn’t have macros I genuinely don’t think I would have been able to write the bulk of it in a day; it would’ve taken a week or more.
I do find, much like with any other "product", it is the peripherals that "sell" it. Working in the REPL for example. I don't know any other language that does this even half as well as Clojure does, and a big reason for that is the syntax, or rather the relative lack of it.
Aye, I think a good REPL-driven workflow, showing that really tight feedback loop, and showing how you actually develop "in" the REPL, is about the most persuasive thing I've seen so far in terms of making folks go "Wow, that's cool! And that's Clojure, right?" -- but even then your point #2 is a common comeback "How do I do that in <language X>?" and they often don't believe that you can't...
When I brought Clojure into World Singles Networks, I cross-trained two CFML developers (yes, really) and they mostly loved Clojure but felt the learning curve was very steep on the switch from imperative/OOP to FP. After a few years one left to go back to CFML at another company (and still does CFML as far as I know) and the other left to take some family time and then went to work for another Clojure shop. So I'd call that sort of 50% success 🙂
Most everywhere I've worked I've been able to bring in some sort of new tech, even if it hasn't always been a new language, but I've been in the industry about 35 years at this point and I've been some variant of "Senior Software Architect" for the last 20 of those so companies sort of expect me to move the needle in terms of tech...