Defining any kind of “good practices” in tech is always a tricky business. Good practices are subjective, heavily dependent to your ways of working and often your personal preference. The best we can do is try to rely on the experience of others and learn from their mistakes.
Starting out with Redux can be quite daunting and figuring out the best way to group the bits and pieces of your application into a sensible folder structure can be tricky. Having been on three green-field React Redux projects in the last year, I have some musings to bestow, regarding the different approaches we’ve taken to end up with what is our “best shot so far”.
Similar to the three pigs building progressively sturdier houses, we gradually arrived at solutions providing better maintainability and a more efficient developer experience. From beginning with straw, progressing to wood and now iterating further with stone, here is our story.
The Straw House: Standard Layout
On the very first project, the whole team was new to Redux. And to be honest, Redux was new to the world (ride the wave.). We played it safe and went with a standard layout, as described in Dan Abramov's amazing (and FREE) Egghead videos.
This is the obvious layout and the one that’s most people’s go-to: group the same ”type” of things together. It’s a brilliant starting point, but when working on large applications, it becomes pretty clear that this layout does not scale. Suppose we have a ToDo list application and consider the user adding a new ToDo item. You would probably have a ToDoItemList /component, a ToDoItemList /container, an ADD_TODO /action, a todoItems /reducer and if you need to make API calls to save your ToDos, a ToDoList /saga. That's an awful lot of files scattered about the codebase that are ultimately working on the same task. Besides, some things just belong together: you'd never use the ToDoItemList container with a different component so should they really be living in different parts of the codebase?
The Wooden House: Group by Feature
In the second project, having learned some good learnings from our straw house approach, we decided to do a 180: rather than separating all of our Redux bits based on what they do, we grouped them all together by the feature in which they belong. We also had a /components folder for pure functional components that could be shared between different features.
This layout minimises jumping around in the codebase when developing features. It worked really well to begin with, however after a while it became clear that the lines between features are blurred. How do you draw the line between User, Account and Profile? Are they all the same feature? It is also easy to end up with just one or two bulky “features” that encompass the entire application.
The Stone House: Group by Function
The stone house layout basically appeared by letting the codebase grow naturally. From the start, we did the minimal possible amount of work ONLY for the feature at hand, refactored A LOT, paid great care not to optimise too soon and added groupings and abstractions only when needed. We are now 4 months into the project and this is what we’ve come up with:
Whereas this way of laying out the application may look a bit hard to grasp initially, it’s worked out really well for us so far. Grouping different “types” of files together isn’t a new idea. After all, in most React applications, test files and css files live in the directory of the component they belong to.
We are by no means finished evolving our stone house and would love to hear about other ideas. If you have a different type of house (folder layout) than any of the ones listed here, we’d love to hear about it.