Domain-Driven File Structuring -React/Redux

By Hassan Djirdeh

A blurb from Vaughn Vernon in Implementing Domain-Driven Design (2013) has a fantastic explanation to what Domain-Driven Design is:

The software development approach called Domain-Driven Design, or DDD, exists to help us more readily succeed at achieving high-quality software model designs. When implemented correctly, DDD helps us reach the point where our design is exactly how the software works.

To break it down further, DDD focuses on using a common Ubiquitous Language shared between domain experts and developers to structure an entire application through Domain Models. Domain Models are software models of a very specific business domain that you may find yourself working on. It’s often implemented as a small, very focused object model where the object has data and behaviour with accurate business meaning.

There are numerous benefits to DDD, ranging from a better understanding of the business, better organized code to even a better user experience. Fully implementing DDD is an iterative approach that continuously requires thought and effort between team members, domain experts and the business to converge to a common design approach. I by no means cover everything DDD related but I hope to show how I adopted a DDD approach in structuring a React/Redux application scaffold.

Domain-Driven React/Redux?

Forking through example scaffolds for React/Redux applications, I often find directories to structure themselves based on the nature of files (e.g. actions, components, reducers). A directory for a simple shopping cart app may resemble something like this:

src/
actions/
CartActions.js
ProductActions.js
components/
Cart.js
Product.js
ProductList.js
containers/
CartContainer.js
ProductContainer.js
reducers/
CartReducer.js
index.js
ProductReducer.js
App.js
routes.js

A fairly straightforward scaffold. Now, if I find myself needing to add information for a new domain (e.g. the login domain that encompasses a user logging in); I would have to add files to the actions, components, containers and reducers sub-directories; which would yield something like this:

src/
actions/
CartActions.js
LoginActions.js <--
ProductActions.js
components/
Cart.js
Login.js <--
Product.js
ProductList.js
containers/
CartContainer.js
LoginContainer.js <--
ProductContainer.js
reducers/
LoginReducer.js <--
CartReducer.js
index.js
ProductReducer.js
App.js
routes.js

A feature change within a particular domain or the creation of a new domain would involve going through multiple subdirectories, which could lead to poor maintainability in the long run. For a large complicated application, this isn’t the most efficient way for file structuring.


How about we modify the above directory with a domain-driven mindset? Looking at our directory we can understand that there are four distinct domains.

  • App
  • Cart
  • Login
  • Product

So we’ll probably get something like this:

src/
app/
App.js
routes.js
reducers.js
cart/
Cart.js
CartActions.js
CartContainer.js
CartReducer.js
login/
Login.js
LoginActions.js
LoginContainer.js
LoginReducer.js
product/
Product.js
ProductActions.js
ProductContainer.js
ProductList.js
ProductReducer.js

In terms of readability, it’s now pretty evident the different domains that exist within the entire application. Creating a new domain would simply involve adding files to one subdirectory instead of multiple and any feature changes would be contained closely together.

If you have components that are to be used across multiple domains, they can be grouped in a common folder within the app domain:

src/
app/
App.js
common/
Button.js
Card.js
Form.js
Modal.js

routes.js
reducers.js
cart/
Cart.js
CartActions.js
CartContainer.js
CartReducer.js
login/
Login.js
LoginActions.js
LoginContainer.js
LoginReducer.js
product/
Product.js
ProductActions.js
ProductContainer.js
ProductList.js
ProductReducer.js

And when it comes to structuring test files, you could arrange the spec files within the main src folder:

src/
...
...
...
product/
Product.js
Product.spec.js
ProductActions.js
ProductActions.spec.js
ProductContainer.js
ProductContainer.spec.js
ProductList.js
ProductList.spec.js
ProductReducer.js
ProductReducer.spec.js

Or have a separate test directory that mimics the src directory:

src/
...
...
...
product/
Product.js
ProductActions.js
ProductContainer.js
ProductList.js
ProductReducer.js
test/
...
...
...
product/
Product.spec.js
ProductActions.spec.js
ProductContainer.spec.js
ProductList.spec.js
ProductReducer.spec.
js

Is this worth it?

This blurb highlights a simple introduction on how you’d be able to implement the concept of domain models within your React/Redux directory structure.

There are probably reasons as to why one shouldn’t go about structuring React/Redux applications with a domain-driven mindset (e.g. having one reducer/action for multiple components may affect the way you initially structure the application). There are also plenty of other DDD concepts that may align better for a traditional MVC framework than React.

However, I believe the benefits to this approach greatly outweigh any potential concerns and make medium to large scale applications a lot more friendly and maintainable. It’s definitely at least worth a try!


Edit: Someone pointed out a similar blog post done by François Zaninotto which goes deeper and touches upon merging your container/presentational components in one file. A great read as well! -> https://marmelab.com/blog/2015/12/17/react-directory-structure.html

Check me out on Github, LinkedIn or my page.