Une nouvelle façon de traiter les erreurs

Nous avons récemment introduit un nouveau mécanisme de gestion des erreurs en utilisant la nouvelle commande throw().
Il s’agit de la première étape vers un nouveau système de gestion des erreurs, positionné aussi près que possible du code qui les génère.
Dans la phase suivante, avec 4D v20 R4, nous étendons cette approche pour intercepter les erreurs pendant l’exécution d’une expression.
Entrons dans les détails.

try(), un nouveau mot-clé utile

Avec l’introduction de 4D v20 R4, les développeurs peuvent désormais accéder à un nouveau mot-clé utile : Try(Expression). Le mot-clé Try() permet aux développeurs d’exécuter une expression entre parenthèses et d’intercepter de manière transparente toute erreur survenant au cours de l’exécution. Ces erreurs peuvent être traitées à l’aide de la commande Last errors immédiatement après l’exécution de l’expression. Cela vous permet de définir votre gestion des erreurs au plus près du code qui les a générées et éventuellement d’utiliser des variables locales.

Exemples de scénarios avant les explications détaillées

Division par zéro

Considérons un scénario simple : la division par zéro. L’exemple suivant montre une méthode de division euclidienne qui lève une erreur et renvoie arbitrairement zéro si le diviseur est zéro. Avec Try(), les développeurs peuvent gérer les erreurs de manière plus élégante :

#DECLARE($dividend: Real; $divisor: Real)->$result: Real
If ($divisor=0)
  $result :=0
  throw (-12345 ; "Division par zéro !")
Else
  $result :=($dividend/$divisor)
End if

$result:=Try(division($dividend; $divisor))
If (Last errors#Null)
  // Error management
  logErrors (Last errors)
End if

Accéder à un document

La gestion des erreurs lors de l’accès à un document devient plus simple si le document n’existe pas.
Pour éviter l’affichage de la boîte de dialogue d’erreur 4D, un gestionnaire d’erreur a dû être installé et le code de gestion des erreurs a dû être écrit à l’intérieur de ce gestionnaire d’erreur :

$previousErrorHandler:=Method called on error
ON ERR CALL ("errorOpenDoc")
var $fileHandle : 4D.FileHandle:=File($path).open()
If ($fileHandle#Null)
  ON ERR CALL ("errorReadDoc")
  $text :=$fileHandle.readText()
  If (Last errors#Null)
    $text:="Erreur de lecture du fichier"
  End if
End if
ON ERR CALL ($previousErrorHandler)

Avec le mot-clé Try(), tout peut être écrit dans la même section de code, en accédant aux variables locales et en simplifiant ainsi la lisibilité :

var $fileHandle : 4D.FileHandle:=Try(File($path).open())
If ($fileHandle#Null)
  $text:=Try($fileHandle.readText()) || "Erreur de lecture du fichier"
End if

Fonction d’enregistrement ORDA

Un autre cas d’utilisation complexe concerne la fonction ORDA save(), qui peut générer des erreurs prévisibles et imprévisibles.
Les erreurs prévisibles, comme le verrouillage de l’entité, peuvent être gérées directement par l’attribut success de l’objet résultat. En revanche, les erreurs imprévisibles, telles que les doublons de clé primaire, nécessitent un gestionnaire d’erreurs installé avec la commande ON ERR CALL, sinon la boîte de dialogue d’erreur 4D s’affiche :

var $customer : cs.CustomerEntity
// Do something with the $customer entity
$previousErrorHandler :=Method called on error
ON ERR CALL ("errorSaveManagement")
$result :=$customer.save()
ON ERR CALL ($previousErrorHandler)
If (Not($result.success))
  Case of
    : ($result.status=3)
      // Locked entity management
    : ($result.status=4)
      // Other error management
  End case
End if

Mais maintenant, le mot-clé Try() devient un allié précieux pour gérer les erreurs prévisibles et imprévisibles sans afficher la boîte de dialogue d’erreur 4D :

var $customer : cs.CustomerEntity
// Do something with the $customer entity
$result:=Try($customer.save())
If (Not($result.success))
  Case of
    : ($result.status=3)
      // Locked entity management
    : ($result.status=4)
      // Other error management
  End case
End if

Exécution d’une expression

Le mot-clé Try() accepte n’importe quelle expression 4D entre les parenthèses, qu’il s’agisse de variables, d’affectations, de méthodes, de fonctions, etc. En cas d’erreur, le flux d’exécution s’arrête et revient au dernier mot-clé Try() rencontré (le premier trouvé dans la pile d’appels). Par conséquent, il suffit de vérifier la pile d’erreurs après l’exécution de l’expression pour savoir si des erreurs se sont produites.
Notez que si une erreur est générée en utilisant la commande throw() en mode différé, le flux d’exécution se poursuit jusqu’à la fin de l’exécution de la méthode/fonction en cours, ce qui constitue un moyen simple de gérer la propagation des erreurs.

Résultats

En cas d’exécution réussie, Try() renvoie le résultat de l’expression.
En cas d’erreur, elle renvoie le dernier résultat de l’expression ou « undefined » s’il n’est pas disponible.
Si l’expression ne définit aucun résultat (par exemple, une méthode ou une commande sans résultat), le mot-clé try() renvoie « undefined ».

À propos de la pile d’erreurs

La pile d’erreurs courante est effacée avant l’exécution de l’expression, ce qui permet de faire table rase pour la gestion des erreurs dans le contexte de Try(). Les erreurs rencontrées pendant l’exécution de l’expression sont ajoutées à la pile d’erreurs, ce qui fournit aux développeurs des informations complètes pour le débogage.

Gestion des erreurs

Si aucun gestionnaire d’erreur n’est défini à l’aide de la commande ON ERR CALL, la boîte de dialogue d’erreur ne perturbera pas l’expérience de l’utilisateur lors de l’utilisation de Try().
Les gestionnaires d’erreur globaux et locaux définis avant d’entrer dans le bloc Try() ne seront pas appelés, ce qui garantit une séparation nette entre le contexte Try et le reste du code.
Si l’expression définit un gestionnaire d’erreur global ou local pour la base de données actuelle, il sera invoqué lorsqu’une erreur se produit pendant l’exécution.

Explorer de nouveaux horizons dans la gestion des erreurs

Cette nouvelle fonctionnalité ouvre un monde de possibilités pour la gestion des erreurs. Mais ce n’est que la deuxième étape de la nouvelle ère de gestion des erreurs 4D qui ouvre la voie aux blocs try-catch multi-lignes !
Partagez vos réflexions et vos expériences sur notre forum, et faites-nous savoir ce que vous pensez de cette nouvelle fonctionnalité.

Bon codage !

Avatar
- Product Owner -Damien Fuzeau a rejoint l'équipe 4D Product en février 2019. En tant que Product Owner, il est en charge de la rédaction des user stories, puis de leur traduction en spécifications fonctionnelles. Son travail consiste également à s'assurer que les implémentations de fonctionnalités livrées répondent aux besoins des clients.Damien est diplômé de l'Université de Nantes en génie logiciel. Il a passé plus de 23 ans dans son ancienne entreprise, d'abord en tant que développeur (découverte de 4D en 1997), puis en tant que responsable de l'ingénierie et architecte logiciel. Cette société est un partenaire OEM de 4D et a déployé des logiciels d'entreprise basés sur 4D pour des milliers d'utilisateurs, sur des centaines de serveurs. Damien est donc habitué au développement et au déploiement 4D dans un contexte multi-langues.