Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What about directory structure? #3

Closed
achtan opened this issue Jan 8, 2016 · 94 comments
Closed

What about directory structure? #3

achtan opened this issue Jan 8, 2016 · 94 comments

Comments

@achtan
Copy link
Contributor

achtan commented Jan 8, 2016

Will be Mantra opinionated about directory structure?

@arunoda
Copy link
Collaborator

arunoda commented Jan 8, 2016

oh yes.

@arunoda
Copy link
Collaborator

arunoda commented Jan 9, 2016

Hope this is answered :)

@arunoda arunoda closed this as completed Jan 9, 2016
@achtan
Copy link
Contributor Author

achtan commented Jan 9, 2016

Yes is it, sort of :)
Many developers use type-based structure:

actions/
    | articleActions.js
    | commentActions.js
components/
    | article.jsx
    | comment.jsx

imho better is feature-based structure:

comments/
    | comment.js
    | commentActions.js
articles/
    | article.jsx
    | articleActions.jsx

and I'm afraid that Mantra will use first approach and that's kind of worries me :/

@arunoda
Copy link
Collaborator

arunoda commented Jan 9, 2016

That's something we need to figure out first. We'll go with 1 for now.
We will have a module system, where you could keep actions, UI components and the containers in a single folder.
You can even distribute them via NPM.

But that's not coming with the initial draft. We'll have it.

@natecox
Copy link

natecox commented Jan 9, 2016

+1 for the feature-based structure. I think it's a better way of laying out larger projects, and more in line with the react methodology of grouping feature based code together.

@achtan
Copy link
Contributor Author

achtan commented Jan 10, 2016

@arunoda you can maybe reopen this issue to get more opinions from people

@arunoda arunoda reopened this Jan 10, 2016
@arunoda
Copy link
Collaborator

arunoda commented Jan 10, 2016

@achtan That's a good idea.

@leocavalcante
Copy link

Feature-based 👍
This reminds me about Uncle Bob's talks where he says about that architecture should reflect intent like a blueprint of a church/library, you see it and you already know what it is about. You open a source-code folder, sees post/, comment/, author/ and category/ you already knows it's about a Blog.

@ghost
Copy link

ghost commented Jan 11, 2016

+1 for Feature based.

@Maxximus007
Copy link

+1 for Feature based

@markshust
Copy link

+1 I think it'll be easier to understand logic & testing flow if everything is feature-based

@adrianmcli
Copy link

+1 for Featured based.

Agreed. Feature-based is probably better for scalability. I used to use a type-based structure, but an app quickly grows in size and you end up having these huge folders filled with many many files.

@arunoda
Copy link
Collaborator

arunoda commented Jan 11, 2016

I'm looking to work on the module system.
Guys any ideas? @achtan gives us a one solution.

So here's my idea.

In a module, we can have it's own

  • Actions
  • Components
  • Containers

But only containers and components can be only view to the outside. (Or do we need actions too?)
We can only export one container from a each module or many.

If it's a one module we can have a directory structure like this:

* actions.js
* component.jsx
* container.js
* index.js
* tests
    - actions.js
    - component.js
    - container.js

Otherwise, thing will get a bit complicated. What do you think?

@natecox
Copy link

natecox commented Jan 11, 2016

One issue that I've had in virtually every framework is how difficult it can be to stay organized when grouping code into single file compartments (e.g., 'actions.js'). My favorite solution to this so far is to turn those files into directories, and inside the directories house a file for each instance.

Taking actions as an example, rather than adding all of the actions for the module into a single file, I would have an actions directory, and each action itself would get a file inside of this directory. This makes it easy to find code you're looking for, makes each file less complicated, and clearly spells out the requirements of each action via imports (if imports are used rather than a global namespace, which seems to be Meteor's preference).

With this in mind, my ideal module would be laid out as follows:

* actions/
    * action1.js
    * action2.js
    * ...
* components/
    * component1.jsx
    * component2.jsx
    * ...
* containers/
    * ...
* tests/
    * actions.js
    * component.js
    * container.js
* index.js

The tests directory is kind of up in the air. I feel like it should be broken down, but I don't know enough about the proposed testing structure and usage to recommend if it should be or not for this use case.

@minfawang
Copy link

Very similar to the two above comments, I have a idea writing in this Gist: https://gist.github.com/minfawang/12ca72ac36260426e46b

Within each module/feature, I have "containers, components, actions ...", but rather than just name them as "container.js", "component.jsx", etc, I put them into separate sub-directories. Then each sub-directory has the "index.js" that exports the files/functions/object/anything dependent by other files/modules. So we could still do something like import { addTodo } from 'TodoApp/client/actions'

@rnarayan
Copy link

+1 for the feature based structure recommended by natecox.

@achtan
Copy link
Contributor Author

achtan commented Jan 12, 2016

@natecox and @minfawang your proposals are type-based in context of module...

@arunoda agree with you, that's a good direction!
btw: but i think we can also export some of the actions if it is necessary. For example if you have cart module in eshop maybe you will need some actions to by accessible in other modules or so...

@arunoda
Copy link
Collaborator

arunoda commented Jan 12, 2016

@achtan Yeah! That's a good one. May be there are some modules, which only have actions.

There is one thing I need to clarify.
We won't have a server directory inside this

We need to make sure client and server are two separate things. But it's okay to have method_stubs like this.

@minfawang
Copy link

@achtan Oh my bad.. Sorry for not reading the post carefully. Now I see your point.

I think both approaches have its own advantages. For the "one module" approach proposed by @arunoda I think the root directory can get cumbersome when the app grows to a large scale.

I feel actually my approach could be thought as feature and type combined based if you separate modules based on features. Currently I separate modules as different code splitting points. You can think of a module as one big feature or a set of small features.

@natecox
Copy link

natecox commented Jan 12, 2016

@achtan This was within the given context of 'structure inside a module'. If you assume that modules are based on features, than this would definitely be feature based rather than type based.

Type based would be

*components
    * Todo
    * Different Todo
* actions
    * Todo
    * Different Todo

where we're suggesting

* Todo
    * components/
        * ...
    * actions/
        * ...
* Different Todo
    * components/ 
        * ...
    * actions/
        * ...

@natecox
Copy link

natecox commented Jan 12, 2016

@arunoda One thing I noticed while reading the spec is that the suggestion is to put all of your components inside the client/ directory. How are you handling server side rendering for SEO in this context? I've always had to provide my components via lib/ to make them accessible for SSR.

@adrianmcli
Copy link

With larger apps, things tend to get complicated very fast. Files get bloated quickly, and I always feel like I want to make many smaller components rather than fewer larger ones.

What do you guys think about modules with sub-modules approach?

- ChatModule
    | component.js
    | actions.js
    | container.js
    - ChatMsgsArea/
        | component.js
        | actions.js
        | container.js
    - ChatInputArea/
        | component.js
        | actions.js
        | container.js

- SettingsModule
    | component.js
    | actions.js
    | container.js
    - GeneralSettings/
        | component.js
        | actions.js
        | container.js
    - AdvancedSettings/
        | component.js
        | actions.js
        | container.js

@arunoda
Copy link
Collaborator

arunoda commented Jan 12, 2016

@adrianmc I think we should limit to a single level of modules. Otherwise, we'll have a lot of nested modules and very hard to deal with.

@natecox
Copy link

natecox commented Jan 12, 2016

@adrianmc I feel like submodules make it too easy to violate the single responsibility principle.

@achtan
Copy link
Contributor Author

achtan commented Jan 12, 2016

@natecox if you isolate this one:

* Todo
    * components/
        * ... // what will be here? todoList.js, addTodoForm.js
    * actions/
        * ... // and here? fetchTodos.js, addTodo.js

