Fork me on GitHub

For a (publicly available) library, yes, I agree that a clear public/private separation is useful from a documentation and support point of view. Otherwise there's not much point. And even for the library API, it's a toss up between using public and private in one ns vs using a fully public ns and an "implementation" ns (clearly documented as such), in my opinion.


(however, when discussing contrib library organization with Cloure/core folks, it seemed they lean heavily toward avoiding the public vs implementation ns approach)

Alex Miller (Clojure team)02:09:28

I don’t think there is consensus - there are examples of every option from clojure/core people


I'll rephrase then: when I asked for feedback on java.jdbc, I got very strong feedback from the Clojure/core folks who expressed a preference back then, that a "private namespace" or "implementation namespace" was not considered "good practice". I didn't push for justification, I just took it at face value.


It definitely feels like something that would be nice to get some design guidance on -- from the wizened ol' Cognitect elder statesmen 🙂

Alex Miller (Clojure team)02:09:45

well go look at core.async, designed by Rich

Alex Miller (Clojure team)02:09:59

it has a public API namespace, and a bunch of namespaces under impl


Yeah, I was a bit surprised at the strength of the feedback on java.jdbc's impl namespace at the time... I didn't think there was really as much consensus as the feedback indicated.

Alex Miller (Clojure team)02:09:15

well, not sure who that was from (hopefully not me) :)


It predates your Cognitect time by a long time 🙂

Alex Miller (Clojure team)02:09:33

there’s plenty of strong opinions around :) I just don’t think there’s consensus

Alex Miller (Clojure team)02:09:50

there are reasonable arguments for a variety of approaches


I think it would be great if Cognitect could perhaps articulate a core of "best practices" or at least the pros/cons of common approaches -- and cover those in a conference talk, to get the community discussion going around that sort of thing.

Alex Miller (Clojure team)02:09:59

I’d say the only approach that I actively don’t like is one public api namespace, with vars imported from elsewhere via potemkin. But I understand other people do like that style and I’ll respect their opinion. :)


Clojure seems to have woefully little guidance on style and code organization overall.

Alex Miller (Clojure team)02:09:45

collectively, people at Cognitect have written like a dozen books and dozens of presentations on it

Alex Miller (Clojure team)02:09:03

so, I feel like the opposite :)


Code organization across namespaces? That's been covered in talks and books?

Alex Miller (Clojure team)02:09:53

well I alone have written about it in multiple books now


Maybe Clojure Applied covers that (I only just bought that -- haven't started it yet).


Glad I bought it then!! 🙂

Alex Miller (Clojure team)02:09:17

Stuart Sierra has done talks about this, and written blogs about it I think

Alex Miller (Clojure team)02:09:07

I’d love to see you write about it :) you have plenty of experience to do so.


Hmm, not about this topic in particular, that I can remember. He's certainly done some strong opinion pieces on other topics 🙂


If I worked for a company that was in the business of advising others, I'd probably write / talk more!

Alex Miller (Clojure team)02:09:27

it’s always a struggle to balance the “doing things” with the “talking about doing things”


I'm just anti-private-cars because it makes unit testing, extension, and REPL debugging harder.


Wow thanks iPhone, private vars not cars


Yeah I wish there was an expressable relationship between test and regular name space letting the private vars be used explicitly


When I first started writing Clojure, I used private functions a lot. Over time I stopped using them and I almost never write a private function now (except for the library case above).


I've tended to find that I end up wanting to reuse functions that I initially thought should be private -- and since they're usually pure functions of their arguments, there's really no downside.

Alex Miller (Clojure team)02:09:53

I find it to be heavily context dependent and I do all of them (all public, public/private, split api/impl namespaces) depending on the situation

Alex Miller (Clojure team)02:09:12

but those are 3 useful patterns


Hi... I would like to know what how do you guys manage state, use things like compose or mount, or just use a simple def atom?


what in-memory mutable state our apps have tends to be in an atom in a component. there's rarely more than like one of those though. mostly state is stored in external systems


States like db connection, rmq connection (to use a single connection) a simple atom? That is it?


I'm making a service, but I'm isolating things like db connection, and others just use it


Each one in their context


But... I keep asking myself how to maintain the connections


unless the connection requires refreshing I wouldn't think of it as state, it would just be a field on a component. if it required refreshing then it would be an atom in a field on a component


Component from Stuart?


ya, I think his talks on that are currently the most common way to manage things like db connections in clojure apps


yes the library


there's alternatives, mount etc. but I believe component is still the most popular


Hmmm, I see, I will test it


I like the way erlang manages it, Passing through argument, but is automatic


Component kind of does that


very similar yes


ie as in, the state is all passed through via function arguments, but initializing that big state map is somewhat taken care of for you


And you isolate all of it... IE?


Isolating and pure functions, that is functional and clojure


components are isolated yes - you can create two of the same component with separate configs, or the same config but they each have their own state


btw a big advantage is for testing - with component all you need to do to “mock” in a test is to provide a hash map with the right keys on it


(as an explicit arg, no need to shadow a var or anything)


I see... but I don't see much reason to write tests on clojure... hehe


But I understand


in my experience that leads to a lot of problems


today, you use the repl and see that your code works


tomorrow, when you change something, do you know without running the app (or worse yet, deploying it) what other thing it might have broken by changing its behavior?


Component is really good to isolat and work with stateful services


unless you memorized everything you did in the repl to verify it worked…


Yah, I agree


and really a test is the simple version of that 😄 - take what you did in the repl, wrap some test/is calls around it


If you write small libs.. tests become pointless, but to do that you must write an excellent documentation so ppl doesn't get lost


I’m unconvinced that tests are ever pointless


some specific tests? sure, testing in general? no


The company that I'm does that way, it really boring writing those docs... hehe


I see, thanks for the tips @noisesmith


on the other hand, this is mostly opinion but I agree with Rich Hickey that “test driven development” is like “guard rails driven development” - it’s good to have barriers that let you know when they are crossed and avoid certain catastrophic mistakes (or catch them sooner when it’s easier to address), but centering your dev process around those barriers seems a bit much


All devs I know hate to write tests lol


@rcustodio I know quite a few devs who love TDD and writing tests. And once you start using generative testing, it's amazing how much value and coverage you get from very little test code. clojure.spec is great for helping with that.