This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-20
Channels
- # adventofcode (140)
- # beginners (107)
- # boot (120)
- # boot-dev (1)
- # clara (13)
- # cljs-dev (9)
- # clojure (107)
- # clojure-argentina (5)
- # clojure-art (16)
- # clojure-dev (23)
- # clojure-greece (19)
- # clojure-italy (5)
- # clojure-russia (2)
- # clojure-serbia (3)
- # clojure-spec (27)
- # clojure-sweden (1)
- # clojure-uk (15)
- # clojurescript (134)
- # cursive (5)
- # data-science (10)
- # datomic (23)
- # duct (28)
- # fulcro (48)
- # garden (5)
- # hoplon (2)
- # instaparse (1)
- # klipse (7)
- # leiningen (8)
- # lumo (36)
- # off-topic (72)
- # om (4)
- # onyx (37)
- # perun (4)
- # re-frame (64)
- # reagent (86)
- # remote-jobs (1)
- # shadow-cljs (59)
- # spacemacs (16)
- # sql (1)
- # uncomplicate (6)
- # unrepl (90)
@weavejesterDuct could support both styles without any issue, so everyone could go for their style. However, many newcomers like me might just follow the convention in project template as @rickmoynihan saying, would it be nice to put the style into the template that creator feel comfortable to work with? That’s why I asked about the preference. Since the preference really affect the newcomer’s user experience.
> I don’t think Duct has a real preference either way.
@weavejester: Except I think it does express a preference; as lein new duct foobar +site +example
creates foobar.handler.example
, and foobar.boundary
which I think sets people off on the wrong foot of grouping things by framework concepts, rather than by application domain concepts.
We’ve found this style problematic on real codebases, and it’s been a source of personal frustration that practically every project template does it this way, leading to a proliferation of this style in various webapps we maintain, and time consuming refactorings later on.
It’s not a frequently discussed topic of conversation in the clojure community though… so perhaps it’s just Russell Dunphy, myself and @albert.lai who feel this way. But I’m a strong believer that the code layout should say something about how your domain is structured, and having folders like foo.handler
, foo.routes
(not so common in duct with a data driven router), and foo.datamodel
etc… puts your technology choice above your domain… much better is a layout like:
- foo.article
- foo.blogpost
- foo.homepage
- foo.user
As the top level says what your app does. Within each you can partition horizontally if you need to, e.g. foo.article.handler
, foo.article.db
, foo.article.util
, foo.article.view
@rickmoynihan, I thought @albert.lai was talking about whether to have a repository per project, or to group many related projects under one repository.
In terms of partitioning by feature or layer, I actually intend to partition by feature.
I place most of a feature’s code under foo.handler.feature
. It’s only interfaces that are shared between features that get their own namespaces.
e.g. if several handlers wanted to access the users table, one might have a foo.boundary.user
, but otherwise boundaries would be part of the handlers themselves.
@weavejester ok, in that case we both agree that by feature is better 🙂
I think foo.handler.*
encourages people to partition by layer though, as the layer (handler) is the outer-most thing; even though I see that’s not how you think of it.
Is there an argument that reversing it to foo.feature.handler
would clear that up misconception up?
obviously it might mean that top level namespaces might end up including features and other odds and ends (like boundaries)… but I’d probably be ok with that
@rickmoynihan I think the problem is that we have features, and things that exist across features. For example, we might have two features, foo
and bar
, that share a common boundary baz
.
So then you might have: app.foo.handler
and app.bar.handler
but app.boundary.baz
Unless you use app.baz.boundary
, but then that also conflicts with things like the way middleware namespaces are usually laid out.
I guess app.feature.foo.handler
might work, but that seems redundant.
Either way I think there are edge cases where it doesn’t really fit right.
@weavejester: yes there are usually shared/cross-cutting things… I normally put them in a common namespace, e.g. app.common.user
or just app.common
or app.util
depending on how they can be grouped
@weavejester: how do you mean they conflict with middlewares?
@rickmoynihan I mean that usually namespaces in libraries are not organised by feature (since they don’t have any), so you have namespaces like ring.middleware.blah
and duct.server.http.jetty
.
Ok… I don’t think that’s an issue though… I think applications and libraries are very different
e.g. it’s not usually the job of a library (in clojure) to specify state inside vars… It should let the application do the def
.
Similarly I think it’s reasonable for us to layout applications differently to libraries
and that layout is something frameworks usually encourage… where as a library wouldn’t.
@rickmoynihan It might be a good idea to draw a line between libraries and applications, though I think in practice there’s a lot of cross-pollination. Namespaces might migrate between an application to a library.
there is cross pollination but if you were moving code from an application to a library you’d likely be renaming it to remove the application name from it… If you’re sharing a feature
(perhaps user login - would be an example) then you’re really sharing a module or component (i.e. a chunk of application) rather than a normal library.
I think I agree with the general thrust of your argument. I’ll need to give it some thought.
Cool. Thanks for taking the time to discuss it.
it’s more common for code to be extracted from an application to a library - and in the process its contract changing (i.e. new names). Libraries rarely move into applications; though if they do, it’s probably on the scale of copy/pasting a middleware or utility function to patch it somehow. When that happens I think you usually have new names too… or if patching you’re deliberately keeping the name (and it’s not in your apps namespace anyway).