PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 2024 → Méthode discutable
Méthode discutable
Débuté par Jean-Michel, 14 aoû. 2017 09:12 - 21 réponses
Membre enregistré
834 messages
Popularité : +13 (13 votes)
Posté le 14 août 2017 - 09:12
Bonjour,
2 personnes ne sont pas d’accord sur une façon de programmer, plus exactement la façon d’écrire ou de modifier un enregistrement dans un fichier.
Afin de les mettre d’accord, j’ai eu l’idée de poster les deux différentes méthodes sur ce forum.
Si vous avez le temps, merci de dire ce que vous en pensez.
Méthode A ou Méthode B et pourquoi ?

Énoncè :
L’écran de création/Modification client reçoit un paramètre.
Il reçoit l’ID du client si c’est une modification ou zéro si c’est une création.
Le paramètre est P_IDclient.
A la validation de la fiche client :

Méthode A
HLitRecherche(Client,IDClient,P_IDclient,hIdentique)
Client.Nom = sai_nom
Client.prenom = sai_prénom
Client.pays = sai_pays
(OU EcranVersFichier(FEN_client,Client)) SI zones rattachées

SI P_IDclient = 0 ALORS
HAjoute(Client)
SINON
HModifie(Client)
FIN


Méthode B
HLitRecherche(Client,IDClient,P_IDclient,hIdentique)
SI P_IDclient = 0 ALORS
Client.Nom = sai_nom
Client.prenom = sai_prénom
Client.pays = sai_pays
(OU EcranVersFichier(FEN_client,Client)) SI zones rattachées

HAjoute(Client)
SINON
Client.Nom = sai_nom
Client.prenom = sai_prénom
Client.pays = sai_pays
(OU EcranVersFichier(FEN_client,Client)) SI zones rattachées

HModifie(Client)
FIN


Merci pour vos commentaires.
J.Michel

--
Synchronize Systems International LTD
Développement d'outils de gestion

Environnements AS400 – Windows
Langages GAP III – CL – Visual Basic - Visual Adélia - Adélia - Windev
http://www.cashpower.fr/

Bangkok / Pattaya
Membre enregistré
939 messages
Popularité : +66 (68 votes)
Posté le 14 août 2017 - 09:22
bonjour,

perso je ferais plutôt :

SI P_IDClient=0 ALORS
HRAZ(client)
SINON
HLitRecherche(Client,IDClient,P_IDclient,hIdentique)
// Contrôle d'accès sur l'enreg à rajouter ainsi que gestion verrou
// si HDejaBloque() ou pas htrouve() alors
// // Message d'info...
// fin
FIN
Client.Nom = sai_nom
Client.prenom = sai_prénom
Client.pays = sai_pays
(OU EcranVersFichier(FEN_client,Client)) SI zones rattachées

HEnregistre(Client)
Posté le 14 août 2017 - 09:41
Pour moi clairement pas la méthode B, à cause de la redondance de code.
Mais sur la méthode A, un htrouve serait plus relevant qu'un P_IDClient=0
Membre enregistré
1 923 messages
Popularité : +53 (65 votes)
Posté le 14 août 2017 - 09:53
Bravo Christophe !
Match nul.

--
Bon dev,
Jean-Pierre
Membre enregistré
281 messages
Popularité : +24 (26 votes)
Posté le 14 août 2017 - 13:49
Bonjour,

Pour mon cas, aucune des deux méthodes ne me conviennent :)

C'est pour moi une hérésie de faire appel à des fonctions comme HLitRecherche() qui font des requêtes à la base complètement inutiles alors que l'ont peux faire bien plus propre et moins gourmand en ressources en exécutant soit meme du code SQL.
Posté le 14 août 2017 - 13:58
Je trouve le HEnregistre un peu cavalier aussi. Ne pas maîtriser s'il faut ajouter ou modifier un enregistrement me paraît quelque peu hasardeux...
Membre enregistré
2 566 messages
Popularité : +222 (260 votes)
Posté le 14 août 2017 - 14:59
Bonjour,

