Transert connaissances

1. SOLID

SOLID stands for:

S - Responsabilité unique (Single responsibility principle)
	une classe, une fonction ou une méthode doit avoir une et une seule responsabilité
O - Ouvert/fermé (Open/closed principle)
	une entité applicative (classe, fonction, module ...) doit être fermée à la modification directe mais ouverte à l'extension
L - Substitution de Liskov (Liskov substitution principle)
	une instance de type T doit pouvoir être remplacée par une instance de type G, tel que G sous-type de T, sans que cela ne modifie la cohérence du programme
I - Ségrégation des interfaces (Interface segregation principle)
	préférer plusieurs interfaces spécifiques pour chaque client plutôt qu'une seule interface générale
D - Inversion des dépendances (Dependency inversion principle)
	il faut dépendre des abstractions, pas des implémentations

Difference between SRD and ISP: https://stackoverflow.com/a/55073007/1565142

En très résumé:

  • une classe = gère un seul concept

  • private par défaut (fermé par défaut)

2. Design pattern

Objectif des design pattern:

  • donner des recettes éprouvées pour le développement de fragment élémentaires de programme.

Avantages:

  • promeut pratiques de dév communes: permet de favoriser l’uniformisation du développement (pas à 100% c’est pas m’objectif, mais on s’y retrouve plus facilement quand on passe sur un programme inconnu)

  • simplifie le dialogue entre développeurs (i.e. au lieu d’expliquer verbeusement ce que fait une classe, on peut utilise le mot du design pattern si elle en emploie une)

Attention:

  • à utiliser avec parcimonie (plus on utilise de DP dans son programme, plus le code a tendance à devenir technique - il faut trouver le juste milieu - qui ne viendra qu’après s’être fait longuement la main sur les DP et avoir failé à de très nombreuses reprises).

Liens:

Les plus communs:

  • Fabrique/Fabrique abstraite

  • Singleton (moins utile avec l’ioc)

  • Prototype

  • Adaptateur

  • Composite

  • Décorateur

  • Facade (pour savoir ce que c’est - bp en parlent/parlaient)

  • Stratégie

  • Commande

  • Itérateur

  • Observateur

  • Patron de méthode

3. TDD

  1. A quoi ça sert ?

    • on aura une meilleure qualité de TU (on teste ce qui est réellement utile fonctionnellement - on ne fait pas du test technique juste pour assurer la couverture de code)

    • on aura une meilleure qualité du code car meilleure testabilité du code (le code est conçu de manière à être plus facilement testé → favorise la décompsition et la ségrégation des responsabilités)

  2. Comment faire du TDD ?

    Résumé: on va écrire le code de test et à partir du code de test progressivement et on va écrire le main en fonction du test

    Etapes:

    • Compréhension du besoin

    • Conception

    • Lister les testcase (cas à tester)

    • Boucle TDD (en commençant par les cas les plus simples)

      • écrire le code du testcase

      • écrire/modifier le code du main jusqu’à ce que les TUS passent

      • refacto des testcase (et donc du main)

  3. Implications du TDD

    Connaître les raccourcis IDE pour générer du code

    sur intellij:

    - F2: view next error
    - ALT+ENTREE: fix current error
    - CTRL+F5: rerun last test
    - ctrl+alt+v: extract variable
    - ctrl+alt+m: extract method
    - ctrl+alt+f: extract field

    sur visual studio code:

    - ctrl + .: opérations de refacto
  4. Exemple 1 TDD

    On va créer un programme Echo qui va lire la sysin et écrire chaque mot en stdout Lorsqu’on écrit un mot en Q, on quitte le programme

    Conception:

    Reader {
    	String read();
    }
    Writer {
    	write(String);
    }
    Echo {
    	echo();
    }

    Liste des cas à tester (pour Echo):

    • l’utilisateur quitte le programme

    • l’utilisateur écrit qq chose

4. Back

4.1. Spring

Spring scanne au démarre toutes les classes contenus dans le ackage de la clase référencée par le SpringRunner + toutes les autoconfigurations (qui sont en général des librairies réutilisables).

Liens:

@RestController
@Controller
@Service
@Component
@Repository
@Named et @Singleton
@Configuration + @Bean (pour déclarer n beans)
! autoconf possibles
  1. Injecter ce bean via un champ ou une méthode annoté avec @Autowired/@Inject/@Resource ou via le contructeur (mieux pour les TUs et pour sentir quand il y a trop d’interdépendance - bref, qd le design commence à sentir mauvais)

Pour injecter:

  • soit via constructeur

  • soit directement dans l’attribut via @Autowired ou @Inject

4.2. Couche REST

@RestController
@PathVariable
@RequestParam
@RequestBody
@RequestMapping
ResponseEntity

@ControllerAdvice + @ExceptionHandler

TP: créer une application spring avec contrôleur REST qui appelle un bean service greetings. jouer avec les annotations (RequestMapping, PathVariable, ResponseEntity, RequestBody) i.e. GET /api?name=user, GET /api/{user}, PUT …​

4.3. Docker

  • qu’est ce que c’est, à quoi ça sert ?

  • dockerhub

  • lancer le helloworld

  • présentation des layers, et optimisation des images

  • TP: création d’une image de l’application Spring précédente et lancement googler pour le faire

    docker build .
    docker run <img> avec <img>: nom de l'image produit à la fin du build
  • divers
    différence image/container se connecter à un container existant, faire du apt install, etc…​

4.4. Application exemple 2: Gestionnaire de tâches

Objectif:

L’application va permettre à un utilisateur de créer des tâches.

Pour créer une tâche l’utilisateur doit indiquer:

  • quel est le type de tâche

  • configurer la tâche

L’application va gérer une liste de types de tâches.

Exemple de types de tâches:

  • Sysout: va afficher la configuration de la tâche en sysout

  • Grovvy: va exécuter le script groovy fourni par l’utilisateur (dans la configuration de la tâche)

  • HostStats: affiche l’état du serveur (cpu, etc…​) en sysout

De nouvelles versions de l’application pourraient permettre de proposer plus de tâches.

Il faut donc que ce soit un mécanisme extensible.

L’utilisateur pourra lister les tâches créer, les modifier et les supprimer.

Il pourra aussi demander l’exécution d’une tâche (il peut exécuter plusieurs fois la même tâche).

Il pourra ensuite consulter l’état des tâches lancées.

On doit voir à minima:

  • identifiant d’exécution

  • nom de la tâche

  • timestamp de début et fin de l’exécution

  • sysout/syserr

  • statut

  • stack d’erreur

4.4.1. Création projet back

⇒ spring starter

4.4.2. Conception

Task<<command>>
=> exécution ?
=> définition

Status
=> SUCCESS, SCHEDULED, RUNNING, ABORTED, ERROR

TaskRun
=> historique d'exécution d'une tâche
seulement avce status success, running, aborted ou error

TaskExecutor<ISP>
-> lance l'exécution d'une tâche (retourne un TaskRun)
=> une implémentation pourrait êxécuter en synchrone, une autre en asynchronevia background thread, une autre en async via kafka, etc...

TDD de
<ISP>
-> liste des tâches
-> création d'une nouvelle tâche

Task(Run)Manager<ISP> ?
-> liste des exécutions

TaskLog
- error
- sout

4.4.3. TP: développer en TDD de TaskManager

  • liste: si pas de tâche en base, alors retourner liste vide

  • liste: si tâche en base, alors retourner les tâches en base (liste paginée)
    ⇒ simplifié car au final on utilise juste un repo (un seul TU donc)

  • detail: visu détail tache, success

  • detail: si tache existe pas, alors Optional
    ⇒ simplifié

  • update: si tache existe, alors vérifier mak

  • update: si tâche n’existe pas alors NotFound

  • delete: idem update

  • create: prendre un taskType en entrée + nom dela tâche (pas de config pour le moment)

  • create: vérifier qu’une tâche de meme nom n’existe pas en db

4.4.4. Fonctionnalités supplémentaires

Si nous souhaitons continuer le développement, on peut imaginer:

  • pouvoir paramétrer le runner des tâches (i.e. synchrone, dans un thread en background, sur un autre serveur (i.e. kafka ?))

  • métadonnées de configuration (spécifique à chaque type de tâches)

  • types de tâches supplémentaires: groovy, etc…​

5. Front

5.1. Démarrer un nouveau projet

# update to latest version of ng cli
npm install -g @angular/cli@latest

# change node version
nvm install 14.17.6

# créer nouvelle version de projet angular
ng new

# installer material ou autre bibliothèque
ng add @angular/material

5.2. Coding style and folder structure

Liens:

On a adopté l’organisation suivrante dans COF:

src/app/core

src/app/features
	fonction1
	fonction2
src/app/shared
	comp1
	comp2

Le répertoire features contient les modules fonctionnels de l’application

Le répertoire shared contient les modules partagés (utilisés) par plusieurs autres modules de l’application

Le répertoire core contient les composants utilisés dès le démarrage de l’application (i.e. authentification, layout, …​)

