Fork me on GitHub
#clojure-uk
<
2020-09-24
>
alexlynham08:09:42

late to the party but always :as so you have a specific namespace

alexlynham08:09:54

except in some very particular cases

dharrigan08:09:27

there's always room for one more at the party

dharrigan08:09:59

the continuous never-ending, no-need-to-be-socially-distant-or-wear-a-face-mask clojure party 🙂

dharrigan09:09:47

I have another good practice question, do you mark functions as private (in their namespace) or just don't bother?

mccraigmccraig09:09:03

rarely @U11EL3P9U, but occasionally it seems like the right thing to do

dharrigan09:09:01

I'm feeling the same 🙂 Currently, nothing of mine is "private"

mccraigmccraig09:09:37

e.g. i marked a fn which implements an extend protocol method fn private yesterday... but i think that's the only private fn in the whole project

reborg09:09:10

As the project grows in size, I find marking fns as private essential. That tells me if I should expect clients of the fn outside the ns but in the same project. I use another practice to mark fn that are also used outside the project. I create a wrapper for them in a specific ns meant as public facing API (for example core). If the function is there, it’s used by external dependencies and should be treated accordingly to allow graceful upgrade.

dharrigan09:09:31

that's an interesting approach 🙂

reborg09:09:00

I noticed this “more formal” approach starts to be required with team of 15-20 people working on mutually integrating projects

dharrigan09:09:14

when doing private, do you prefer (defn-...) or (defn ^:private ....)?

reborg09:09:44

If that’s not your case… don’t bother, all public! :)

reborg09:09:53

Normally defn- which is shorter

alexlynham10:09:45

I tend to mark things as private a fair bit, but often find that I eventually end up unmarking a lot of them cos they need to be used

3
reborg10:09:52

Other good scaling projects conventions: put docstrings in namespaces, kill utils.clj ruthlessly, don’t mark fn public because you want to test them ;)

dharrigan10:09:11

all very interesting 🙂 I like to ponder on what people do and see if I can use/adapt/ignore 🙂

reborg10:09:35

again… formality/conventions bring value when scaling, it has a price in the small. As always, tradeoffs.

dominicm10:09:10

I bet this varies a lot on how you structure your code. If it's more like a series of libraries which are being composed together, then there's a lot more private vars.

dominicm10:09:27

The 15-20 heuristic as a point when libraries start happening is a good link.

lsnape14:09:53

In the past I've tried to use functions in libraries, only to find the author made them private. Very frustrating! However for non-library projects i have found them useful

seancorfield15:09:44

I started off obsessively marking everything private (with defn-) because of my OO background. Then I gradually shifted to having everything public so client code could call anything and it was all easier to test. Like @U054W022G as our project at work has grown, I've gone back to making everything private unless it is a documented part of the API because my linter can tell me if a private Var is unused which helps with maintenance in a large codebase. I also have clj-kondo set to flag missing docstrings on public Vars -- again, a nod to the API-ness of such things.

seancorfield15:09:55

In my OSS libraries in particular, keeping things private unless they're part of the documented API makes life a lot easier -- for me as maintainer and for my users since they can stick to reading the API docs in general and not have to go grubbing around in the code.

dharrigan16:09:33

that's very interesting too. Do you still favour (favor? 🙂 ) defn- over ^:private?

seancorfield16:09:42

defn- and def ^:private

seancorfield16:09:05

(after all, defn- is built-in and shorter than defn ^:private)

lsnape08:09:42

@seancorfield, it’s a fair assumption, but in the past I’ve found lower-level functions I cannot use because they’re scoped private, presumably because the author didn’t think they’d be useful. It’s not always possible to anticipate the API that library users will need – often they don’t know until they start digging, or hit on a problem which means they can’t use the API as intended. OS maintainers are free to put out whatever they want of course, and there’s always a way round – please don’t take this as criticism of all the great work you’ve done! But for the sake of convenience I would eschew private in my libs unless I thought the vars were unquestionably off limits.

dominicm10:09:00

I feel like this conversation is potentially across purposes. I private functions because I have no intention of retaining or supporting them. Both answers given are potentially correct, so there's actually an additional distinguishing dimension.

👍 3
Adrian Smith12:09:29

It's a weird thing to think about, I think most people's intention is actually to try and tell you the functions they expect you to use, but when you see a private function it often won't explicitly tell you what function you should be using Maybe it'd be better to think about a mechanism for promoting functions rather than demoting functions

seancorfield16:09:23

@U07SQJ620 As an OSS maintainer, if someone decides to start using a private var and doesn't create an issue asking for it to be made public, I'm not going to be very sympathetic if I refactor the function away or change its signature (or even its behavior) and break their code 🙂

seancorfield16:09:00

OTOH, I am perfectly happy to consider an issue requesting a private var be "promoted" to part of the API.

dominicm17:09:57

I think the question is why the structure of the API even makes it a problem. There's usually a mismatch in either design or problem being solved.

seancorfield18:09:49

Definitely. If I "made a mistake" and made something private that left the API lacking, I'm happy to fix it. If the private function is truly an implementation detail then I need to figure out what the API should so that functionality is exposed officially, in a supportable manner.