Perso je ferai ça:
SI PAS HLitRecherche(Client,IDClient,P_IDclient,hIdentique) ALORS HRAZ(Client)
Client.Nom = sai_nom
Client.prenom = sai_prénom
Client.Pays = sai_pays
(OU EcranVersFichier(FEN_client,Client)) SI zones rattachées
HEnregistre(Client)


Quant à l'écriture de sql, sans méchanceté aucune Damien, pour ce petit bout de code le temps gagné est tellement infinitésimal qu'il me semble être une perte de temps.

--
Cordialement,

Philippe SAINT-BERTIN
Géode Informatique
Membre enregistré
281 messages
Popularité : +24 (26 votes)
Posté le 14 août 2017 - 16:49
Philippe SB a écrit :
Bonjour,

Perso je ferai ça:
SI PAS HLitRecherche(Client,IDClient,P_IDclient,hIdentique) ALORS HRAZ(Client)
Client.Nom = sai_nom
Client.prenom = sai_prénom
Client.Pays = sai_pays
(OU EcranVersFichier(FEN_client,Client)) SI zones rattachées
HEnregistre(Client)


Quant à l'écriture de sql, sans méchanceté aucune Damien, pour ce petit bout de code le temps gagné est tellement infinitésimal qu'il me semble être une perte de temps.

--
Cordialement,

Philippe SAINT-BERTIN
Géode Informatique


Dites cela à un de mes clients qui à des sites à travers le monde et des connexions avec de grosses latence ;) La moindre économie d'aller/retour est importante et il y a aussi le fait de maitriser ce que l'ont fait !
Membre enregistré
2 566 messages
Popularité : +222 (260 votes)
Posté le 14 août 2017 - 18:59
Il y a toujours des cas particuliers mais il ne faut pas faire d'une exception une généralité. Dans 95% des cas, mon code est plus court et suffisamment efficace.

--
Cordialement,

Philippe SAINT-BERTIN
Géode Informatique
Membre enregistré
190 messages
Popularité : +21 (23 votes)
Posté le 14 août 2017 - 20:33
Bonjour

Il y a différentes méthodes avec des avantages/inconvénients,
Idéalement il faut que ce soit concis, facile à lire, rapide d'accès, évolutif.

Pour faire simple, nous avons opté pour 2 paramètres dans la fenêtre de consultation d'une fiche.
Un paramètre d'action : Visualisation / Modification/ Création/ et même copie d'enregistrement / Suppression
Et un paramètre ID fiche.
Avoir uniquement un ID (Création si ID=0, modif sinon) ne nous suffisait pas pour ce qu'on voulait faire.

A l'initialisation de la fenêtre on lit la fiche si on a un ID, (sinon HRAZ)
Selon l'action on active le menu adéquat
A la validation (ou abandon) de la fenêtre, selon l'action, on réalise le traitement.
De plus, ça nous permet en fonction du type d'utilisateur, d'autoriser ou non l'action grâce à une table des droits.

C'est bien d'échanger sur différentes méthodes de saisie.
Après ça dépend les cas métiers rencontrés.
Membre enregistré
30 messages
Popularité : +3 (3 votes)
Posté le 15 août 2017 - 18:16
Bonjour

déjà quand une recherche échoue et que l'on doit faire un ajout, je fais toujours un hraz(dufichier)

SI PAS HLitRecherche(Client,IDClient,P_IDclient,hIdentique) ALORS
HRAZ(Client)
FIN
Client.Nom = sai_nom
Client.prenom = sai_prénom
Client.pays = sai_pays
(OU EcranVersFichier(FEN_client,Client)) SI zones rattachées

SI Client..NouvelEnregistrement ALORS
HAjoute(Client)
SINON
HModifie(Client)
FIN


