This is a response to Bill Fisher regarding experience with Flux:
@abdullin Also, can you clarify what you mean by "solution structure"? I am thinking about revising the examples soon.
Currently all flux samples (that I've seen) group files into folders based on technical similarity. For example, stores go with stores, action creators reside in the same folder shared with the other action creators.
This pattern works quite well for smaller projects. It feels especially good for the sample projects of various MVC frameworks, when you have just a bunch of controllers, models and views.
However, as we discovered on some production projects, such approach doesn't scale well. At some point you end up with dozens of technically similar files per folder and logically messy solution.
- Doesn't scale well.
- While you work on a component, you have to suffer from extra context switching overhead (jumping between various folders).
- Solutions become more "entangled" than needed.
- More complex IDE features are needed to support the workflow (e.g. context-aware navigation and completion).
- More merge conflicts, since it is harder to bound work by a feature (and communicate that).
We discovered that aligning solution with the domain model leads to a better design in the long run. E.g. we try to group files by their functionality or feature. This would mean, that different technical elements of a single feature could be squashed into one folder or onto one file. For example, for Flux we are considering to have a single folder for "News feed", which would contain all related action creators, fetchers and stores. Of course, there could be some other components that the this chat page would use (e.g. avatars, like buttons or user stores), such components would reside in their own folders. On the overall, such component decomposition is requires more effort than simply grouping files by class type. However, we value both the process (it leads to a deeper insight) and the outcome (solution that is more simple to think and reason about).
Of course, this is just something that seems to work only in a subset of cases I've been exposed to. There can easily be a deeper pattern which I fail to recognize.
This is a difficult problem, and I think it's similar to how we approach naming variables, objects or methods. In naming, it's important to focus on what the method does, or what the object is, rather than how we will use it. Naming according to use, rather than functionality, leads a team of engineers to accidentally write the same method twice. Uses change, but functionality is consistent.
Organizing view components, action creators, stores, and auxiliary utilities based on their logical domain would work well in some situations, but this obscures their cross-domain potential. Many parts of a Flux application can be cross-domain. For example, actions are not tied to a single store. We often have a list of FooActionCreators that correspond to a FooStore, but a BarStore could easily need to respond to one of the actions created by the FooActionCreators. Likewise, it's very likely that our controller-views will need to be listening to multiple stores.
When I'm hunting for an existing action creator, I'd prefer to be opening a single directory and then see a list of all the action creator modules in the application. This puts the entire application's API in a single place. I can only imagine how frustrating it would be to open the foo directory, not find what I'm looking for, and have to navigate out to the bar, baz and qux directories to find the right method.
Likewise, it's a good idea to keep the action types in a constants file. This way, when you open that one file, you'll see a list of every action type in the entire application. Lately I've been careful to name action types in the format of: DOMAIN_VERB or OBJECT_VERB, where the object is the thing being acted upon, and the verb describes what is happening. For example: MESSAGE_CREATE, MESSAGE_DELETE, IMAGE_SELECT, PLAYBACK_STOP. This naturally groups the action types in my constants file in a way that makes it easy to go back and find one.
I could more easily imagine the benefits or organizing React components based on their UI specifics. Again, however, when we build well-designed reusable React components, then we need to name them and organize them based on what functionality they really provide, rather than how we happen to be first using them.