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

Route driven pod structure #44

Closed
wants to merge 3 commits into from

Conversation

chadhietala
Copy link
Contributor

@chadhietala chadhietala changed the title Route driven project structure Route driven pod structure Apr 3, 2015
@ultimatedelman
Copy link

i think this is a step in the right direction!

@trabus
Copy link

trabus commented Apr 3, 2015

Overall, a HUGE 👍 for this.

What I love about this is that covers the three concerns that I've seen from investigating what people want from pods:

  • project discoverability
  • easily identifiable file names
  • separating concerns of route specific ui and shared ui (and data, see below)

I'd like to see where models fit into this, specifically those with associated adapters and serializers. Maybe something like this, where data is similar to shared and houses concerns related to data:

app
├── data
│   └── adapters
│   │   └── profile.js
│   ├── models
│   │   ├── profile.js
│   │   └── user.js
│   └── serializers
│       └── profile.js
├── routes
│   ├── profile
│   │   ├── components
│   │   │   ├── member-photo.js
│   │   │   └── member-connections.js
│   │   ├── styles
│   │   │   ├── member-photo.scss
│   │   │   └── member-connections.scss
│   │   ├── templates
│   │   │   ├── member-photo.hbs
│   │   │   └── member-connections.hbs
│   │   ├── edit
│   │   │   ├── components
│   │   │   │   └── edit-name.js
│   │   │   ├── templates
│   │   │   │   └── edit-name.hbs
│   │   │   ├── styles
│   │   │   │   └── edit-name.scss
│   │   │   └── profile-edit.js
│   │   └── profile.js
│   └── admin
│       ├── components
│       │   └── member-permissions.js
│       ├── templates
│       │   └── member-permissions.hbs
│       ├── styles
│       │   └── member-permissions.scss
│       └── admin.js
├── helpers
│   └── format-date.js
├── initializers
│   └── tracking.js
├── services
│   └── tracking.js
├── utils
│   └── fib.js
├── shared
│   ├── components
│   │   └── dropdown-menu.js
│   ├── templates
│   │   └── dropdown-menu.hbs
│   └── styles
│       └── dropdown-menu.scss
├── app.js
└── router.js

@samselikoff
Copy link
Contributor

I'm doing something similar now under /pods, and the extra components, templates and styles dirs do concern me a bit. Though I understand the pain of having x number of component.js files. I've still found Ctrl+P useful to search, though, because I just search by component name then start typing "component.js".

Here's one of the most deeply nested components in my current project:

image

It'd be rough if there were the extra dirs at every step, but, maybe it wouldn't be that bad.

In any case, I absolutely support having a directory that's exclusively for UI code and whose structure mirrors the hierarchy of your actual app's UIs. Again I've been doing this with /pods and it's made navigating the project very simple and intuitive.

I also second @trabus's remark about a top-level /data directory for models, adapters and serializers, since these aren't tied to the UI hierarchy and are shared throughout the app.

@opsb
Copy link

opsb commented Apr 3, 2015

I've held off moving to the pod structure for the findability issues, this looks great!

Regarding coarse bundling, I'd expect to see models etc. nested inside the routes directory. There is the possibility that models don't have matching routes though so I'm not sure how that would look.

@mgenev
Copy link

mgenev commented Apr 3, 2015

+1 I really like this, I also really like the proposal by @trabus about putting the data in its own place

@cascalheira
Copy link

+1 Sounds good. Also second @trabus sugestion.

@jamesleebaker
Copy link

+1 MUCH better.

@trabus
Copy link

trabus commented Apr 3, 2015

I wanted to note, it was pointed out that this is really more of a hybrid approach between pods and the type based structures. The fact that the files are consistently named by the name (rather than the type OR name) is huge IMO. We may actually want to call it something other than pods, since there has already been some establishment around what they are currently. It could be confusing to have to refer to new pods vs old pods.

It'd be rough if there were the extra dirs at every step, but, maybe it wouldn't be that bad.

I really feel that the consistency in naming plus grouping by concern is worth the tradeoff of some possible extra dirs. I also think maybe using more generalized components in the shared folder should be leveraged as much as possible to minimize the amount of nesting necessary. I feel like that much custom ui would be more of an uncommon use case.

@samselikoff
Copy link
Contributor

we could also just put hbs + js + scss in the same file... :trollface:

but seriously

@ultimatedelman
Copy link

^ get this guy outta here :D

@2468ben
Copy link

2468ben commented Apr 3, 2015

+1
@trabus @samselikoff Yeah I'd love either of your structures to be default, both way better than what we have.

What if the one option people had was grouping the files in each route by type or component? And if you choose to group by component it would still be member-photo.js and member-photo.hbs in the same folder, so they'd keep the name in the file like @trabus said.

@samselikoff
Copy link
Contributor

I'm confused where nested components would live, the OP shows components nested 1-level deep from each route. I have an app that doesn't use a lot of routes but still has a lot of complexity in the UI hierarchy, so I have components nested 5 or so layers deep (see the screenshot in my comment above). Where would these live?

For example say I want to render the {{lesson/questions-module/multiple-choice-question}} component. lesson is a route, but the others are both components. If I create a new dir within lesson, how can we tell whether it's a component or a route? Would resolver take care of that?

app
└── routes
    └── lesson
        ├── lesson.js
        ├── lesson.hbs
        │   
        └── questions-module
            ├── questions-module.js
            ├── questions-module.hbs
            │
            └── multiple-choice-question 
                ├── multiple-choice-question.js
                └── multiple-choice-question.hbs

@2468ben
Copy link

2468ben commented Apr 3, 2015

@samselikoff I guess in the OP's case there might have to be a routes subfolder alongside the components and templates one.
In your version where it's grouped by name and not filetype, you're right that's confusing even if the resolver can magically figure what's up.

@2468ben
Copy link

2468ben commented Apr 3, 2015

Sorry I meant your example right there. The screenshot you use at TED clearly avoids all that.

So with all these nested folders, will people's primary way of finding a file be searching in Sublime/Vim/some other editor? If that's the most likely way, then I don't mind as long as it works well with searching. Like searching "components/profile" or "profile/component" or "profile/profile.js".

@jamonholmgren
Copy link

Would using an extended extension work a little better?

app
├── routes
│   ├── profile
│   │   ├── member-photo.component.js
│   │   ├── member-photo.style.scss
│   │   ├── member-photo.template.hbs
│   │   ├── member-connections.component.js
│   │   ├── member-connections.style.scss
│   │   ├── member-connections.template.hbs
│   │   ├── edit
│   │   │   ├── edit-name.component.js
│   │   │   ├── edit-name.template.hbs
│   │   │   ├── edit-name.style.scss
│   │   │   └── profile-edit.js
│   │   └── profile.js
│   └── admin
│       ├── member-permissions.component.js
│       ├── member-permissions.template.hbs
│       ├── member-permissions.style.scss
│       └── admin.js

Just thinking out loud here. I know this is not particularly desirable, but the deep-deep nested structure conjures scary images of ZendPHP to me.

@csantero
Copy link

csantero commented Apr 3, 2015

👍 for @jamonholmgren's idea. I see three advantages over the original proposal:

  1. It reduces the total number of folders
  2. It lets you tell with a glance at just the filename what that file is for. In editors that only show the filename this can be really handy.
  3. All the files for a given component are implicitly grouped because of alphabetical ordering, making related files easy to find.

Based on the communities feedback we want to have the template, js, and
styles grouped togeather in a single folder.  The only option that makes
since to keep this feature is to have repetition in files and folders on
disk. While verbose this solution achieves the findability issue and keeps
the spirit of the original "pods".
@sglanzer-deprecated
Copy link

The vast majority of our application is written in shared components, so I'm most interested in the proposals impact to that structure.

I haven't had a big issue with the current pod structure, but @jamonholmgren's idea would be a nice incremental improvement.

@RuslanZavacky
Copy link

I am with @sglanzer - I see no big problem with current structure, it makes sense when you are writing different application with the same modules.

I'd like to discuss/question all different approaches and problems that they try to solve.

@chadhietala

Findability - this problem is kinda "imaginary", each IDE helps easily to find any component by just writing "buzz/c" or "buzz/t" to find template, etc.
In your proposed structure, you'll need to write "member-photo.js" or mem-ph.js" to find the right file, as the extension really matters. So its the same in terms of findability, as the current solution.

To separate app into bundles is the good way to go, to have different bundles, with the separate built files in the end. But it requires only 1 sub-folder to current changes to achieve that, and not changing all the structure.

Shared bundle is not the really good choice to go with. If you will have big application, with different bundles and each bundle will need to extend special component and customize it for bundle needs, storing it in app/ structure will loose main point of separation of concerns. Components should be bundles with some part of the application, like UserManagement, and not just be "flying" around. UserManagement can be bundle that will be extended for app bundle and admin bundle and will have some methods extended.

<profile.edit@edit-name> - its kinda far away from simple html structure and web components.

Please ask yourself a question "What problem do you want to solve and is it a real problem and not imaginary?"

As we are using pod structure in no so small application, I'd really like to see solving of real problems, and not just improving by breaking current structure.

@nathanhammond
Copy link
Member

