[HN Gopher] Babashka Clojure nREPL as a system interface
       ___________________________________________________________________
        
       Babashka Clojure nREPL as a system interface
        
       Author : Borkdude
       Score  : 97 points
       Date   : 2022-11-27 10:22 UTC (12 hours ago)
        
 (HTM) web link (yogthos.net)
 (TXT) w3m dump (yogthos.net)
        
       | gemstones wrote:
       | One nice thing about this setup is that it's not specific to
       | Clojure/Lisp; any scripting language with a REPL will do this
       | well:
       | 
       |  _Python:_                   import subprocess         import
       | json              def osquery(query):           return
       | json.loads(subprocess.check_output(["osqueryi", "--json",
       | query]))                  #>>> osquery("select * from routes
       | where destination = '::1'")                  #>>>
       | [{'destination': '::1', 'flags': '2098181', 'gateway': '::1',
       | 'hopcount': '0', 'interface': 'lo0', 'metric': '0', 'mtu':
       | '16384', 'netmask': '128', 'source': '', 'type': 'local'}]
       | 
       | _Node:_                   const { execFile } =
       | require("child_process");              async function
       | osquery(query) {           return new Promise((resolve, reject)
       | => {             execFile("osqueryi", ["--json", query], (error,
       | out, _err) => {               if (error) {
       | reject(error);                 return;               }
       | resolve(JSON.parse(out));             });           });         }
       | //> await osquery("select * from routes where destination =
       | '::1'");                  //> [         //>   {         //>
       | destination: '::1',         //>     flags: '2098181',         //>
       | gateway: '::1',         //>     hopcount: '0',         //>
       | interface: 'lo0',         //>     metric: '0',         //>
       | mtu: '16384',         //>     netmask: '128',         //>
       | source: '',         //>     type: 'local'         //>   }
       | //> ]
       | 
       | _Ruby:_                   require "open3"         require "json"
       | def osquery(query)           out, err, exit_status =
       | Open3.capture3("osqueryi", "--json", query)           if
       | exit_status != 0             raise err           end
       | return JSON.parse(out, symbolize_names: true)         end
       | #irb(main):1:0> osquery("select * from routes where destination =
       | '::1'")         #=>         #[{:destination=>"::1",         #
       | :flags=>"2098181",         #  :gateway=>"::1",         #
       | :hopcount=>"0",         #  :interface=>"lo0",         #
       | :metric=>"0",         #  :mtu=>"16384",         #
       | :netmask=>"128",         #  :source=>"",         #
       | :type=>"local"}]
        
       | user3939382 wrote:
       | I hear near universal praise for repl development but in my very
       | limited experience with it, found it nearly impossible. Maybe
       | someone can clarify?
       | 
       | What I saw was that the repl leads to a runtime state that is
       | invisible and therefore hard to predict. For example, you define
       | a function in the repl, or assign a value to a variable. You're
       | just supposed to keep the existence of those declarations in your
       | head? I must be missing something.
        
         | nlitened wrote:
         | > What I saw was that the repl leads to a runtime state that is
         | invisible and therefore hard to predict
         | 
         | I'd also add to what Borkdude said: it also helps that Clojure
         | strongly encourages you to keep runtime state localized (not
         | spread all over the places).
        
         | nanomonkey wrote:
         | In the case of Clojure and many other Lisps one makes changes
         | to your source code, and evaluate each one of those changes
         | automatically, or through some key command (ie highlighting the
         | s-exp and evaluating it directly).
         | 
         | This allows you to hot reload changes to the source code, or
         | fire off events directly from your editor. In Clojure one often
         | has commented out code that one can test functionality, or make
         | state changes directly.
         | 
         | Very little work is done at the REPL command line, instead it
         | is fired off to the nREPL (network accessable REPL).
        
         | TacticalCoder wrote:
         | > For example, you define a function in the repl, or assign a
         | value to a variable. You're just supposed to keep the existence
         | of those declarations in your head?
         | 
         | If you're using a LSP server, which btw uses the "clj-kondo"
         | which borkdude mentioned, it's totally independent from the
         | REPL and will tell you immediately if your source file is
         | missing a function definition or a variable.
         | 
         | Now it could be argued that you could have a wrong version of a
         | function declared in the source file (and hence LSP / clj-kondo
         | would still be happy) while the correct version got only
         | defined at the REPL but...
         | 
         | That's not how I develop: typically I test stuff at the REPL
         | but only define my functions in the source file. And from the
         | source file, I "eval" the function and its hence available
         | directly in the REPL.
         | 
         | Now I don't know about others but in my case I regularly write
         | _anonymous_ functions at the REPL, which I test directly on
         | some data at the REPL, and then I copy /paste the anonymous
         | function to the source file and give it a name there.
         | REPL> ((fn [x] (* x 2) 21)         42
         | 
         | OK, good, it works now, I cut/past (fn[x] (* x 2)) to the
         | source file and change the anonymous _fn_ to a _defn_.
         | 
         | But I'll also sometimes just directly write the function in the
         | source code file.
         | 
         | In addition to that, unit tests can help too.
         | 
         | So it's REPL + unit tests + LSP (which uses clj-kondo) and all
         | three are totally independent.
         | 
         | And yet although they're independent, when LSP tells me
         | something like: _" Function x is called with only argument but
         | expects two"_, I can fix it, eval the correct function, and the
         | REPL is immediately aware of the correct version.
         | 
         | I've always got both the REPL and the Clojure LSP server
         | running, independently, simultaneously.
         | 
         | > or assign a value to a variable.
         | 
         | Clojure really tries to put the emphasis on functional
         | programming so you don't typically have lots of mutable
         | variables to juggle with. I'd say I have more of a "global
         | application state" at the REPL than different variables.
         | 
         | > I must be missing something.
         | 
         | Maybe you're simply not aware that you can code in the source
         | file, eval there, and the eval'ed functions are directly
         | available from the REPL?
         | 
         | I'm not sure my explanation are very clear but I hope it helps.
        
         | Borkdude wrote:
         | In Clojure, you don't typically type code into the REPL, but
         | write code in a file and then evaluate that code in a REPL
         | connected to your editor. We don't just type into a console
         | window, then reboot for some OS updates and forget about our
         | previous efforts :). Combining this with a static analysis tool
         | / linter like clj-kondo will also help since it will remind you
         | that you removed certain functions, while they may still be
         | there in the REPL.
        
       | sph wrote:
       | Babashka looks great (and perhaps the one thing that will make me
       | try Clojure. I am allergic to the JVM), and I didn't know of
       | osquery.
       | 
       | But am I blind, or is there no documentation of what osquery
       | modules/tables are available?
       | 
       | https://osquery.readthedocs.io/en/stable/
       | 
       | EDIT: rewritten the comment so it's less of a rant
        
         | hiyer wrote:
         | The list of tables is available here -
         | https://www.osquery.io/schema/5.5.1/
        
         | jwr wrote:
         | > I am allergic to the JVM
         | 
         | Ok, I have to admit I am "allergic" to this take. Why do you
         | mind (or even care about) the JVM? Do you care about the
         | innards of Python's VM, or any other language's runtime?
         | 
         | Leaving aside which language you use on top, the JVM is likely
         | the single most-developed and most-improved VM ever created.
         | Uncounted bazillions of man-hours of development went into it.
         | Corner cases were found, performance was tweaked, just-in-time
         | optimization was implemented, novel garbate collectors were
         | developed. It is an impressive piece of machinery, which is why
         | I find it slightly annoying when it gets a dismissive treatment
         | "just because".
         | 
         | Of course I might be wrong and you might just be that person
         | that spent the last three weeks chasing an obscure JVM issue
         | that happens in 0.01% percent of production servers, in which
         | case you do have legitimate reasons for being "allergic" to the
         | JVM.
        
           | bmitc wrote:
           | I can speak to this a little, as I have the same aversion to
           | the JVM. Despite wanting to get into Clojure multiple times,
           | I always get hung up on getting going with it. How do I
           | install Java? Is this the "right" Java? How do I now install
           | Clojure? Which project management thing do I use? There's
           | this Leiningen thing but also this new Clojure CLI. Then it
           | comes to IDEs, and they all work rather differently.
           | 
           | The first time I tried Clojure, I tried with Leiningen, but
           | it dumped literally hundreds of lines of Java stack traces
           | when something went wrong. So I stopped.
           | 
           | As a comparative example, how do I install F#? Well, you
           | install the .NET SDK, and then you get F# automatically. When
           | something goes wrong, I get good error messages that are
           | tailored to F#.
           | 
           | I think it's a little misleading to ask "why do you care
           | about the JVM?" because the answer is that "Clojure makes you
           | care about the JVM".
           | 
           | Of course, maybe it's me. But I have no trouble using F#,
           | Racket, Elixir, Erlang, or several other languages. Yet, I
           | have struggled every time to get going with Clojure.
        
             | __jem wrote:
             | I don't mean to deny your experience or sound rude, but it
             | genuinely baffles me that you would have difficulty
             | installing Java. I do not understand how it is different
             | than installing literally any other programming runtime.
             | How is installing the .NET SDK any easier than installing
             | Java?
        
               | bmitc wrote:
               | That's not exactly what I said though. For Java in
               | particular, is it Oracle JDK or OpenJDK, what's the
               | difference, and why should I care? The latter is the same
               | sentiment of the person I responded to. I don't care, but
               | I'm presented with the different options depending upon
               | which Clojure install guide I am following.
               | 
               | It's really the experience in totality. There are
               | choices, but for someone new to the Java ecosystem, it's
               | confusing why and why should I care. Because in the end,
               | I don't care. I just want to use Clojure, but there's
               | decisions to be made at every step of getting going that
               | aren't clear to someone new to the ecosystem.
               | 
               | This same thing happened with .NET as well. At one point
               | in time, there was .NET Framework, .NET Core, and Mono
               | and a question of how to get F# in all that. That was
               | just as, if not more so, confusing. However, it's since
               | been cleared up: install .NET 6 or higher.
        
               | kaba0 wrote:
               | > For Java in particular, is it Oracle JDK or OpenJDK,
               | what's the difference, and why should I care?
               | 
               | I know it's mostly about a sentiment, but if you or
               | anyone is curious -- there is basically none, OracleJDK
               | is a fork of OpenJDK (which is the reference
               | implementation) with basically negligible changes.
               | License wise OpenJDK uses the same one as Linux so you
               | can use it as you seem fit, while the current LTS
               | OracleJDK (17) is free to use until the next LTS release
               | + 1 year, but unless you need corporate support, you
               | really have no need for that.
        
             | kaba0 wrote:
             | <your-pkg-manager> install openjdk
             | 
             | Pretty much whatever you do, you will get OpenJDK (all
             | these options are forks with minuscule changes for the most
             | part). If you do happen to need multiple JDKs I can
             | recommend sdkman. But I think the java platform is pretty
             | suckless, especially that it has probably the very best
             | backwards compatibility.
        
           | user3939382 wrote:
           | I have an irrational fear of it because of the days in the
           | late 90s/early 2000s when Windows desktop software would
           | sometimes require booting a Java VM which guaranteed two
           | things: the UI would be weird / not native, and the boot time
           | would be super slow. I'm still scarred.
        
             | [deleted]
        
             | the-alchemist wrote:
             | That's fair. I remember those damn Java applets that froze
             | the entire computer for a minute while they started.
             | 
             | But that was 20-30 years ago, literally. A few things
             | happened: SSDs, and Java startup time.
             | 
             | A warm-start Java "Hello World" is 200-300ms. A babashka
             | (bb) "Hello World" is 30-40ms, which is faster than Python3
             | "Hello World" (40-50ms).
        
               | askonomm wrote:
               | I'd still say that even today Java desktop apps are much
               | slower, laggier and generally still look worse than their
               | native counterparts. It's just that, yes, hardware is so
               | much better which sort of hides most of the Java
               | problems.
        
               | kaba0 wrote:
               | Uglier is relative, but I will give you that neither
               | unthemed Swing or JavaFX are too fine looking.
               | 
               | But I would say that e.g. IntelliJ looks quite good and
               | that is a basic theme available without much tweaking,
               | plus it can be very snappy (when jetbrains doesn't ship
               | it with a decade old JVM with shitty default settings. It
               | is fixed in recent versions).
        
           | sph wrote:
           | I did not expect anyone to be offended because I have never
           | been a fan of the Java world. I have no real reasons, never
           | had a need to use the language, I always saw it overly
           | verbose and associated with boring corporate culture and
           | didn't enjoy my time configuring Tomcat and other Java
           | projects 15 years ago.
           | 
           | I am well aware it is a very productive ecosystem, though I
           | feel I am entitled to like or dislike any technologies I wish
           | to, however irrational it might be. It was a figure of speech
           | mostly intended as tongue-in-cheeck, not a statement of fact
           | that I need to defend.
        
             | __jem wrote:
             | I mean, you said you were allergic to the JVM, not to Java
             | syntax. Those are clearly different things, and especially
             | nonsensical in this context as Clojure is not Java (indeed
             | Clojure tends to be one of more terse languages in
             | practice).
        
       ___________________________________________________________________
       (page generated 2022-11-27 23:01 UTC)