it is type base structure inside module because you separating code by type

@achtan
Copy link
Contributor Author

achtan commented Jan 12, 2016

maybe a good question would by "what is the 'Module' and what you / I / everyone think under that term"

@arunoda
Copy link
Collaborator

arunoda commented Jan 12, 2016

@natecox Actually, that's a decision of Meteor's current 1.3's layout system let's talk about SSR here.
See: #11

@arunoda
Copy link
Collaborator

arunoda commented Jan 23, 2016

@tomitrescak In Meteor everything in the server got imported (or places outside imports). Let's see what we can do for that as well.

@tonyxiao
Copy link
Contributor

@tomitrescak everything in the client also gets imported, if they aren't placed inside imports directory. See http://docs.meteor.com/#/full/structuringyourapp

@tjmonsi
Copy link

tjmonsi commented Jan 26, 2016

@arunoda and everyone, I did a modified structure of Mantra to test my point

  • making a npm-module-able generalized stateless ui components list,
  • an npm-module-able generalized posts and comments modules (to get the data),
  • and a developer-created containers to match the data got from posts and comments modules to the generalized stateless ui components

I would like to get your opinions about it: https://github.com/tjmonsi/mantra-atomic-structure-suggestion

@arunoda
Copy link
Collaborator

arunoda commented Jan 27, 2016

Guys,

We are finalizing the module system and now it's almost ready. But, we need to figure out a decision regarding routes. Could you have a look at this?

See: mantrajs/mantra-sample-blog-app#24

@mquandalle
Copy link

@arunoda Could you explain why you prefer to restrict Mantra modules to being client side only? It seems to me that a “module per feature” model would benefit from Meteor-like “universal” modules.

@arunoda
Copy link
Collaborator

arunoda commented Jan 31, 2016

In the future, there won't be any server code we need to manage. (Or we don't need to).
We can simply use some GraphQL queries for that.

So, mixing server and client code together is a really bad idea.
And I'm strictly opposed to universal apps.

@mquandalle
Copy link

I disagree in that I see some value in modules being able to define some client and server logic. A central argument in your article against “universal apps” is against “single codebase that runs everywhere” which is really not my point here. Similarly I could agree with “mixing server and client code together is a really bad idea”, but this is easily solved by putting code for different targets in different files.

So maybe we don’t have the same definition of a module, but for me it is important that they are able to send emails, define new GraphQL mutations, or start backgrounds tasks, all of which happen on the server. I can go into more details if the examples I’m giving aren’t clear (and if you have some time you can take a quick look into a description of my desired plugin system for Wekan).

@leocavalcante
Copy link

I always though about universal apps as client code running everywhere. Is clarifying to read about universal apps as code shared between client and server too, seeing them mixed and loaded twice (in the browser and in the Node) was something that really bugged me on my way learning Meteor.

On the other hand, I think that this is one of the Meteor core ideas. If I start to think in server and client code separated, glued by something like GraphQL I don't know why I even will be using Meteor instead of a Node/Express solution like Relay or my own.

Splitting server and client code and not thinking universally isn't Meteor-counter productive? Why to use Meteor if you will be avoiding Meteor features?

@markshust
Copy link

@leocavalcante this is a core principle of mantra, so it will never change. I do think it was one of Meteor's core ideas, but I think even MDG is moving away from this practice as it doesn't work in the long term.

Think of React/frontend as just the view layer, as it is. Then Meteor/server as the backend/API that is called. The two aren't and really shouldn't be related. Arunoda's article on this sums it up pretty nicely. It's a different way & a change to what we've been taught with Meteor. And if you don't like it, you don't have to follow it :)

@leocavalcante
Copy link

Thanks @markoshust
Splitting client from server code is what I've doing a long before Meteor (I guess everybody did/does), going back to this way of thinking isn't a problem at all. I was just confused about using Meteor and coding "against" its ideas, but as you emphasized, it was how MDG thought and things are changing.

@achtan
Copy link
Contributor Author

achtan commented Feb 1, 2016

i'm kinda agree with @mquandalle

@tjmonsi
Copy link

tjmonsi commented Feb 1, 2016

I think for me, if you are creating something that will be put in the
modules folder inside the client folder, then i have to agree that we
should just put client code in there and not mix it with server code.

If you are going to put the modules folder inside the import, then i guess
it would be best to have both the client and server in the modules folder
PROVIDED that you want to create "mini-apps" or "mini-plugins" that you can
just install and use either from the client or from the server.

And from there, you can publish it to npm, which is akin to just putting
the folder inside the imports/modules to npm_modules. By just using npm
install, you can "install" a module or plugin (may it be fully client like
reusable react ui components, or fully server like a full feature api with
database management, or a feature that has a client component and server
api)... Then just use import {needed} from 'installedmodule';

On Tue, 2 Feb 2016 04:49 David Ďurika notifications@github.com wrote:

i'm kinda agree with @mquandalle https://github.com/mquandalle


Reply to this email directly or view it on GitHub
#3 (comment).

@PEM--
Copy link

PEM-- commented Feb 2, 2016

I really don't like this idea of separating client code from server code when we are dealing with JS 😬 This reminds me so much of bad practices: code rewriting, mixed responsibility, team shouting match, project management euphoria... This clearly defeats the whole purpose of using a common language on the server as well as on every clients. Yerk.

For dealing with different targets and bringing more stuff on the table for capable devices, we should use coding/design patters. AOP, for instance or simple directive.

There's not 1k flavors per device for each Linux kernel release. Though you can install it on almost every iot, smartphone, computer, server, grid and even fridge. They are using simple pragma and macro. Just like we can do it with UglifyJS or SweetJS.

@natecox
Copy link

natecox commented Feb 2, 2016

@pem with respect, most of the problems you're addressing are almost certainly the result of tightly coupling the server with the client.

By drawing a distinction between the code which operates the server, and the code which powers the client, you are actually allowing for a much greater freedom of mobility in your code, and dramatically reducing boilerplate code and rewrites on large projects. You are allowing yourself the freedom to have your server power your web app, native apps, et cetera without bloating each client's install with the specific needs of a release candidate.

Meteor has always had a clear distinction between client and server at this point, which was muddled only by documentation. For example: Meteor.method definitions are the clear domain of the server, and are designed to be executed in blocks that the client never sees, but rather the client is given a separate API call for accessing them.

What mantra is doing is drawing a clear philosophical distinction, rather than simply a technical one.

@PEM--
Copy link

PEM-- commented Feb 2, 2016

@natecox Meteor.methods are for the client & the server. This is the core principle of optimistic UI 😉

And nope, this is not an issue with tight coupling. On the contrary. Splitting client and server code is like claiming that HTML / JS and CSS have been created for avoiding coupling. In the end, we all know where it ends. That the core essence of React 😄

I strongly prefer the isomorphic approach where you develop a use case from end to end. It's far clearer. For instance, I can tell you that being able to make a whole payment process in a single module is amazingly productive and clear. It would be mumbo jumbo splitting into modules for the client A, the client B, the server, the shared parts... blablabla.

@natecox
Copy link

natecox commented Feb 2, 2016

@pem What you're describing is monolithic, rather than isomorphic. Isomorphism simply describes that all of the app assets are written in a single language.

The dichotomy here is between modularity and monolithism. I would content that writing monolithic apps decreases clarity, understanding and therefor productivity by eschewing the single purpose principle. Instead of focusing on doing a single thing and doing it well, you're focusing on doing everything in the same spot. This leads to unrelated code being colocated, a more complicated structure and less ease in perusing code.

How this comes up in the code itself is a grab-bag. I feel that a strong separation of client and server is a good thing, but I also think it can be represented in multiple ways. A strong feature-oriented modularity in the total app itself goes a long ways, and I personally feel that including a server/ directory inside of that module isn't the end of the world.

