Fork me on GitHub
#clojure
<
2024-03-11
>
cjohansen06:03:26

I want to add an assert-like macro to a library, for development use. However, instead of throwing exceptions, I want it to emit data on some channel, so that users can have a choice in reporting mechanics. Is tap> suited for this use? I like how "low tech" that would be, but at the same time I'm not sure if libraries tapping data is "a thing". If I use it, it would tap maps with some namespaced keys. Opinions? Alternative suggestions?

slipset07:03:40

Haven’t thought through the consequences at all, but you could have an “error” atom that holds the errors? Sucks of course if you create a lot of errors and you run out of memory?

cjohansen07:03:17

Yeah, that's the alternative. I'm not too worried about memory, but an atom does mean offering a place with state instead of offering a channel of information. With tap you could even build reporters without requiring my library directly. Not sure if that's a big win though 😅

slipset07:03:07

You wouldn’t even have to expose the atom as such, you could provide for an interface to add watchers to the atom. So then your code just provides a on-error kind of interface which takes an client supplied error callback.

slipset07:03:56

So, I guess that if you start with that, ie provide your clients a way to supply an error-callback, you’re free to deal with/change how you handle those errors internally?

cjohansen07:03:02

Sure, but I still want to know if just using tap> is reasonable 😄

slipset07:03:04

Which is reasonable 🙂

2food07:03:25

We do something like this with malli and portal. We instrument some functions with malli schemas, so that "errors" are tapped and inspectable in portal. It's quite useful. (this only happens in dev though)

cjohansen07:03:55

Yes, that's basically what it's for - in app code (my understanding). What I'm wondering about is if it's OK for a library to do that.

p-himik08:03:27

You can expose a function that registers some reporting mechanism that by default is disabled. Then your users can do stuff like (the-lib/set-reporting! #(tap> [:the-lib %])) or anything else they might like.

cjohansen08:03:18

Yes, so basically @U04V5VAUN's suggestion. Am I right then to conclude that tap> is the application developer's tool, and they should have control of what goes on it? That was my initial gut feeling.

p-himik08:03:06

Almost, but without an atom that stores the data. You can use an atom to store the function itself though. Anything that's prone to conflicts of any kind should be controlled by the app developer. tap> is one such thing, the conflict being for the attention of the developer. If they tap> their own thing and expect to see only one entry in the output, but your library taps 10 other things in the meantime, it's not good.

2food08:03:45

Yes, I definitely want a library's use of tap> to be opt-in!

thheller08:03:08

I'd say that tap> is a debugging-aid in the same sense that prn is. It can be used for other things, but shouldn't be treated as a generic "logger"

cjohansen09:03:30

I'll leave tap to the user then, thanks everybody 🙂

vemv11:03:02

What we opted to do in a particular library was to define specs in test/ and use vanilla instrumentation. The test/ dir generally never ends up bundled in a lib's .jar, so users cannot accidentally activate your specs

Ed13:03:34

another option could be something like a multimethod with a default implementation that does nothing. Then the user of the library can call defmethod to register their reporting action? Also depending on what your lib does, it might make sense to classify these things and register different actions for different types of data? idk ... but it's a language construct that's open to extension that might allow custom behaviour?

Olav Fosse08:03:39

I made a channel #C05M9Q11DQW for discussion about using Clojure for Capture The Flag (CTF) hacking competitions. Feel free to join if you’re interested!

👍 1
🎏 2