Main Schools of Thought
Before we begin it helps to understand the main schools of thought seen in most major web frameworks.
Keep folder nesting to the minimum, and name folders in a general manner. Most notably seen in the Ruby on Rails web framework.
- Easy to understand.
- Easy to onboard new team members.
- As the project scales it can be hard to find the file you need in a folder with 20 or 30+ files.
- Naming conventions become paramount to avoid conflicts and navigate the project.
Group similar components or resources together in nested folders. Most notably seen in the Django web application framework.
- Once you understand how resources are related it becomes easy to find exactly what you need quickly.
- Naming conventions are much more lax.
- Can easily become a series of Russian nesting dolls that make it difficult to navigate and understand from a holistic view.
- More challenging to maintain.
- Longer period to onboard new team members due to the unique nature of each project.
As linear styled projects grow in size and complexity group similar resources together in well-named folders that contain at least 3+ files.
- Brings the best of both linear and fractal structures.
- Maintainable by default.
- Mostly straightforward on-boarding for new team members.
- It takes a bit of an adjustment to start thinking this way.
Frontends tend to lend themselves to an adaptive fractal structure depending on what framework you use. Because frontends usually involve React or Vue at the time of this writing we will focus on those. The recent release of Webpack v4 made the
dist folders the defaults to run webpack without a configuration file so we’ll accept those as our starting point. Here is a general overview:
src/ components/ services/ store/ views/
Keep reusable components separate from components used a single time as a page with
views folders. The
store/ folder is used if your application needs a state management tool like Vuex or Redux. The
services folder is less common but could help separate your request logic from your application.
In React projects, especially ones involving Redux, the src/components folder complements the fractal style. For each component you probably want a folder with the Redux container, React component and styling file. It should look something like this:
src/ components/ Navbar/ Navbar.js NavbarContainer.js (more commonly index.js) Navbar.spec.js main.css services/ user.js admin.js store/ actions.js configureStore.js reducers/ rootReducer.js user.js admin.js views/ Home.js Admin.js Login.js App.js main.js
This style works well with React and Redux because it helps keep the container logic separate from the component. Even the store works well with fractal as it keeps complex configuration files and reducers separate from the rest of the application.
For Vue projects, a more adaptive fractal style is preferred. Because Vue’s single file components can easily take advantage of scoped styles and a Vuex store is easily mapped to a component our project structure should reflect this:
src/ components/ Navbar.vue mixins/ plugins/ services/ user.js admin.js login.js store/ user.js admin.js views/ TheHome.vue TheAdmin.vue TheLogin.vue App.vue main.js
In Vue, components used only once are named with ‘The’ before it. Vue uniquely also has mixins and plugins so this structure reflects this, just as the React example had container files for reduxed components.
The backend should be separated from the rest of the application similar to
src/ on the frontend. The naming of this folder is debatable but most people settle on
app as this conveys that the folder encapsulates both the front and back end. I personally choose
server. Within this folder should be a file named either server.js or index.js as well as a routes.js file to keep all routes in one place. In a linear project the backend structure should look something like this:
server/ models/ controllers/ helpers/ routes.js server.js
A fractal backend structure tends to look like this:
server/ user/ model.js controller.js routes.js helpers/ routes.js server.js
I find the fractal structure tends to lead to repetition in a backend context. As you can see in the above example for a large scale project there needs to be more than one routes file and within each resource, you have to repeat the few lines to configure the express.Router. And because it’s fractal you have to search extensively through the server to find routes and discover relationships they may have with other parts of the application. This is not ideal and forces developers to globally search for that route while guessing its name.
Additionally here are some pretty common folders. The
assets/ folder is for stying assets like logos to be served via the backend. A
scripts/ folder holds any automated build tasks or generators your team may have created. And finally, the
test/ folder contains unit, integration, and end to end tests.
assets/ (or sometimes called public/) scripts/ test/
assets/ dist/ scripts/ server/ controllers/ helpers/ models/ routes.js server.js src/ components/ services/ store/ views/ test/ backend/ unit/ frontend/ unit/ e2e/