Je ferme aussi toujours un SI par un FIN car j'ai eu des galères sans nom avec l'indentation et les SI condition ALORS action sur la même ligne.

Même si je trouve le HEnregistre très séduisant, je préfère maitriser l'opération d'accès au fichier lors du HAjoute et HModifie.

Après je suis plutôt d'accord avec Damien, il est préférable de passer par des requêtes SQL mais ce n'est pas le propos de ce topic.


Thierry
Posté le 16 août 2017 - 11:03
Philippe SB a présenté l'énoncé suivant :
Bonjour,

Perso je ferai ça:
SI PAS HLitRecherche(Client,IDClient,P_IDclient,hIdentique) ALORS
HRAZ(Client)
Client.Nom = sai_nom
Client.prenom = sai_prénom
Client.Pays = sai_pays
(OU EcranVersFichier(FEN_client,Client)) SI zones rattachées
HEnregistre(Client)


Quant à l'écriture de sql, sans méchanceté aucune Damien, pour ce petit bout
de code le temps gagné est tellement infinitésimal qu'il me semble être une
perte de temps.


+1
Pour une lecture, H... pour un ensemble SQL....

a plus

--
-------------------------------------------------------------
www.ctc-soft.com
Gestion biblo-documentaire (free-share)
Comptabilité shareware
Logiciels de Gestion de saisie terrain
Spécialisé Tournées de boulangers
-------------------------------------------------------------
Membre enregistré
96 messages
Popularité : +18 (20 votes)
Posté le 16 août 2017 - 15:34
Bonjour,

Aucune des deux méthodes ne me parait correct, mais si je devais en choisir une, ce serait la première, car comme déjà dit précédemment, il y a une redondance de code.

Lorsqu'on effectue le HLitRecherche (j'ai une préférence pour le HLitRecherchePremier plutôt que d'utiliser hIdentique), il faut vérifier si l'on trouve l'enregistrement. Si on ne le trouve pas, il faut gérer l'erreur.
Idem lorsqu'on enregistre, il faut gérer l'erreur si l'enregistrement échoue.

Si on mélange la création et la modification dans le même code, je trouve que le HEnregistre permet de diminuer la quantité de code. Si on distingue les deux cas (deux procédures distinctes par exemple), il faut utiliser HAjoute dans le cas d'un ajout et HModifie dans le cas d'une modification. Cela protège le code car on ne peut pas faire d'ajout avec un HModifie (Identifiant nul) et une modification avec le HAjoute (erreur de doublon).

NouvelEnregistrement est un booléen
EnregistrementTrouvé est un booléen

NouvelEnregistrement = (P_IDclient = 0) // Utiliser une variable est plus parlant qu'une comparaison
SI NouvelEnregistrement ALORS
HRAZ(Client)
SINON
EnregistrementTrouvé = HLitRecherche(Client, IDClient, P_IDclient, hIdentique)
SI PAS EnregistrementTrouvé ALORS
// Gestion de l'erreur
// Il faut prévenir l'utilisateur et gérer l'erreur car on se trouve dans un cas interdit. L'enregistrement a disparu ! Ce n'est pas anodin
// Dans tous les cas, le traitement doit s'arrêter ici
RENVOYER Faux OU RETOUR
FIN
FIN

EcranVersFichier(...) // Ou assignation des champs manuellement

SI PAS HEnregistre(Client) ALORS
// Gestion de l'erreur
// En cas d'erreur, il faut prévenir l'utilisateur et gérer l'erreur. Au pire des cas, on logge l'erreur.
FIN


