Arborescence, structure et nommage


  • Respecter une structure "LIFT" : Localiser le code rapidement, Identifier le code en un coup d'œil, Faire en sorte de garder une structure aussi plate que possible, Tenter de rester DRY (don't repeat yourself)
  • Localiser : pouvoir rechercher et trouver un fichier rapidement, particulièrement important à long terme lorsque quelqu’un d’autre que vous devra apporter des modifications à l’application.
  • Identifier : Nommer les fichiers de façon à comprendre directement leur utilité dans l’application. Préférer des noms longs et descriptifs plutôt que des abréviations qui auront moins de sens.
  • Flat structure : essayer de garder une structure aussi “plate” que possible. Il est plus facile de chercher dans un dossier contenant quelques fichiers que dans un dossier contenant une multitude de sous-dossiers. Au-delà de 7 fichiers, il est cependant préférable de faire des sous-dossiers.
  • Tenter de rester DRY (don’t repeat yourself) : ne pas être redondant dans les noms de fichiers, afin de rester le plus clair possible (pas de "product-view.component.html", on se doute déjà que c'est une vue car on est dans un fichier HTML).


  • Faire des sous-modules pour mieux séparer le code et permettre d’implémenter du lazy-loading sur les modules pouvant être routés.


  • Faire un ou plusieurs modules partagés selon le besoin, afin de regrouper les éléments partagés dans toute l’application ainsi que les fonctionnalités utilisées au sein de plusieurs modules. Exemples : AngularMaterialModule pour stocker tous les imports/exports des composants de la librairie Angular Material, SharedModule pour stocker des composants réutilisables de l’application (des listes, des formulaires génériques…)


  • Faire des data-services ayant spécifiquement pour objectif de communiquer avec le serveur


  • Suivre la convention de nommage des fichiers : d’abord le nom de la fonctionnalité, séparé par des tirets si besoin, puis son type (feature.type.ts).

Les types conventionnels sont les suivants : .service, .component, .pipe, .module, et .directive.

Quelques exemples :

  • products-list.component.ts
  • product.component.ts
  • products.module.ts
  • products-routing.module.ts
  • products.service.ts


  • A l’intérieur d’un fichier, le décorateur utilisé doit correspondre au type de fichier, et le fichier ne doit contenir que cela (pas de mélange de plusieurs classes ou interfaces dans un fichier). De cette façon, la structure de l’application est simple à comprendre.


  • Déterminer quelle stratégie de gestion du state mettre en place selon ses besoins : ngrx, services, routing...


  • Faire un choix entre Template Driven Form et Reactive Form et n’utiliser qu’une seule méthode partout dans l’application.


  • Configurer le projet pour éviter les ‘../../../../’ dans les chemins de fichiers pour les fichiers .ts et .scss


angular.json

	(...)
    	"sourceRoot": "src",
	(...)
           "stylePreprocessorOptions": {
              "includePaths": [
                "src/app/styles",
              ]
            },
	(...)


Sources : https://angular.io/guide/styleguide


Performance


  • Toujours unsubscribe toutes les subscriptions : Utiliser par exemple une class ObservableComponent pour gérer la destruction des subscriptions de façon générique.


  • Utiliser trackBy dans les *ngFor 

Améliore les performances lors du rendering de grandes listes


  • Eviter de mettre trop de logique côté template


Exemple 1

Au lieu de ça :

<p>Total guests : {{ total + 10 }}</p>

Ecrire plutôt :

<p>Total : {{ totalGuests }}</p>

Et gérer la logique du calcul du total côté TS.


Option 1 : utiliser une propriété supplémentaire, et la mettre à jour quand cela est nécessaire selon la logique du composant.

Option 2 : utiliser un getter

get totalGuests(): number {
	return this.total + 10;
}

De cette façon, le code est plus lisible, maintenable et réutilisable.


Exemple 2

<h1>{{ getTitle() }}</h1>

Ecrire plutôt

<h1>{{ title }}</p>

Et calculer title côté TS lorsque cela est nécessaire (sur le ngOnChanges si c’est un Input, à l’initialisation si cela n’est jamais amené à changer, dans certaines méthodes si nécessaire…). Ainsi on s’assure que l’affichage du template ne sera pas ralenti par l'exécution d’une fonction.


  • Gérer manuellement la détection de changement si besoin (ChangeDetectionStrategy OnPush)


  • Ne pas faire des Pipes customisées avec une logique de filtrage ou de tri. Ce sont des opérations coûteuses, qu’il vaudra mieux gérer dans le composant ou le service avant de lier les données au template.


  • Faire attention aux animations, elles peuvent avoir un fort impact sur la fluidité de l’application.


  • Garder un oeil sur les librairies externes dont certaines fonctionnalités peuvent impacter la performance globale