Application Structures
The folder structure of a project is very important. It helps you to organize your project in a better way. It also helps you to understand the project structure easily.
In this guide, we will discuss the folder structure of a project.
Minimal structure
The minimal structure proposed by the project consists of a simple source folder containing your business code.
The bin
folder is used to use the hmr
within your application during the development phase; so you should not delete
it.
├── bin
│ └── main.dart
│
├── lib
│ ├── events
│ └── commands
│
├── pubspec.yaml
└── .env
N-tier structure
When you're developing increasingly complex applications, you generally lose readability and maintainability and maintainability if you don't focus on a stable, future-proof software architecture.
One approach we recommend is the module-based architecture. This involves dividing your application into several business modules that are independent of each other.
We recommend the following structure.
├── assets
│ ├── image1.png
│ └── image2.png
│
├── bin
│ └── main.dart
│
├── lib
│ ├── commons
│ │ ├── helper.dart
│ │ └── api.dart
│ │
│ ├── module 1
│ │ ├── events
│ │ ├── commands
│ │ └── provider.dart
│ │
│ └── module 2
│ ├── events
│ ├── commands
│ └── provider.dart
│
├── pubspec.yaml
└── .env
To simplify the management of your modules, we recommend that you create a provider.dart
file within each which will
serve as the entry point for each module.
import 'package:mineral/api.dart';
final class Provider extends Provider {
final MineralClientContract _client;
Provider(this._client) {}
}
import 'package:mineral/api.dart';
final class Provider extends Provider {
final MineralClientContract _client;
Provider(this._client) {
_client.register(MyEvent.new);
_client.registerCommand(MyCommand.new);
}
}
final client = Client()
.setCache((e) => MemoryProvider())
.registerProvider(Provider.new)
.build();
Layered architecture
When we talk about modular architecture, we quickly come to hexagonal architecture. This architecture allows you to decouple the different parts of your application according to their core business and responsibility within it.
We recommend the following approach.
├── bin
│ └── main.dart
│
├── lib
│ ├── ui
│ │ ├── events
│ │ │ ├── ready_event.dart
│ │ │ └── message_create_event.dart
│ │ │
│ │ └── commands
│ │ └── foo_command.dart
│ │
│ ├── services
│ │ └── foo_service.dart
│ │
│ ├── data
│ │ ├── models
│ │ └── repositories
│ │
│ └── provider.dart
│
├── pubspec.yaml
└── .env
The above structure is an example that we recommend to help you adopt a modular, scalable and maintainable architecture by decoupling the different parts of your application as much as possible.
However, it will not always suit your business needs and will need to be adapted accordingly.
ui
: Contains the various parts of your application which are related to your business, includingevents
andcommands
.services
: Contains the services which allow you to manipulate the data in your application; they will generally be used from theui
.data
: Contains the DTOs and repositories that allow you to manipulate the data in your application. An example of use is the use of a remote REST service to which you need to make HTTP calls.provider
: The entry point of your module who's call under themain
file.
Hexagonal architecture
When we talk about modular architecture, we quickly come to hexagonal architecture. This architecture allows you to decouple the different parts of your application according to their core business and responsibility within it.
We recommend the following approach.
├── bin
│ └── main.dart
│
├── lib
│ └── application
│ │ └── tickets
│ │ ├── commands
│ │ ├── events
│ │ └── ticket_provider.dart
│ │
│ ├── domain
│ │ └── tickets
│ │ ├── entities
│ │ ├── repositories
│ │ ├── dtos
│ │ └── contracts
│ │
│ └── infrastructure
│ └── tickets
│ ├── repositories
│ └── dtos
│
├── pubspec.yaml
└── .env
The previous structure is an example of an implementation based on hexagonal architecture. business context from the rest of the application or external services in order to make it more testable but also to remove any dependency on external services.
bin
: Contains the entry point of your application.application
: Contains the various parts of your application which are related to your business, includingevents
,commands
,states
or any mineral component.domain
: Contains the entities, DTOs, repositories, contracts that allow you to manipulate the data in your application. He contains the business logic of your application and must not depend on anything other than itself.infrastructure
: Contains implementations that must interact with external services such as APIs, BDDs and queues. Each implementation must implement a contract defined in the domain.
You can find a sample implementation of this architecture here