@RuslanZavacky and others, the needs for this sort of architecture are many-fold and not limited to simply "findability" and "alignment with routable components." There are supporting reasons throughout the rest of the RFC, which I've enumerated here and explain below:

  • Findability
  • Alignment with Routable Components
  • Segmentation of Applications
  • Direct evolutionary path to Engines
  • Automatic namespacing of components
  • Discrete workspaces for larger teams

With that list of reasoning, I don't find it particularly debatable as to the need, making our goal here to identify the global maxima for the best possible structure of Ember's future file layout (wherein the somewhat-existing pod structure and original layout each have their own drawbacks).


Findability

Scores of files named identically is a confusing use case in at least some of the tools that we all use. This cannot be hand-waved away unless we intend to write additional code to ensure developer happiness in every possible environment. We should find the optimal tradeoff here in terms of communicating information about the project declaratively and obfuscation via numbers of files and folders. I believe that @chadhietala's approach does a decent job approximating this.

Alignment with Routable Components

Routable components are coming. We need to start accounting for this eventuality within our application layout. This starts to make components feel like a first class citizen under a route instead of merely stuck there because of default rendering behavior.

Segmentation of Applications

By making applications "flat" we have no way of inferring interdependencies in build tools without either having the developer declare their intentions or doing (likely incorrect) static analysis. This can rapidly get out of hand in medium to large applications. @chadhietala discusses this when talking about coarse bundling. There are many possible benefits to this, primarily lazy-loading segments of the app or including sections as third-party code.

Direct evolutionary path to Engines

The segmentation forced by scoping everything to routes enables us to view this as a step toward having engines as a core part of Ember.

Automatic namespacing of components

If you're building a large enough application (possibly especially with routable components), component name collisions will occur, requiring namespacing. If components are scoped to the route in which they appear this avoids the collisions.

Discrete workspaces for larger teams

It is inevitable with Engines that users will want the ability to create a single host application with the ability to launch other applications at mounted routes. Each one of those mounted apps is effectively a discrete workspace for some large portion of the final product and can, in many cases, be developed in isolation from the other components (deep-linking being a cross-cutting concern). This is a step in the right direction in avoiding coordination between teams working inside of the same global application but in their own (not-so-)tiny world.

@jamonholmgren
Copy link

Regarding findability, as someone new to Ember, I think it's helpful to see examples of where my confusion lies with the current pod structure, and why having pod name + type info in the filename would be helpful. I'm using the current pod structure, and due to the anonymous way files are generated, here's what I look at in Sublime:

pod-screen-shot

It's hard to tell what controller that is.

I get around it by doing this:

pod-screen-shot-2

Now I know what controller I'm looking at, but I've gone away from the generated (and presumably recommended) coding style.

With the pod name in the filename, it becomes more obvious:

pod-screen-shot-3

@sglanzer-deprecated
Copy link

Prodding @jamonholmgren's proposal a bit, I think a few elements are missing (route template/style) and I'm wondering if we need the explicit component/style/template extensions when js/scss/hbs would sufficiently distinguish these files. Any opinions on the following adjustments? I am assuming the components nested in route directory would be scoped to the route and not available outside. The base level components would be available globally. Also, no idea if the '-route' is necessary for to support the dash requirement for components.

Partial expansion (1):

app
├── components
│ ├── custom-button
│ ├── custom-table
├── routes
│ ├── profile
│ │ ├── components
│ │ ├── edit
│ │ ├── profile-route.hbs
│ │ ├── profile-route.js
│ │ ├── profile-route.scss
│ ├── admin

Partial expansion (2):

app
├── components
│ ├── custom-button
│ ├── custom-table
├── routes
│ ├── profile
│ │ ├── components
│ │ │ ├── member-connections.hbs
│ │ │ ├── member-connections.js
│ │ │ ├── member-connections.scss
│ │ │ ├── member-photo.hbs
│ │ │ ├── member-photo.js
│ │ │ ├── member-photo.scss
│ │ ├── edit
│ │ │ ├── components
│ │ │ ├── profile-edit.hbs
│ │ │ ├── profile-edit.js
│ │ │ ├── profile-edit.scss
│ │ ├── profile-route.hbs
│ │ ├── profile-route.js
│ │ ├── profile-route.scss
│ ├── admin

Fully expanded:

app
├── components
│ ├── custom-button
│ │ ├── custom-button.hbs
│ │ ├── custom-button.js
│ │ ├── custom-button.scss
│ ├── custom-table
│ │ ├── custom-table.hbs
│ │ ├── custom-table.js
│ │ ├── custom-table.scss
│ │ ├── row
│ │ │ ├── custom-table-row.hbs
│ │ │ ├── custom-table-row.js
│ │ │ ├── custom-table-row.scss
├── routes
│ ├── profile
│ │ ├── components
│ │ │ ├── member-connections.hbs
│ │ │ ├── member-connections.js
│ │ │ ├── member-connections.scss
│ │ │ ├── member-photo.hbs
│ │ │ ├── member-photo.js
│ │ │ ├── member-photo.scss
│ │ ├── edit
│ │ │ ├── components
│ │ │ │ ├── edit-name.hbs
│ │ │ │ ├── edit-name.js
│ │ │ │ ├── edit-name.scss
│ │ │ ├── profile-edit.hbs
│ │ │ ├── profile-edit.js
│ │ │ ├── profile-edit.scss
│ │ ├── profile-route.hbs
│ │ ├── profile-route.js
│ │ ├── profile-route.scss
│ ├── admin
│ │ ├── admin-route.hbs
│ │ ├── admin-route.js
│ │ ├── admin-route.scss
│ │ ├── components
│ │ │ ├── member-permissions.hbs
│ │ │ ├── member-permissions.js
│ │ │ ├── member-permissions.scss

Also, just throwing this out there, but are there any ideas worth stealing from BEM or SMACSS? These approaches have been very effective in organizing global namespaces for CSS projects.

@ultimatedelman
Copy link

@sglanzer i like your directory structure. i think it makes the most sense and is more or less what i've had in mind for what i hope our final structure looks like. +1.

however, let's be careful about what CSS methodology-du-jour we think about picking. i would vote against BEM based on the fact that a) it creates rigid, confusing (and ugly) markup, and b) it's extremely presentational. it might be good for a small project, but obviously for a project of our scope i feel it would do more harm than good. i don't know much about SMACSS but from the little i've read, it seems to rely mostly on presentational class names.

@drogus
Copy link

drogus commented Apr 13, 2015

While I like the idea of different naming for files in pods, I'm not sure about a move to routes directory. Splitting this RFC into 2 may be a good idea.

@chadhietala
Copy link
Contributor Author

Hoping to have a summary and steps forward on this RFC this week.

@Panman82
Copy link

Honestly, I'm fine with the current pod structure. I just wish Sublime and other editors would show the folder name along with file name (not the whole path, just parent folder name). Ex: foo/route.js

IMO, adding the route name to the file name becomes redundant and wordy. Along with the refactoring inconvenience (changing the route name), which I have done a couple times.

Combining all the JS into one file (route/component) just doesn't seem right either. Again, current pod structure works for me. But nesting components needs improvement yet (if not done already).

BTW, would this PR be more relevant for the ember-cli/rfc's? https://github.com/ember-cli/rfcs/pulls

@yonjah
Copy link

yonjah commented Apr 15, 2015

@Panman8201 are you using latest Sublime version ?
At least for me (3083) if I open two files with the same name sublime show only the path diff (which is usually just the parent folder )

@walter
Copy link

walter commented Apr 15, 2015

At least for me (3083) if I open two files with the same name sublime show only the path diff (which is usually just the parent folder )

emacs 24.3.50.2 with ido makes the path diff distinction as well. In the past it would distinguish files with the same name by adding a number increment to it. Nice improvement to see where the file is coming from.

@Panman82
Copy link

@yonjah Not on my ember dev machine, I'll give the update a whorl. Thanks!


## Automatic Namespacing

As of Ember 1.10.0, components can be nested we have the ability to namespace modules based on the route in which the component is contained in. For example, using the `member-photo` component would look like the following.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel namespacing is a engine concern. for local isolation, components should be able to yield forward otherwise private or local components and helpers: Some exploration here: https://gist.github.com/stefanpenner/86812ac262414232285c

@chadhietala
Copy link
Contributor Author

Update

After meeting with several core team members about this RFC, we feel that this RFC tries to address too many concerns at one time. Besides the findability issues, the spirit of this RFC is isolation. There are 3 types of isolation primitives we want in Ember: local/private scoped helpers & components, pods, engines. Instead of going down the road of taking an intermediate step towards isolation via a route centric directory structure, it is probably better to simply begin work on engines to introduce the concept of isolation at a route scope.

In terms of findability, structures presented in this RFC should be re-assed once the isolation from engines has landed. The reason for this is that engines would provide the namespace making resolution via the resolver much more reasonable. This RFC will be updated to focus more on the issue of pods themselves instead of taking on the isolation problems that engines and local/private scoped helpers and components intend to solve.

@rwjblue
Copy link
Member

rwjblue commented Jun 7, 2015

@chadhietala - Thank you for summarizing the specific points, we are going to close this for now and we can open a new RFC once Engines/Scoped Helpers/etc have been worked on.

@rwjblue rwjblue closed this Jun 7, 2015
@chadhietala chadhietala mentioned this pull request Mar 8, 2016
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

Successfully merging this pull request may close these issues.