I'm curious what the most success people have had running Clojure (any dialect) on something like a Pi Zero (512MB RAM, 1GHz 4-core)? Like how heavy/scale of app were you able to achieve? I just got a Pi Zero 2 W in yesterday to test some code in a tiny environment and I'd love to get some insights on running/optimizing Clojure code.
not sure how the specs on a pi zero 2 compare to a 12 year old beagle board, but I bet it is beefier, and I didn't have to do anything special back then https://www.youtube.com/watch?v=XMIKfOmAMjQ
the tricky thing is interacting with hardware, since that usually requires fiddling with native code, but it wouldn't surprise me if these days there is already a java library for it on the pi zero 2
and there's #coffi if you need to write low level code
What processor has the Zero? 32 bit or 64 bit? (bb does run on the 64 bit RBP)
(you'll also need to install the 64 bit OS)
64-bit. Can bb run on 32?
no only 64
just use the linux arm binary, should work
In 2019 I built a Pi Zero W-powered garage door server. I really haven't upgraded it since that time, it's still on Java8. I used the "Immutant" webserver since (at the time) it was the best option for supporting websockets. I simply built an uberjar, I didn't do anything fancy like GraalVM (though I've been pondering that experiment for 6 years lol) Anyway, the uberjar is pretty slow to start up, 1-2 minutes. But, it starts up automatically on boot up, and its only job in life is to receive commands from my cljs UI to open/close the door, and to tell me the state of the door, and to send a history of events. So startup time is not really a factor. Once warmed up it consumes about 242K virt ram, 96K res ram. It can handle multiple users, but really I'm the only user. So, the resource needs are about as modest as they get, but, the Pi does a fine job.
As for interacting with hardware, I had only very modest needs to read from 2 GPIO pins (magnetic door position sensors), and write to 1 GPIO pin (to "push the garage door button", i.e. a relay).
Linux on the Pi already lets you read/write GPIOs just by using the filesystem, for ex: /sys/class/gpio/gpio17/value is one of my door sensors; read this file and you get a 0 or 1. So easy. Writing is similarly easy (don't forget to send the newline, i.e. "0\n")
The only awkward part was that Linux doesn't (or didn't at the time, not sure if this has changed) give you a way to activate pull-up resistor on a GPIO pin, which I needed to do in order to reliably read my sensors. I had to install some command-line binary utility to let me do this, but, I just run that utility on startup and pull-up the 2 relevant GPIOs.
I had a personal epiphany for a technique for designing ‘interfaces’ and was wondering if it is common knowledge/practice.
I have a extraction-state domain object, which is just a map, but I felt uncomfortable using map functions nilly-willy; I wanted to have the freedom to change the representation later, and also have other niceties like being able to quickly see all the points where extraction-objects get assoc’ed to.
So I decided to create an API/interface for it, but nothing too ceremonious like records and protocols, just dedicated functions to manipulate
this kind of objects. I started creating a set-state, and an update-state function, replicating map’s assoc and update, but then it just occured to me - I could just
(def set-state assoc)
(def update-state update)
and now I have my light interface ready to go. Is this kind of impl something that any others have been using? Would you be taken aback if you saw sth like that in a codebase?not crazy. I think i’d put a docstring and arguments on set-state. Right now it’s the same as assoc, but could easily change. using def is cute and quick but feels a bit loose unless this is just the exploration phase
hmm, so you’d use defn with similar arglists to the core functions?
i think there’s two common paths: Stay in data land. Let it just be a map and use map functions like assoc and update. Or, go to an api over a data structure. In that case give good docstrings about what they are. This is a middle way here that seems to not embrace either so it feels a bit wishy-washy. You have the veneer of an api but it’s definitely tied to data.
I see the point, thanks for the input. My thinking is to have something light and quick, but that would still provide some boundaries
> I wanted to have the freedom to change the representation later I would advise against this. Just because clojure doesn't force you to define a data model, it doesn't mean that you shouldn't. In general, data tends to outlive basically all other parts of your program. It gets defined literally in code, saved to disk, written to logs, stored in data bases, etc, etc. Over the long run, thinking about your data model and using an accretion approach will help keep you sane over time. It's ok to have an exploration phase where you're figuring things out, but you do want to hammer out your data model eventually.
Adding a layer of indirection like set-state and get-state usually doesn't help. Since data tends to leak all over the place, the layer of indirection doesn't really help you "change" your data model.
There are cases where you can define a protocol that let's you separate what an operation means from how it is implemented.
I’d agree that defining a data model is sth we should do, but do you also say forego the the ability to change representation, at least as a rule of thumb? Maybe I’m still a bit influenced by more education-oriented approaches like SICP (👋 Adrian, long time!)
(also, probably domain object was probably a little heavy and confusing a term for my extraction-state , it is not sth that gets stored in a db or anything, more like an intermediate result)
If your advise is for actual domain object I agree wholeheartedly
One point to consider is that maybe you have just a handful of top-level keys that you update, so all your state updates end up being basically (update-in state [:some-key-among-5-other-well-known-ones :foo] inc).
In that case, I'd probably create an update function per such a top-level key, all with their own arity, docs, and a clear name.
That's a nice approach
This discussion called https://leanpub.com/elementsofclojure to mind
Right, if it’s an important operation in your domain give it a specific name (create a function for it) - don’t just assoc/update willy-nilly
Has anyone created a machine-readable SBOM (Software Bill of Materials) for a clojure project? I'm not finding great hits on google. Maybe the easiest way is to convert pom.xml into SPDX using maven?
It's been a while but it should be possible to output a pom.xml and use Java tooling to check it
Ok it seems the cdxgen tool supports deps.edn and project.clj natively. Nice.
Either I don't know how to use cdxgen or it's not really doing anything for me. I'm running
npx @cyclonedx/cdxgen cdxgen -t clojure