En règle général, je place ce genre de code dans une procédure globale. Je gère les erreurs par des exceptions (ou dernièrement avec des retours de valeurs multiples avec le message d'erreur en deuxième paramètre). L'alimentation des rubriques du fichier se fait par plusieurs paramètres ou par une structure passée en paramètre (La nouvelle syntaxe des paramètres nommés de procédure est très pratique pour cela aussi).
En procédant ainsi, je peux utiliser ma procédure dans les fenêtres mais aussi dans des traitements automatisés.

Ce qui donnerait ceci :

Procedure ClientEnregistrer(pIdClient est un entier, pNom est chaîne, pPrénom est chaîne, pPays est chaîne, ...)

NouvelEnregistrement est un booléen
EnregistrementTrouvé est un booléen

NouvelEnregistrement = (pIdClient = 0) // Utiliser une variable est plus parlant qu'une comparaison
SI NouvelEnregistrement ALORS
HRAZ(Client)
SINON
EnregistrementTrouvé = HLitRecherche(Client, IDClient, pIdClient, hIdentique)
SI PAS EnregistrementTrouvé ALORS
RENVOYER (Faux, "Le client n'existe pas. Impossible de le modifier.")
FIN
FIN

Client.Nom = pNom
Client.prenom = pPrénom
Client.pays = pPays

Client.Adresse = pAdresseClient
...

EnregistrementEffectué est un booléen = HEnregistre(Client)
SI EnregistrementEffectué ALORS
RENVOYER (Vrai, "")
SINON
RENVOYER (Faux, HErreurInfo())
FIN


// Et lorsque j'appelle mon code
EnregistrementEffectué est un booléen
MsgErreur est une chaîne
(EnregistrementEffectué, MsgErreur) = ClientEnregistrer(P_IDclient, sai_nom, sai_prénom, sai_pays)
SI PAS EnregistrementEffectué ALORS
Erreur("Erreur lors de l'enregistrement de la fiche client.", MsgErreur)
FIN


J'espère que cela donnera l'inspiration à tes collègues.

Bon code !

--
Johjo aka Jonathan Laurent

Mon blog : http://blog.ytreza.org
Twitter : @Johjo07
Message modifié, 16 août 2017 - 15:36
Membre enregistré
834 messages
Popularité : +13 (13 votes)
Posté le 17 août 2017 - 05:50
On ne pensait pas recevoir autant de commentaires.
Cela a été un réel plaisir de lire vos commentaires et critiques constructives sur ce petit morceau de code de type école.

A force de les entendre se disputer pour un "si" et un "tantque", j'ai voulu leur démontrer, qu'il n'y a pas qu'une seule façon d'écrire mais plusieurs et qui fonctionnent.
Grace à vous, et à ce forum, pari réussi.

En ce qui me concerne, les 2 codes sont bons avec une légère amélioration.
Du moment que cela fonctionne et que le code est écrit clairement afin qu'un débutant puisse le comprendre, pour la maintenance.......

A moi de jouer :
HLitRecherche(client,IDclient,P_idclient,hIdentique)
TANTQUE HErreurBlocage() = Vrai
HLitRecherche(client,IDclient,P_idclient,hIdentique + hBlocageLectureEcriture)
FIN
SI PAS HTrouve(client) ALORS HRAZ(client)

client.nom = SAI_nom
client.prenom = SAI_prenom
client.Pays = SAI_pays

SI PAS HTrouve(client) ALORS
HAjoute(client)
SINON
HModifie(client)
FIN

HDébloqueNumEnr(client)


Un grand merci à vous tous et Bon Dev..........................

--
Synchronize Systems International LTD
Développement d'outils de gestion

Environnements AS400 – Windows
Langages GAP III – CL – Visual Basic - Visual Adélia - Adélia - Windev
http://www.cashpower.fr/

Bangkok / Pattaya
Membre enregistré
96 messages
Popularité : +18 (20 votes)
Posté le 17 août 2017 - 08:29
Je pense qu'il faudrait rajouter une temporisation (multitache par exemple) dans le tantque. Si l'enregistrement est bloqué par un autre poste, le programme va partir dans une boucle infinie qui prendra tout le processeur.

--
Johjo aka Jonathan Laurent

Mon blog : http://blog.ytreza.org
Twitter : @Johjo07
Membre enregistré
834 messages
Popularité : +13 (13 votes)
Posté le 17 août 2017 - 14:19
Surtout pas Johjo et cela ralentirait le process inutilement. Les enregistrements sont toujours débloqués à la fin de la procédure.
On utilise ce procédé dans la mise à jour des stock. Il arrive très souvent que plusieurs postes fassent une vente du même article au même moment, la procédure lit l'enregistrement du stock en bloquant, fais un négatif, écrit le nouveau stock et libère l'enregistrement. Grace à cette boucle, il attend que le 1er finisse pour continuer. Cela ne dure que quelques millisecondes. De plus, des mouvements et des approvisionnements de stocks sont également fait en même temps par le stock central.
Plus de 4.000 transactions toutes les nuits.
J'ai fait un test en mettant 2 pc en réseau qui vendent le même article toutes les 0,x secondes pour l'un et 0,x1 seconde pour l'autre. Au bout de peu de temps il y a de multiples accès concurrentiel. En mettant un "trace" j'ai pu suivre et c'est parfait.

--
Synchronize Systems International LTD
Développement d'outils de gestion

Environnements AS400 – Windows
Langages GAP III – CL – Visual Basic - Visual Adélia - Adélia - Windev
http://www.cashpower.fr/

Bangkok / Pattaya
Membre enregistré
96 messages
Popularité : +18 (20 votes)
Posté le 17 août 2017 - 20:37
Tout dépend du contexte dans lequel on se trouve.

Tout d'abord, je me méfie toujours d'une boucle sur lequel je ne maîtrise pas la sortie. Je met toujours en place une option de sortie avec gestion de l'erreur. Dans un monde parfait, on est sûr de sortir de la boucle. Si ne je ne suis pas sûr à 100%, j'envisage une autre sortie. Dans le cas présent, s'il y a un blocage sur l'enregistrement qui se fait en dehors de cette procédure et pour une raison quelconque, le blocage ne se défait pas (on n'est jamais à l'abri d'un bug), la boucle ne se terminera jamais.

Dans le cas présent, si l'on part en boucle infinie, un des cœurs du processeur sera mis à genou. Si en plus on est sur du HF Client / Serveur, lui faire un HLitRecherche sans temporiser risque de le chatouiller un peu.

Deuxième chose, on est dans le cas d'une fiche de saisie d'un client. En règle générale, on bloque d'une manière ou d'une autre l'enregistrement lié au client lorsqu'on rentre en saisie sur sa fiche. On a tout intérêt à faire cela pour éviter que la fiche soit modifiée par deux personnes. Le blocage de l'enregistrement peut être une des méthodes utilisées.

Dans le cas présent, soit le blocage n'est pas nécessaire car déjà fait au préalable car on a ouvert la fiche client, soit on est dans un traitement automatique (avec des champs de saisie, peu probable), et dans ce cas, la fiche client peut avoir été laissée ouverte sur un autre poste.

Dans le contexte de mise à jour de vos ventes, vous êtes dans un processus automatique (pas de bug due à l'interface chaise / clavier) et vous avez fait en sorte d'avoir un process qui ne génère pas d'erreur (ou bien vous débloquez les enregistrements en cas d'erreur). Il est normal que ça marche car vous semblez tout contrôler dans votre environnement (et ça, c'est une bonne chose).

Petit détail pour compléter votre exemple, je mettrai aussi le blocage dans la première lecture car s'il n'y a pas d'erreur de blocage, l'enregistrement ne sera pas bloqué.

Bon dev à vous aussi !

--
Johjo aka Jonathan Laurent

Mon blog : http://blog.ytreza.org
Twitter : @Johjo07
Membre enregistré
834 messages
Popularité : +13 (13 votes)
Posté le 18 août 2017 - 07:24
Joho,
Concernant la fiche de saisie d'un client, je vous donne raison, j'ai mis ce code de blocage un peu inutilement par réflexe.
Par contre, dans l'exemple de mon batch, je ne vois comment procéder autrement, ce n'est pas plus bête que ça.
Si vous avez un exemple, je suis preneur car il faut bien qu'il soit mis en attente avant de traiter......
Concernant le petit détail, le blocage est également dans la 1ere lecture, mais n'apparait pas dans mon exemple, oups......

--
Synchronize Systems International LTD
Développement d'outils de gestion

Environnements AS400 – Windows
Langages GAP III – CL – Visual Basic - Visual Adélia - Adélia - Windev
http://www.cashpower.fr/

Bangkok / Pattaya
Membre enregistré
96 messages
Popularité : +18 (20 votes)
Posté le 18 août 2017 - 09:58
Pour votre batch, je pense que votre méthode est bonne.

Quand je vous propose une temporisation et une option de sortie (basé sur le nombre d'itération ou sur une certaine durée), c'est plus de la prévention qu'autre chose. En temps normal, il y a de forte chance qu'on n'y rentre même pas ou qu'on en sorte dès la première itération.

Les accès concurrents sont vraiment compliqués à gérer. Avec un blocage sur le fichier, ce sera extrêmement rare, mais on peut tomber sur un processus qui souhaite bloquer le fichier, mais il y aura toujours un autre processus pour le bloquer avant lui. L'idéal, ce serait d'avoir une file (premier entré, premier traité) pour gérer les blocages et l'idéal pour cela, c'est l'utilisation des sémaphores associée au blocage Hyperfile.

Mais lorsque le HModifie s'effectue sur plusieurs postes différents, on ne peut pas utiliser les sémaphores. Il ne reste donc que le blocage Hyperfile.

On pourrait avoir une application serveur qui s'occupe de faire les modifications, et dans ce cas, on peut utiliser les sémaphores avec le blocage mais cela revient à casser toute l'architecture d'une application qui tourne correctement.

Donc, à mon avis, votre méthode est la bonne.

--
Johjo aka Jonathan Laurent

Mon blog : http://blog.ytreza.org
Twitter : @Johjo07
Membre enregistré
834 messages
Popularité : +13 (13 votes)
Posté le 19 août 2017 - 11:05
Johjo ,
J'ai voulu voir votre Blog mais ça marche pas !!
J'arrive la dessus :




--
Synchronize Systems International LTD
Développement d'outils de gestion

Environnements AS400 – Windows
Langages GAP III – CL – Visual Basic - Visual Adélia - Adélia - Windev
http://www.cashpower.fr/

Bangkok / Pattaya
Membre enregistré
96 messages
Popularité : +18 (20 votes)
Posté le 20 août 2017 - 19:47
Bonjour,

merci pour cette info, mon serveur personnel semble être tombé. Dès que je rentre de weekend, je répare ça !

--
Johjo aka Jonathan Laurent

Mon blog : http://blog.ytreza.org
Twitter : @Johjo07
Membre enregistré
1 623 messages
Popularité : +100 (114 votes)
Posté le 21 août 2017 - 15:42
SI P_IDCLIENT = 0 ALORS
HRAZ(Clients)
AffectationValeurs
SI PAS HAjoute(Clients) ALORS
Erreur("Erreur lors de l'ajout du client")
SINON
P_IDCLIENT = Clients.Idclient // La fenetre passe du coup en mode edition apres la création
FIN
SINON
HLitRecherchePremier(Cients,IDclient,P_IDclient)
SI HTrouve(clients) ALORS
AffectationValeurs
SI PAS HModifie(Clients) ALORS
Erreur("Un erreur est survenue de la modification du client.")
FIN
SINON
Erreur("Une erreur est survenue de la modification du client.. Client non trouve")
FIN
FIN

PROCEDURE INTERNE AffectationValeurs
clients.nom = SAI_Nom //etc...
FIN
Message modifié, 21 août 2017 - 15:44