Cette organisation permet:

  • promouvoir l’organisation fonctionnelle de l’application (chaque répertoire fils de features, et shared correspond à un nom/module fonctionnel - éviter le découpage technique)
    Donc on aura plutôt un découpage:

    src/app/features
    	objet-formation
    	formation

    Donc on aura plutôt un découpage:

    src/app/features
    	components
    	services
    	models
  • activer le lazy loading (sur les features)

5.3. Models ou pas de model ?

Perso, je suis pour la création d’objet model distincyts de l’API - sauf dans le cas d’une application très simple qui doit être développée rapidement ou jettable.

Ceci permet d’ajouter du comportement directement au niveau des models et simplifie la maintenance.

Dans COF, cela a permis d’éliminer du code dupliqué des composants angular en le déplacant dans le modèle

5.4. ngrx ou pas ?

A mon sens, déjà il faut bien maîtriser angular et rxjs avant d’envisager la mise en place de ngrx.

5.5. Types d’objet Angular

  • Composant

  • Service

  • Module

  • Router

  • Pipe

  • Resolver

  • Interceptor

Composant: - il s’agit dun composant graphique
→ favorise la réutilisation et le découpage en briques élémentaires de l’UI
→ utiliser SRP !!!

Service:

  • Singleton (en général)

Model:

  • Pas un composant Angular, mais correspond aux entities/value object de l’application du point de vue front certains projets utilisent les objets retournés par les APIs appelés (bof) d’autres projets créent leur modèle eux même (pour pouvoir ajouter du code)

Module:

  • permet de regrouper des classes Angular liées à une même fonctionnalité ensemble. un module va permettre d’exposer uniquement ce qui est censé être utilisé par l’extérieur et cacher ce qui est propre à l’implémentation de la fonctionnalité i.e. si pour développer une fonctionnalité 'lister les tâches', j’ai dû développer un composant liste de tâches mais aussi un composant colonne de la liste, alors le module exportera uniquement le composant 'liste des tâches' (celui pouvant être utilisé par d’autres modules)

Router:

  • permet de naviguer entre écrans/fragments d’écran

Pipe:

  • permet d’optimiser l’affichage de données élémentaires à l’écran

  • permet de réutiliser un même algorithme d’affichage
    i.e. afficher la monnaie

Resolver:

  • permet de pré-charger des données avant l’affichage d’une page.
    A utiliser avec parcimonie/soin, voire à éviter…​ Bof à mon sens car:

    • cela scinde artificiellement un composant en 2 (le composant ne pourra plus fonctionner sans son resolver) - on a donc 2 composants très fortement couplés

    • en général pas forcément utile d’attendre la récupération des données avant de démarrer l’affichage d’une page

Interceptor:

  • permet de faire des traitement avant/après une requête Ajax

5.6. rxjs

Tips sur Rxjs:

  • faire le plus simple possible (il faut se méfier des pipes avec 10 opérateurs rxjs)

  • si besoin d’échaîner bp d’étape, alors ne pas hésitez à scinder en étapes fonctionnelles (méthodes private avec des noms fonctionnels parlant)

  • quand on a fini d’écrire le pipe, il faut comprendre pouquoi on a utilisé chaque opérateur (ne pas utiliser au hasard)

  • lors de l’écriture du pipe, ne pas hésiter à changer les lambda (les écrire en multi-ligne si ça sert), à utiliser l’ide pour connaître le type de données en entrée et en sortie de chaque étape du pipe ⇒ une fois que ça compile faire du cleanp (i.e. multi-ligne ⇒ single line, etc…​)

Opérateurs les plus utilisés:

  • map

  • switchMap/mergeMap

Plus rare:

  • catchError

  • of

  • filter

  • forkJoin

  • takeUntil

A éviter:

  • pluck

5.7. Démarrer les dév

On va développer la partie front du projet back précédent (gestionnaire de tâches)

On utilise le client angular (ng cli) pour nous aider à créer les composants.

Une fois qu’on sera à l’aise, on pourra les créer à la main.

# créer un module core
ng g module core

# créer un feature module (avec routing)
ng g module features/task --routing

# créer un composant
ng generate c features/task/task-list --export -m features/task

# créer un service
ng g s shared/task

# installer les dépendances (à faire à chaque modif du package.json)
npm i

# démarrer application
ng serve

More CLI:

ng g class core/models/task

5.8. Exemple 2: service lister les tâches

créer la fonction lister tâches dans le service (retourne une liste en dur) hint: retour obs

utiliser le service dans le composant et afficher les tâches dans une liste