When we take the first steps in project creation, we need to make many fundamental decisions. One of those steps is a project structure. The project structure is the foundation. The correctness of the choice affects the introduction of new functionality into the project, support, onboarding new people into the project, etc.
In this article, I would like to review structure's approaches for Frontend applications, especially React-based ones. React-based examples are interesting to review because the folder structure and project organization are very different from project to project.
There are many ways to organize your project structure. Some developers do not pay enough attention to the structure of the project, placing files without logical connection. Some developers even write JS code in one file. But the purity of our code starts with the project structure. I will describe my experience using different approaches, the impact on the team and development time, and more.
When you define a project structure and choose a repository approach, you should understand your project goals, the approximate team size, business development paths, etc.
Let's start our journey with the repository.
The vast majority of projects are regular GIT repositories. React Component, Website, Single Page Application, Backend API, whatever!
Working in a regular repository is usually focused on speed. With this approach, the team has a mix of backend, frontend, QA, Business Analyst specialists, as well as an assigned Product Owner or Project Manager. So that, the team is completely independent and holistic, but at the same time small.
Code splitting is minimal with this approach. For example, when making a website, the project is divided into 2 repositories - SPA, Backend API. Or the frontend part is stored in the server repository. The work going forward, without worrying about versioning.
It is a collection of GIT repositories. We can move the UI into a separate repo and use it in several applications, micro services, reusable parts, etc.
This approach is great for large projects. For projects where we build an ecosystem of many applications. As soon as we choose this approach, it is very important to understand that each repository must have its own command. The team should be like a full-fledged unit, have its own QA, product owner, etc.
In a multi-repository approach, versioning and understanding breaking changes are very important. Your teams, assigned to their own parts of the system, use other parts of the system as a black box. If the UI command changes the interface of the components, then many applications that depend on these changes will stop working. At the same time, using versioning, the transition to the new version will have a smoother transition.
It is worth considering that working with multi repositories we can speed up the development process by doing tasks in parallel, increasing the speed. At the same time, due to separate commands for the repository, the costs increase. Integration between major versions becomes more difficult as changes are likely to affect other teams.
This is a repository that includes related modules
This is a kind of balance between logic separation and simple implementation. Large projects like Babel, React-Router have a mono repo system. Thus, it is easier to add new modules, there is no need to worry too much about backward compatibility, since the current version is taken as a basis, as in option Monolith.
This approach allows you to avoid unnecessary pull requests, for example, you have updated the UI library and you need to update this dependency in all applications. In the monorepo approach, you only need one PR to accomplish this. In many repos, you need to create a PR for all repos where the dependency needs to be updated.
This approach is good for a small team on a fairly large project.
The project folder structure should be as intuitive as a map. Showing where and what you have. We will look at examples in SPA React applications.
This approach is suitable when you are developing a React module that will integrate into your application. For example, you are making a chat that will be embedded in the site. In this case, the components that will make up the chat will be independent, have their own local state, and will be used by the index.jsx file as a generated module.
This approach is offered in many frameworks like AngularJS, Angular 2+, etc. I bumped into this approach often both in React and in various other programming languages, especially on the Backend.
In large applications, the contents of folders become a dump. It is very difficult to find the required file and determine the dependencies.
Separation by features promotes the idea of separating business logic from the presentation by bringing logic into independent and independent units - features.
In this example, we see the routes folder, which corresponds to the routing of the application and collects the entire page structure, components, and interaction with features.
Features are separated from views. This is a set of logic dealing with state and callbacks that will be delegated to components on routes.
An example of this approach can be found at the link
I would especially like to note that with the advent of React hooks, this approach fits very succinctly into the structure of the application. The example above uses hooks.
A couple of years ago, a friend of mine and I were working on a large project called Cleverbrush. It was a startup, we had no money, we needed to release a production-ready application as soon as possible.
Since the Cleverbrush project consisted of several applications (graphics editor, photo collage, admin panel, and landing page), we used the Monorepo approach to bring common parts such as UI, utils, etc. into separate packages. Monorepo allowed us to work faster if we worked in different repositories.
The folder structure reflected the approach of separating features from views, much like the example.
This allowed us to separate our business logic and delegate it to components.
Also, we had to develop many components from scratch, for this purpose we used the folder structure of option Separation into components.
Thus, we mixed different approaches to achieve maximum quality, minimize time to our project.
As with all aspects of application development, there is no silver bullet, no one right approach. It all depends on the team, project, time, money. Experiment! Consult with colleagues as the project structure affects the entire team. All good mood and interesting projects!