Destiny is an open-source project available on npm that scans folders for file dependencies and places the files in a fractal structure, where they are “destined” to be.
The fractal tree concept
Consider a square. Now put two smaller squares on top of it, such that all three make a triangle in the center. Apply the same process to both smaller squares (and again, and again, depending on the number of files), and you have a fractal tree.
Destiny takes the same approach to structuring files. If a file has a dependency, it is moved to a folder with the same name as the file. It follows the principle that states, “Repeat the unit until all dependencies are structured, one below another.”
Benefits of a fractal file structure
Fractal allows you to:
- Focus on your code and not worry about the dependencies
- Manage complex file structures
- Scale faster
- Avoid the time-consuming task of restructuring your project manually
When multiple people are working on a single project, it’s sometimes difficult to get on the same page in terms of the file structure. Often, a programmer will simply search for all the dependencies in a project to understand the file structure format. The goal of Destiny is to create a common understanding of the file structure so development teams can work more efficiently together.
Below is the fractal representation of a file structure.
index.js is the main file and
footer.js are the dependencies of that main file. Ideally, the dependencies are placed inside a folder named
index, which is the same as the main file name.
How Destiny works
Destiny scans the selected folder and places files according to their dependencies. It follows the steps outlined below to restructure the dependencies.
- Scan the selected folder
- Create a fractal representation based on the directed graph
- Move the files inside the fractal app structure
To better understand how Destiny works, I created a project that demonstrates the file structure before and after using Destiny.
Structure before using Destiny
As you can see, this file structure is a fiasco. No one could possibly understand how the dependencies exist in the project without going through all these files individually.
Now let’s take a look at our project’s dependency graph.
There are multiple dependencies organized in a multilevel hierarchy for our
footer.js are dependencies of
header.js has dependencies of its own.
Now let’s see how Destiny transforms the file structure.
Structure after using Destiny
After creating a fractal structure using Destiny, our project will look as follows. The yellow box represents a folder with its name written inside.
This is how the files should be structured in a fractal manner.
Now let’s see what it looks like after applying Destiny to our project. You can simply traverse the file structure and understand the relationships and dependencies between the different components. For example, the index folder contains both a header and a footer. Furthermore, the header consists of a nav component that contains both a login button and a search bar. Easy, right?
│ ├── footer.js
│ ├── header
│ │ ├── nav
│ │ │ ├── loginButton.js
│ │ │ └── search.js
│ │ └── nav.js
│ └── header.js
Using Destiny from the CLI
It’s very easy to install and use Destiny in your project. If you use npm, write the following command to install Destiny globally.
npm i -g destiny
If you use yarn, use the following command.
yarn global add destiny
To use Destiny in a folder:
destiny <path to source files> # example destiny ./src
If you’re using Destiny in a React project, install Destiny and use the following command to scan all files and folders in your
npx destiny "src/**/*.*"
The structure has not yet been applied with this command. To do so, you need a
write flag to apply the changes. You can either use
- w or
--write to apply the file structure changes.
npx destiny -w "src/**/*.*"
What if there is a certain file that is required for both
footer.js but not
Destiny counters this problem very easily. A new folder called
shared is created under the
index folder, generating the
/index/shared path. Here, the shared dependencies are located next to the highest dependent file.
In the above graph,
footer.js have a dependency named
_button.js (placed inside curved brackets). This
button.js file must be moved to a new folder under the index folder.
After using Destiny, this is how the file structure should look:
As the graph shows, the fractal structure has been applied by Destiny and files have been placed accordingly.
This is what our folder tree looks like now. Below is the structure of a shared dependency project.
│ ├── footer.js
│ ├── header.js
│ └── shared
│ └── button.js
Other popular file structures
There are many other file structure formats out there, including:
- Model-view-controller (MVC)
- Organize by functionality
- Organize by type
The MVC pattern
Organized by functionality
In essence, when you organize by functionality, you organize files according to the functional areas of your application. For example, all functionalities related to handling emails go into an
You can scale this approach further by grouping more specific functionalities within your higher-level functional folders. For example, let’s say you’re hosting a feature for sending and displaying emails. You can further divide the
Organized by type
When you organize files by type, you get a very similar approach to MVC. A type can be a service, controller, domain, or any other type of file, such as a database model. However, as your application grows, you’re cound to accumulate services. Therefore, when organizing by type, you’ll end up organizing by feature within your type folders to keep your file structure clean.
Destiny was created by developer Ben Awad to manage a file structure for React applications. In the beginning, the tool was called butter-CLI before being changed to Destiny.
In most cases, when a developer starts a project, the project is tidy and well-structured — all files and folders are in their correct place and dependencies are managed properly. But as time passes, it becomes a much bigger effort to keep your file structure clean and tidy. You might move functionalities between components and create many shared folders. Often, you’ll end up with a whirlpool of files and their shared dependencies.
Destiny is designed to help you manage files on a large scale and make the file structure easy to understand for other developers working on your project. As of this writing, Destiny has a solid following with more than 2.7k stars on GitHub and 16 contributors.
LogRocket: Full visibility into your web and mobile apps
LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.