nodejs
application project layouts
The project layout follows a set of conventions around the project's codebase structure. Such conventions can be adopted by a team, or taken verbatim from the community of developers. This article will explore commonly adopted nodejs
applications projects layouts.
In this article we will talk about:
- Minimalist layouts
- Multi-repository layouts
- Mono-repository layouts
- Modular layouts
Even though this blog post was designed to offer complementary materials to those who bought my Testing
nodejs
Applications book, the content can help any software developer to tuneup working environment. You use this link to buy the book.
Minimalist layouts
The minimalist layout applies to the simplest programs. Such programs may take from one file to a couple of files, preferably under 10 files. Anything that goes beyond 10 is subject to reach 100 or even 1000 down the road. Minimal projects can be liberal on the choice of the name of files, as the directory structure is not really needed. The rule of thumb is YAGNI. It makes sense to take as a few files as possible, as long as we do not have an idea how big the program has to grow. Categorizing files by type(category) under these circumstances makes complete sense. Example of type (category) file structure may looks as /utils.js
, /index.js
etc.
When the applications start to grow, meaning beyond 10+ files, then it makes complete sense to organize files under directories. The question is, should we take a category approach such as /utils/index.js
, controllers/index.js
, or does it makes more sense to organize files by utility(feature), for instance /inbox/utils/index.js
or catalogue/models/index.js
? The next paragraphs will provide clarity on this.
Project layout by category
There are multiple categories of small programs that make a software suite running. When those are sliced following the layered architecture(models, views, controllers, services, etc), the project structure becomes by category(or by kind). In the early days of a project, when there is no clear specialization, it makes sense to keep it simple and organize directories by category.
The problem becomes a little messier, when requirements about adding an inbox, or catalog, or any other major feature gets added to the project. The next paragraph shows how we can specialize in directory structure as features get added to the project.
Project layout by feature
It may take a little longer to realize how organizing projects by features the application has to provide is really simple, or easy to track project progress. When a new major feature is added to a project, it makes it hard to isolate or detect how far the project is getting done, by simply looking at the project layout. The file organization by feature makes it clear how many features are in a project.
There are some concerns that this strategy may make code reusability a challenge, if not a mess. When you look at it, those concerns are perfectly legit. For example, the /inbox
feature may be having model/user.js
. By the time /admin
feature gets added to the project, it is almost guaranteed that /admin/model/user.js
and /inbox/model/user.js
will certainly be representing the same thing. There should be an approach that makes sharing cross-feature code feasible. That is how a hybrid project layout comes into play.
Feature/Category Hybrid project layout
The hybrid model combines what is the best in both project ” layout by feature” and ” layout by category”. The starting point is the feature-based project layout. Let's take an example where a feature is a catalog (or inventory) for instance. The catalog may have a controller, model, service, and a bunch of views. Using the minimalist approach, as long as the catalog has only one controller, one model one service, and one view, those single categories can be made .js
files, otherwise directories. Let's assume that further iterations require adding inventory, and both the inventory and catalog share the product model. One thing we want to avoid is to have a dependency between inventory and catalog, so it makes sense to add a directory where shared code can be stored. Such directories have recognizable names such as: /common
, /core
, or /lib
. Our product model can be moved to /core/models/product.js
. It worth highlighting that /core
is in this case organized by category and not by feature. This closes our case of hybrid project layout.
Multi-repository layouts
The multi-repository layout is often based on git's workspace model. A parent project may inject other projects managed by git
. Individual projects can be organized by category or by feature, or a mix of both(hybrid). The evident use case is when we have Backend code, SAP for frontend code, a bunch of migration scripts, or even programs such as Widgets and CLI.
Mono-repository layouts
The mono-repository, also known as monorepo
approach makes monolyth
sexy and easy to work with. The monolyth
put all programs under one roof, which makes it hard to deploy especially in a CI environment or when dependencies are tightly coupled. monolyth
are those applications that have a database, business, and rendering logic embedded not only in the same repository but also running at the same time when deployed. They are hard to maintain, depending on how big the project turns out to be, and they are quite a challenge to adopt monolyth
when a program is being shipped multiple times a day.
Modular layouts
The modular approach is more aligned with what npm
and nodejs
's /node_modules
have to offer. Each and every top-level directory(-ish) can serve as an independent complete application module.
Conclusion
In this article, we revisited various project layout schemes and assessed requirements to adopt one over the other. We barely scratched the surface, but there are additional complementary materials in the “Testing nodejs
applications” book that digs deeper into the subject.