As a side note: Meteor.method called on the server and on the client are designed to do two different things: on the server it denotes an actual method and is responsible for hitting the database and so forth, while on the client it denotes a stub (a fictitious element that outputs what you think should happen and is clobbered by the server method which is what has actually happened). That's the definition of 'optimistic ui' and absolutely supports the notion of server/client separation at a fundamental level.

@PEM--
Copy link

PEM-- commented Feb 2, 2016

@natecox Well, it's a point of view. I strongly prefer the use case view. It's more natural for my flow of programming. The framework should make the effort of reusing, splitting, optimizing. We could just put stuff for orienting it like we do with Meteor.isClient / Meteor.isSever. In essence, my point of view is that a framework should value feature productivity over architecture for its user. While, under the hood, using strong patterns (especially the creational ones instead of the behavioral ones) for easing its extensibility.

@natecox
Copy link

natecox commented Feb 2, 2016

@pem everyone is entitled to their point of view, of course. There's more than one way to do everything in programming. That being said, Mantra has clearly established itself in the camp of modular, non-universal, opinionated architecture.

It's probably not what everyone wants from Meteor, but just taking a look at this repo over the past several weeks I'm convinced that there are lots of us who agree with it and I wouldn't suggest that we change fundamentally to try to please everyone's point of view. There were a few things in the making that I didn't initially agree with either, but keeping an open mind and being willing to explore them I have generally reversed those opinions.

@arunoda
Copy link
Collaborator

arunoda commented Feb 3, 2016

@PEM--, @natecox sum it up. Yes. We've more places to improve. But, we need to take some decisions where not everyone agrees.
That's the nature of an opinionated stack. It's for the greater good.

@tierralibre
Copy link

Hello Arunoda,
Thank you so much for such great work. Personally I am very excited
about this.
Looking forward to the tutorials on mantra and the courses. Roadmap
looks amazing!
Kind regards,
Angel
On 2/3/2016 at 5:20 AM, "Arunoda Susiripala" wrote:

@PEM-- @natecox sum it up. Yes. We've more places to improve. But, we

need to take some decisions where not everyone agrees.
That's the nature of an opinionated stack. It's for the greater good.

Reply to this email directly or view it on GitHub.

@arunoda arunoda changed the title what about directory structure? What about directory structure? Feb 3, 2016
@arunoda
Copy link
Collaborator

arunoda commented Feb 3, 2016

Hi all,

I'm happy to close this issue after some great work. Now we've a module system as we discuss.

@arunoda arunoda closed this as completed Feb 3, 2016
@mquandalle
Copy link

Sorry @arunoda but I still can’t understand your reasoning about modules being unable to define features for the server. Your sample application for instance has a module called “comments”. On the client, the stub methods are defined inside the module whereas the corresponding real methods are defined in the global context outside the module on the server.

I would totally buy that this inconsistent architecture between the client and the server is due to some technical limitations of the Meteor bundler. Meteor indeed doesn’t offer much control about where we put files and I would agree that for now it is easier to put everything that is related to the server on a server/ directory and similarly for the client. However you are not saying that is a temporary organization motivated by technicals limitations, you are saying that this is the desired shape of the module system, and despite reading all your messages here and linked blog posts, I still don’t understand the arguments in favor of that.

@arunoda
Copy link
Collaborator

arunoda commented Feb 3, 2016

@mquandalle Shall we open a new issue for this?

@tonyxiao
Copy link
Contributor

@arunoda do you have examples for how to distribute modules via npm?

@arunoda
Copy link
Collaborator

arunoda commented Feb 11, 2016

@tonyxiao not yet public. Only think I'm finding hard to do it the CSS packaging. If that's done, we are good to go.

@philohelp
Copy link

Inline styling ? I like the "CSSmodules" specs...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests