Fork me on GitHub
#duct
<
2017-12-20
>
albert.lai05:12:51

@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.

rickmoynihan10:12:36

> 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.

rickmoynihan10:12:42

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.

rickmoynihan10:12:46

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

weavejester14:12:11

@rickmoynihan, I thought @albert.lai was talking about whether to have a repository per project, or to group many related projects under one repository.

weavejester14:12:54

In terms of partitioning by feature or layer, I actually intend to partition by feature.

weavejester14:12:52

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.

weavejester14:12:05

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.

rickmoynihan15:12:50

@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?

rickmoynihan15:12:22

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

weavejester20:12:01

@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.

weavejester20:12:08

So then you might have: app.foo.handler and app.bar.handler but app.boundary.baz

weavejester20:12:53

Unless you use app.baz.boundary, but then that also conflicts with things like the way middleware namespaces are usually laid out.

weavejester20:12:57

I guess app.feature.foo.handler might work, but that seems redundant.

weavejester20:12:26

Either way I think there are edge cases where it doesn’t really fit right.

rickmoynihan21:12:15

@weavejester: yes there are usually shared/cross-cutting things… I normally put them in a common namespace, e.g. app.common.user

rickmoynihan21:12:43

or just app.common or app.util

rickmoynihan21:12:59

depending on how they can be grouped

rickmoynihan21:12:17

@weavejester: how do you mean they conflict with middlewares?

weavejester21:12:33

@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.

rickmoynihan21:12:17

Ok… I don’t think that’s an issue though… I think applications and libraries are very different

rickmoynihan21:12:48

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

rickmoynihan21:12:47

and that layout is something frameworks usually encourage… where as a library wouldn’t.

weavejester21:12:35

@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.

rickmoynihan21:12:16

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.

weavejester21:12:44

I think I agree with the general thrust of your argument. I’ll need to give it some thought.

rickmoynihan21:12:03

Cool. Thanks for taking the time to discuss it.

rickmoynihan21:12:42

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).