Skip to content

Commit a80b0a5

Browse files
n0mad-d3vFilledStacks
authored andcommitted
docs: translate in-depth/services.md
1 parent 866e56e commit a80b0a5

File tree

1 file changed

+169
-0
lines changed
  • i18n/fr/docusaurus-plugin-content-docs/current/in-depth

1 file changed

+169
-0
lines changed
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
id: services
3+
title: Services
4+
sidebar_label: Services
5+
sidebar_position: 3
6+
---
7+
8+
9+
# Qu'est-ce qu'un Service ?
10+
11+
En plus d'avoir une View (qui fait le rendu notre UI) et un ViewModel (qui contient toute la logique de l'état de la View), nous avons également des Services. Un service, en termes simples, est la classe qui effectue ou orchestre le vrai travail. Il existe deux types de services.
12+
13+
14+
## Types de Services
15+
16+
Nous avons un Facade Service et un App Service. _En fait, nous recherchons de meilleurs noms, alors n'hésitez pas à collaborer si vous êtes intéressé._ Regardons d'abord le service qui "fait le travail réel".
17+
18+
### Facade Service
19+
20+
Un facade service englobe un autre package pour supprimer la dépendance forte de notre codebase et "fait le travail réel". Regardons le problème que cela résout en examinant l'exemple ci-dessous :
21+
22+
```dart
23+
class HomeViewModel extends BaseViewModel {
24+
List<Artist> _artists = [];
25+
26+
Future<void> fetchArtists() async {
27+
// #1: Structure la requête http
28+
final response = await http.get(Uri.https('venu.is', '/artists'));
29+
30+
// #2: Valide si la réponse est un succès
31+
if (response.statusCode < 400) {
32+
// #3: Convertit la réponse en map
33+
final responseBodyAsMap = jsonDecode(response.body);
34+
35+
// #4: Récupère les informations utiles de la réponse
36+
final artistMaps =
37+
responseBodyAsMap['data'] as List<Map<String, dynamic>>;
38+
39+
// #5: Désérialise en une liste d'artistes
40+
_artists = artistMaps.map(Artist.fromJson).toList();
41+
}
42+
}
43+
}
44+
45+
class Artist {
46+
final String name;
47+
final String coverImage;
48+
49+
Artist({required this.name, required this.coverImage});
50+
51+
factory Artist.fromJson(Map<String, dynamic> data) => Artist(
52+
name: data['name'],
53+
coverImage: data['coverImage'],
54+
);
55+
}
56+
```
57+
58+
Dans le code ci-dessus, on peut voir que "le travail effectué" est entièrement effectué par le `HomeViewModel`. Cela signifie que le `HomeViewModel` a la responsabilité de structurer et d'effectuer la requête http (#1), de vérifier qu'elle a réussi (#2) et de désérialiser la réponse en une liste d'artistes (#3, #4, #5). C'est assez courant en Flutter. En fait, dans la plupart des cas, on vous apprend à le faire dans votre fonction `initState` 🤯🤯, ce que, si vous êtes sur cette page, je vous supplie de ne jamais faire.
59+
60+
C'est là que le Service de Facade intervient. Le `HomeViewModel`, comme tous les autres ViewModels, est là pour gérer la logique de l'état de l'application et maintenir l'état de la View. Il ne devrait pas effectuer le travail réel mentionné ci-dessus. Pour résoudre cela, nous introduisons un service qui englobe tout cela pour nous. Voici à quoi nous voulons que cela ressemble dans notre modèle mental :
61+
62+
![Stacked architecture breakdown that shows what code does the actual work](/img/tutorial/services-who-does-the-work.png)
63+
64+
Comme indiqué par le bloc rouge, la View et le ViewModel ne doivent pas effectuer de travail. Ils délèguent au service, où tout le travail réel est effectué. Regardons un exemple. Dans votre projet Stacked, exécutez :
65+
66+
```shell
67+
stacked create service api
68+
```
69+
70+
Cela générera une classe `ApiService` et l'enregistrera dans le service locator, créera le fichier de tests unitaires et enregistrera le mock de ce service pour les tests unitaires. Dans le `ApiService`, nous pouvons maintenant créer une version typée du travail qui était effectué par le ViewModel. Nous allons tout déplacer dans une fonction appelée `getArtists` qui nous renvoie une `List<Artist>` :
71+
72+
```dart
73+
class ApiService {
74+
Future<List<Artist>> getArtists() async {
75+
final response = await http.get(Uri.https('venu.is', '/artists'));
76+
if (response.statusCode < 400) {
77+
final responseBodyAsMap = jsonDecode(response.body);
78+
final artistMaps =
79+
responseBodyAsMap['data'] as List<Map<String, dynamic>>;
80+
return artistMaps.map(Artist.fromJson).toList();
81+
}
82+
83+
throw Exception('Response Code: ${response.statusCode} - ${response.body}');
84+
}
85+
}
86+
```
87+
88+
Maintenant que nous avons englobé la fonctionnalité (et l'implémentation) du package dans un Service, nous pouvons l'utiliser dans le `HomeViewModel` :
89+
90+
```dart
91+
class HomeViewModel extends BaseViewModel {
92+
final _apiService = locator<ApiService>();
93+
List<Artist> _artists = [];
94+
95+
Future<void> fetchArtists() async {
96+
_artists = await _apiService.getArtists();
97+
98+
// Utilisez artistes ou extrayez un état supplémentaire, par ex.
99+
// empty state, multi select, etc ...
100+
}
101+
}
102+
```
103+
104+
Rien de plus n'est nécessaire pour créer un Service de Facade. Avec ce petit changement, votre code bénéficie des avantages suivants :
105+
106+
- **Séparation des responsabilités / Responsabilité unique** : Vous avez maintenant séparé la responsabilité des requêtes http, de la désérialisation, de la vérification des erreurs et de la construction du modèle du ViewModel. Le ViewModel peut maintenant se concentrer uniquement sur la gestion de l'état pour la View.
107+
- **Plus facile à tester** : Comme la dépendance forte sur le package Http a été supprimée, cela signifie que vous pouvez mocker l'ApiService et écrire des tests unitaires déterministes pour votre ViewModel.
108+
- **Code DRY** : Tout autre ViewModel ou Service qui nécessite cette fonctionnalité peut simplement `locate` le service et utiliser la fonction `getArtists`. Pas besoin de la dupliquer ailleurs.
109+
- **Lisibilité du code** : À notre avis, le code semble clair et il est facile de voir très rapidement ce qui est attendu sans avoir à voir la construction des requêtes http et la complexité de la désérialisation de la réponse dans une liste distincte.
110+
111+
Ce modèle est au cœur de l'attrait de Stacked. Dans presque toutes les situations, les experts de Stacked recommanderont de "Créer un service et l'appeler dans votre ViewModel".
112+
113+
114+
### App Service
115+
116+
Un App Service (faute d'un meilleur nom) est l'endroit où réside votre logique métier. Ces types de services orchestrent l'interaction entre les Facade Services pour accomplir une certaine business logic (métier). Prenons par exemple un `ArtistService` qui a une fonction qui fait ce qui suit :
117+
118+
- Vérifie si un utilisateur est connecté
119+
- Récupère des artistes lorsqu'un utilisateur est connecté
120+
- Enregistre les artistes dans la base de données locale lorsqu'ils sont renvoyés
121+
122+
C'est ainsi que nous voulons que cette "Fonctionnalité" apparaisse dans notre modèle mental :
123+
124+
![App Service orchestration using Facade Services](/img/tutorial/services-app-service-orchestration.png)
125+
126+
Nous créons une fonction dans la classe `ArtistService` qui utilise nos Facade Services pour déléguer le travail réel à effectuer. Voyons à quoi cela ressemble en code. _Ce code suppose que les autres services sont déjà créés. Il ne s'agit pas d'un exemple complet de création d'un service Auth ou d'un service DB, mais illustre simplement comment utiliser ces services._
127+
128+
129+
Dans votre classe d'App Service, le `ArtistService`, ce que vous ferez est :
130+
131+
- Localiser les Services requis en utilisant le `locator` _Documentation sur le `locator` à venir !_
132+
- Utiliser leurs fonctionnalités pour orchestrer la logique métier
133+
134+
135+
En code, cela se traduit par ce qui suit :
136+
137+
```dart
138+
class ArtistService {
139+
final _databaseService = locator<DatabaseService>();
140+
final _authenticationService = locator<AuthenticationService>();
141+
final _apiService = locator<ApiService>();
142+
143+
Future<List<Artist>> getArtists() async {
144+
// Vérifier si l'utilisateur est connecté
145+
if (_authenticationService.userLoggedIn()) {
146+
// Récupérer les artistes depuis le backend
147+
final newArtists = await _apiService.getArtists();
148+
149+
// Sauver en base de données
150+
await _databaseService.saveArtists(newArtists);
151+
152+
return newArtists;
153+
}
154+
155+
throw Exception('User must be logged in to see artists');
156+
}
157+
}
158+
```
159+
160+
Nous localisons chacun des services, puis utilisons leurs fonctionnalités pour atteindre notre objectif. Cela rend notre processus de développement de fonctionnalités très clair et facile à lire lorsqu'on regarde nos App Services.
161+
162+
163+
Ceci conclut notre définition des Services.
164+
165+
---
166+
167+
## Nous sommes prêts pour le Web 🚀
168+
169+
Maitrisez Flutter pour le web avec le [cours Flutter Web](https://masterflutterweb.carrd.co/) officiel.

0 commit comments

Comments
 (0)