protips

Logo

This site lists the protips that we shared with students during our courses

View the Project on GitHub appliedtechnology/protips

Project structure

Most applications that you write will consist of a large number of files and it can pretty soon be overwhelming to navigate the project.

This post tries to give a few simple tips on how to get a good start organizing your code. Writing about folder structure is a bit of a minefield since no one standard has emerged yet. I will, therefore, give generic tips and then pointers to suggestions and thoughts.

Generic thoughts

The main thing to think about when organizing the project is that the structure should be easy to follow along in- and easy to pick up when joining a development team.

Therefore you should always strive to group logical units together. This is related to making your modules cohesive (but with low coupling). For example, you want to put all the files for the API in the API-subfolder. You wouldn’t put client code in the server folder etc. This is easy to make up stupid examples about, but can also be a tricky trade-off sometimes.

In this document, I’m going to use an example with a SPA client, an API (that the client uses) and finally a server that serves up the different parts. But, again - I’m not going into too many details.

The root

In the root you first put things that concerns the entire project. This is a starting point for most developers and is displayed by default when navigating the project on, for example, GitHub.

Here are some of the more common items that are/can be found in the root

Don’t put too many things in the root since it makes it very tricky to navigate - only the things that belong & affect the entire application.

So: here’s what our ideal root directory would look like:

├── src
│   └── all the source code for our application
│
├── config
│   └── all the config that we'll need for our application
│
├── scripts
│   └── bashScript1.sh
│   └── bashScript2.sh
│
├── tools
│   └── tool1
│       └── tool.bin
│   └── tool.js
│
├── .gitignore
├── docker-compose.yml
└── README.md

The source code - src

The source code of the application should go in the src (or similar) folder. In this folder, you can further divide the application up into the parts that make up the application. For example:

I like to divide the API and the server but I can almost guarantee that they are others that would argue against that. My argument is that in this setup we can now build the server directory and it will be the mother application that we run to get the parts.

But just as a few examples that show how my opinion could be challenged:

Whatever solution you go for, make sure that the structure is clear and easy to understand and start.

So: here’s what the inside of our src folder could look like:

├── client
│   └── all the source code for our client
├── server
│   └── all the source code for our server
├── API
│   └── all the source code for our API
└── README.md

Root of each application

The package.json is the application manifest and is the marker for where an application lives. For example, the root of the server directory is where the server-application. Hence I would expect a package.json in this folder. This is also where the package-lock file will be generated.

Typically this folder also holds a starting point for the application (the "main"-section of the package.json-file). If you don’t have great reasons for other naming conventions, use the default convention in Node of index.js .

Another good reason for an index.js-file at the root of each folder is that you can use that as a gateway/entry point for code that references the folder.

For example, let’s say that I have a DB-folder with some database access code in. Maybe I can access two different databases and hence create a file (or a folder) for each: userDataAccess.js and ordersDataAccess.js. By adding a db/index.js in I can now expose the functions in a simple way like this:

const users = require('userDataAccess.js');
const orders = require('ordersDataAccess.js');

module.exports = {
  users,
  orders
};

The client code will now be very simple:

const db = require('./lib/db/');
db.users.getUserById(22345);

// or
const userDbClient = require('./lib/db/').users;
userDbClient.getUserById(22345);

An easy structure that helps our code to become more readable and useable. And still leaves room to grow in.

So: an example of a really bare bones server folder:

├── lib
│   └── db
│       ├── userDataAccess.js
│       ├── ordersDataAccess.js
│       └── index.js
├── index.js
├── package.json
└── package-lock.json

Components, routes, lib etc

Cohesive means that things that logically belongs together should be closely connected. When it comes to folder structure there are a few good examples for what that means:

├── components
│   └── navbar
│   │    ├── navbar.jsx
│   │    ├── navbar.test.jsx
│   │    └── navbar.css
│   └── map
│   │    ├── map.jsx
│   │    ├── map.test.jsx
│   │    └── map.css
│   └── app.jsx
│
├── index.js
├── public
│
└── ...and all the rest that a react app needs

As the application grows you might want to break the handling code further. Notice that my example has one userRoutes that have that code and another routes for all the other routes. Further down the line, I might move the userRoutes to a separate folder under routes/users and then make new folders with route-handling code for other needs. Only add complexity when you have a good need to do so.

Tests

The placement of tests is a debate that has been going back and forth quite a lot in the community. My suggestion is to place test code as close together with the production code (the code the test is testing) as possible. Which gives:

Generators

Many tools have generators for the most common frameworks like npx create-react-app or npx express-generator. For tools like these, it’s almost always better to follow the generated structure rather than to fight it with your own opinions.

Resources

As I promised here are some opinions on how to structure applications

Summary

There are many different opinions and ideas on how to structure an application/project. Whatever you decide to go with ensuring that you are always helping the person reading the code to easier understand and find what they are looking for. That person is very likely you in a month or two.