Scaling Redux part 1: Codebase Organization

Uttam Kini
Jul 20, 2017 · 4 min read

React and Redux have radically changed the way we look at front end development. These frameworks encourage you to write code in a certain way. For example React encourages you to write small components and compose them into a bigger widgets and applications. Redux forces you to separate state from components. There are some areas where these frameworks have no opinion. For example, React does not tell you how you need to split your app into smaller components and Redux does not have an opinion on how to organize the state tree. As your codebase grows with more complexity being added to your application, these questions start becoming more important. I was a part of a team that adopted React and Redux quite early on an existing complex single page application and we learnt a few lessons . This post focusses on codebase organization.

The Organize by Abstraction Style

When I started learning Redux, all the tutorials which I read had similar directory structures; They were organized by the technical abstraction in Redux (reducers, containers, actions, components). This is a style that rails originally popularized and it is a great way for beginners to internalize the abstractions of the framework.

.
├── ActionTypes.js
├── actions
│ ├── AccountActions.js
│ ├── HeaderActions.js
│ ├── OrderActions.js
│ └── UserActions.js
├── components
│ ├── Account.js
│ ├── App.js
│ ├── Footer.js
│ ├── Header.js
│ ├── Order.js
│ └── User.js
├── containers
│ ├── AccountContainer.js
│ ├── HeaderContainer.js
│ ├── OrderContainer.js
│ └── UserContainer.js
└── reducers
├── AccountReducers.js
├── HeaderReducer.js
├── OrderReducer.js
├── RootReducer.js
└── UserReducer.js

It has the following problems as your codebase becomes bigger
* It has low cohesion, i.e. files related to each other are kept away from each other.
* With a large number of files, names can get ambiguous and it is hard to jump to the right file quickly.
* You need to create and manage a lot of files (one for each abstraction) and switch between them when you are working

The Organize by UI Structure Style

An alternative way to organize the codebase is by the ‘domain’ or ‘feature’.
If you have programmed in Django, this style will be familiar to you. The key difference from a backend app is that that the ‘domain’ in a front end app is the way information has been laid out in the UI. This can exactly be the same as the ‘domain’ in the api/backend for simple apps, but for a complicated business app the backend/api domain and the UI structure start diverging depending on the how the user experience is designed.

.
├── ActionTypes.js
├── App.js
├── RootReducer.js
├── account
│ ├── Account.js
│ ├── AccountActions.js
│ ├── AccountContainer.js
│ ├── AccountReducer.js
│ └── user
│ ├── User.js
│ ├── UserActions.js
│ ├── UserContainer.js
│ └── UserReducer.js
├── footer
│ └── Footer.js
├── header
│ ├── Header.js
│ ├── HeaderActions.js
│ ├── HeaderContainer.js
│ └── HeaderReducer.js
└── order
├── Order.js
├── OrderActions.js
├── OrderContainer.js
└── OrderReducer.js

In the above example the codebase is organized on how the information is laid out in the UI and not on how the backend/api is structured. For example the User.jscomponent is inside the accounts/user directory and not in its own top level directory because the UI is structured that way. Here,

* Related code lives together (high cohesion)
* A developer can understand the UI structure of the application by looking at the directory structure and vice versa (know exactly where to change stuff to fix a defect).
This structure still does not solve the problem of too many files.

Ducks to the rescue !

That is where the Ducks pattern comes to the rescue. It is a style where related reducers, actions and action types live in one file. The above directory structure then becomes

.
├── App.js
├── RootReducer.js
├── account
│ ├── Account.js
│ ├── AccountContainer.js
│ ├── AccountDuck.js
│ └── user
│ ├── User.js
│ ├── UserContainer.js
│ └── UserDuck.js
├── footer
│ └── Footer.js
├── header
│ ├── Header.js
│ ├── HeaderContainer.js
│ └── HeaderDuck.js
└── order
├── Order.js
├── OrderContainer.js
└── OrderDuck.js

As you can see, the ‘Duck’ has subsumed ActionsTypes.js and every Action and Reducer file. Related action types now live with the action that they are related to (higher cohesion). The only caveat with this pattern is that you will run into circular import situations quite easily if the action from one duck is consumed by another. The workaround there is to have a rule that all duck imports from another duck should be always local.

This ends this post. This is not the only thing that will help you scale your codebase. There is other stuff like organizing state and reducing boiler plate which I shall cover in future posts.

Further Reading:

)

Uttam Kini

Written by

Solver of problems concerning people and software, compulsive wikipedia reader

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade