Les bonnes pratiques de codage

Voir le sujet précédent Voir le sujet suivant Aller en bas

Les bonnes pratiques de codage

Message par Christophedlr34 le Mar 12 Avr - 19:09

Bonsoir à tous,

Première chose, désolé par avance pour les éventuelles fautes de frappes, je suis sur mon portable car mon windows est en cours de réinstallation.

Ce topic, à pour but, de vous proposer les bonnes pratiques de développement et quelques astuces, pour la plupart, tirés de mes propres connaissances.

Quand vous faites un programme, que ce soit sur ComputerCraft la autre d'ailleurs, évitez autant que possible les boucles infinies. En effet, même si c'est plutôt utile dans certaines circonstances, ça fait plus de mal que de bien.

Sachez qu'une boucle infinie, doit toujours avoir un point de sortie. Si vous n'en n'avez pas, cela veut dire que votre programme ne va jamais s'arrêter, hors il faut toujours qu'il puisse s'arrêter à un moment donné. Retenez bien cette information, car elle est très importante.


Une boucle infinie, n'est là que pour que le programme fonctionne sans devoir le démarrer au préalable.
Si on boucle, on doit sortir, sur CC il faut un pollEvent. C'est une fonction qui va attendre un évènement. Le programme est alors en sommeil, il ne consomme donc pas de ressources pendant qu'il ne fait rien.

L'autre cas où on peut boucler a l'infini, c'est si une condition particulière, permet de sortir de la boucle.


Passons ensuite, sur le positionnement des variable. Éviter autant que possible, les déclarations n'importe où dans le code, en effet, LUA comme tout les langages de.programmation, en particulier les langages de script, fait un parsage du script afin de repérer les différents éléments puis il exécute.
Quand il parse le code, il trouve les variables, quelque soit l'endroit, il est alors tentant de se dire : "Je met mes variables n'importe où". En effet ca marchera, pour peut que la variable soit déclarée avant son utilisation ça marchera si elle est dans le scope (si elle est accessible par la fonction qui y accède).

Toutefois, mettre les variables globales en haut du programme, permet à l'interpréteur de les trouver plus vite. Ainsi, il est plus rapide pour lui de trouver au début les variables puis ne pas en trouver dans le programme que l'inverse, car comme les variables sont déjà trouvées AVANT les fonctions, il n'a pas besoin de vérifier si la fonction accède à une variable qui n'est pas dans le scope. Bon en pratique il vérifie toujours, mais quand il vérifie sur les appels fait par la fonction, quand il compare à sa liste, il trouve de suite.

Ensuite, mettre les variables globales au début est un excellent moyen de pouvoir s'y retrouver.
Pensez aussi à mettre des noms clair, si possible en anglais afin d'avoir des tailles assez courtes, évitez les "de", "la", "le" et autres qui alourdissent la taille de la variable ou de la fonction.
Préférez plutôt des ordres, par exemple une fonction qui afficherait un message à l'écran, on ne va pas l'appeler : "AfficheUnMessageALEcran", mais plutôt : "AfficherMessage" ou en anglais : "DisplayMessage" ou encore plus court (et plus courant dans l'informatique) : "DisplayMsg".

Ce dernier exemple en vient à mon astuce suivante : on a tous pour habitude de raccourcir certains mots, il est courant en informatique d'avoir "msg" pour "message" par exemple, "ret" pour "retour" ou "retourner" ou encore en anglais : "return", etc. A vous de trouver vos abréviations si vous souhaitez vous en servir, mais ça doit rester compréhensible. En parcourant notre cher ami à tous Google, vous retrouverez des dizaines voir des centaines d'abréviations utilisés dans le domaine informatique (toutes ce rapportant à l'anglais par contre), prenez exemple dessus.

Evitez autant que possible les variables globales. Dans un système orienté objet comme l'est le PHP (l'exemple le plus courant pour apprendre la programmation, car très simple, très puissant et orienté objet), on abolie les variables globales car les classes disposent de variables de classe (appelées des propriétés), se sont des variables globales à la classe uniquement et non à tout le programme ou le script.

Dans les langages de script comme le LUA, qui ne sont pas sur un principe d'objets (ou pas directement, le JavaScript est aussi dans le lot), on est obligé d'utiliser des variables globales.
Pour rappel une variable globale, c'est une variable accessible de n'importe où dans le script (voir dans un autre script dans le cas "d'exportation" de variables, mais c'est plus spécifique au JavaScript par exemple), c'est donc le recours le plus courant.
Hélas c'est une très mauvaise idée, car cela permet à n'importe quel morceau de code du script, de faire tout et n'importe quoi avec la variable.

Il faut savoir que les langages de scripts, font du "transtypage automatique", c'est à dire que contrairement au Java, C#, C, C++, Pascal, Pascal Objet/Delphi et autres langages de ce style qui eux exigent qu'on indique spécifiquement le type de la variable (par exemple int i indique que la variable nommée i contient que des nombres entier allant de -2 milliard à +2 milliard, alors que unsigned int i par exemple, permet d'aller de 0 à 4 milliard ; vous avez sans doute tous entendu parlé de la limitation des ordinateurs 32 bits, ne pouvant disposer de plus de 4Go de mémoire RAM, ben c'est parce que le unsigned int ne suffit pas, il faut un unsigned long int soit donc sur 64-bits plutôt que 32-bits), les langages de scripts le font automatiquement.

Le fait de typer automatiquement la variable est bien dans un sens, où on ne s'embête pas à savoir le type de donnée que doit avoir la variable, mais cela veut dire qu'en cours de route on peut passer d'une variable pour stocker du texte à une variable pour stocker un booléen (vrai ou faux, en anglais : true ou false).
Si la variable est globale, on peut la modifier de n'importe où disions-nous tout à l'heure, donc on peut la modifier alors qu'il faut pas et foutre le programme en l'air et le serveur avec si on entre sur une boucle infinie à cause d'une mauvaise valeur dans notre variable (tiens encore une manière d'avoir une boucle infinie, vous allez voir que tout peut créer cette situation).

Il faut autant que possible, que la variable soit passée en paramètre de votre fonction, ainsi dans votre fonction vous en avez une copie seulement. Si maintenant vous avez plusieurs fonctions demandant la même variable, il est plus judicieux de la mettre en globale au début du programme afin de donner son accès partout.
Vous pouvez aussi le faire pour d'autres raisons bien entendu, mais faites attention avec.
Oubliez pas aussi que quand vous quitter une fonction, toutes les variables déclarées dedans sont supprimées, c'est aussi là l'intérêt des variables propre à vos fonctions : libération de la mémoire.


Au niveau des conventions d'écriture, il est d'usage en informatique d'écrire le code en anglais, que se soit le nom des fonctions ou les variables. Cela permet d'une part un gain de place, on est moins enclins à ajouter des mots tels que : "le", "de", "ton" etc.
Ensuite, cela permet si vous partagez votre code, qu'il soit compris facilement. En effet, si vous écrivez en russe par exemple, ben seuls ceux qui parlent russe, vont comprendre avec le nom de la fonction, ce qu'elle fait ; alors qu'avec l'anglais c'est tout le monde.
Pour la même raison, il est fortement conseillé de commenter votre code, en particulier chacune des fonctions que vous créez. Le nom doit être explicite, mais le commentaire permet d'en savoir plus.
Lui aussi en général c'est en anglais, toujours dans le même soucis de compréhension par tous.

Puisqu'on en est sur les conventions, il y en a une qui tan à se généraliser au fil des années, car tout les bons IDE avancés (tel qu'Eclipse, la référence en la matière), sont capable de les lires. Ils 'agît des commentaires "Javadoc". Je le met entre parenthèse, car cette façon de commenter ses fonctions, classes et méthodes (le nom des fonctions dans une classe c'est "méthodes"), a été créée par Sun Microsystem à l'époque où leurs ingénieurs ont créer le Java. Le principe était qu'un programme (javadoc), lisait ces commentaires, et générés automatiquement une documentation du code (format HTML).
Depuis ce système a été repris pour la plupart des langages, Doxygen par exemple sait les lire et générer une documentation pour la grande majorité des langages (dont le PHP, on dit donc une "PHPdoc".

Il s'agît en général d'utiliser le commentaire multiligne (souvent /* et */) avec une étoile en plus (/** */) et une étoile pour chaque ligne. Ensuite, on utilise des informations avec un @ (arobase), permettant de décrire l'information.

Par exemple, en PHP nous aurions :

/**
* Return hello world with selected name
*
* @param string name
* <p>Name of player</p>
*
* @return string
* <p>The hello world string and presentation of player, with playername</p>
*/
function helloName($name) {
return "Hello world ! My name is ".$name;
}

Dans cet exemple, nous allons nous intéressé qu'au commentaire, car le reste c'est une fonction typique en PHP, et pas tout le monde connaît le PHP.
Ici, nous avons un première commentaire : Return hello world with selected name, rien de particulier là nous avons "titré" notre fonction, en gros on dit ce qu'elle fait, puis on laisse une séparation pour l'aération du commentaire.
Ensuite on indique @param, cela signifie qu'on indique que c'est un paramètre, l'information qui suit stipule que nous avons affaire à une chaîne de caractère, et enfin le nom de la variable représentant la chaîne (ici name). Juste dessous, nous indiquons à quoi sert ce paramètre avec une balise HTML <p>, pour créer un paragraphe et avoir un côté esthétique dans la présentation de notre commentaire (il est plus lisible avec que sans).

Nous avons ensuite une autre information : @return, ici on indique que la fonction retourne une information (le return qu'on voit dans la fonction), on dit que la fonction renvoi une chaîne de caractères et on indique ensuite ce qu'est ce retour (là on dit que ça renvoi la chaîne "hello world" et la présentation du joueur avec son nom de joueur).


Ce genre de présentation de commentaire (type PHPdoc dans l'exemple, pour LUA on dirait LUAdoc lol), prend de la place, mais ça apporte tellement sur la compréhension de la fonction, que c'est incontournable.
Alors certes, les "/* */" ou "/** */" ne sont pas présent en LUA, nous n'avons que le "--", donc on utilisera ça.

Même si derrière nous n'avons pas une génération de la documentation ni l'utilisation d'un puissant IDE comme Eclipse (le premier et l'un des rare à parser les commentaire comme ça pour les afficher en surbrillance, ce qui permet de savoir ce que la fonction fait et ce qu'elle attends comme paramètre), mais vous même vous allez immédiatement comprendre ce que fait votre fonction, ce quelle avant et ce qu'elle renvoi.

Je vous conseil vivement de vous en servir pour commenter vos fonctions, vous verrez que vous vous y retrouverez plus facilement dans vos codes. Pensez aussi aux "crédits" de votre programme avant les premières lignes de code (l'auteur, ce que fait le programme, l'éventuelle licence qui s'applique, la date de création et toute info que vous jugerez utile de mettre).

Pour terminer et compléter un peut tout ça, ComputerCraft permet de charger d'autres fichiers LUA, aussi évitez de faire des programmes de 500 lignes dans un même fichier ; d'une part vous allez vous y perdre pour les noms de fonctions, mais en plus vous allez avoir du mal à retrouver vos petits dans tout ce fatras, d'autant que l'écran des computer n'est pas très grand et la navigation pas très pratique.
Ainsi, si votre programme dispose d'une interface graphique par exemple, et ensuite d'un traitement d'après les informations fournies par l'interface, pensez à séparer en deux programmes : un pour la GUI (interface graphique utilisateur, en anglais Graphics User Interface), et l'autre qui fait le travail.

Un fichier de configuration (même temporaire) entre les deux, permet de passer facilement les instructions que donne la GUI pour le traitement.
Par exemple, j'avais fais à l'époque sur CC, un programme pour creuser automatiquement des mines optimisées, j'avais donc fait une interface graphique afin de configurer facilement la turtle pour son travail. J'enregistré le tout dans un fichier texte, ce qui me permettait plus tard de lui refaire faire le travail sans devoir la reconfigurer, car la config était déjà stockée.

J'aurais pu à cette époque (mais on ne pouvait pas encore le faire il me semble), séparer le programme en deux : la GUI pour configurer et enregistrer la configuration, et le travail de la turtle ; son programme aurait juste eu a lire la config et a faire son boulot.


J'espère que vous aurez appréciés ces quelques conseils et astuces pour de bonnes pratiques de programmation. Il est probable que j'en oublis, étant pas mal crevé avec mon stage (et ca tombe bien, je parlais de JavaScript à un moment donné, je suis sur ça en ce moment donc ça tombe très bien lol), c'est difficile d'avoir les idées claire, d'autant que j'ai commencé ce post via le portable du fait de la réinstallation de Windows, avec un miss clic sur "Envoyer" (et finalement heureusement) et terminé sur PC quelques heures plus tard.

Pensez que je vous oblige à rien, ce sont juste des conseils sur comment bien coder (et éviter les boucles infinies qui foutent le bordel lol), et comment rendre votre code lisible et compréhensible par tous et surtout par vous même.
Après, vous pouvez retrouver un exemple de tout ce que j'ai dis, dans les programmes que je fais, j'en ai déjà déposé un sur le forum, vous pouvez aller voir ce que ça donne dans la façon de coder. Pour ceux qui le désirent, je peux aussi fournir du code (de d'autres langages de programmation), afin de vraiment voir ce que donnent ces pratiques de codage. Mon site (dont je donnerais l'adresse par MP sauf si Cedmeu accepte que je mette sur le forum, mais il risque de considérer cela comme de la pub lol), regroupe justement un peut tout ce que je programme sur mon temps libre, et c'est une bonne source d'information sur la façon de coder, comment coder de façon logique (ce que je n'ai pas abordé ici) etc.

Pour ceux qui auraient aussi des connaissances dans le domaine voir un niveau supérieur au mien, peuvent ajouter leurs propre conseils, et compléter les miens. Plus on aura de conseils et bonnes pratiques à faire passer à tout les codeur LUA en herbe de ce serveur, au plus les programmes seront de qualité. Même un programme de quelques lignes avec seulement 2/3 fonctions courtes et sans prétention, peuvent mettre à mal le serveur s'ils sont codés "avec le cul" (j'aime bien cette expression, merci à mon formateur pour cette trouvaille lol). Faire un programme de qualité en terme de codage et en terme de lisibilité du code, est réellement à la portée de tous, il suffit juste de savoir les bonnes choses et les mauvaises.

L'indentation par exemple est très importante aussi : identer votre code systématiquement et en particulier si c'est lu sur un Computer et non un Advanced Computer, donc sans coloration syntaxique. L'aération est importante aussi, rien de plus chiant à lire qu'un pavé de 50 lignes constituant une fonction, sans la moindre aération. En général on retrouve les traitements entre eux, voir on les découpes en 2/3 morceaux avec des lignes vides, afin d'apporter un côté plus chaleureux à nos pauvres yeux. Allez lire un code de 50 lignes sans aération, sans indentation, et regardez la même chose une fois que c'est aérer et indenter. Rien que là déjà vous allez mieux comprendre, et si en plus le code est un minimum commenté, là c'est la jouissance la plus totale (merde je parle comme BobLennon, au secours ^^).


Je vais m'arrêter là, j'espère vous avoir aider à faire des programmes de meilleurs qualités, moi j'ai pris plaisir à rédiger ce message malgré ma fatigue de la journée (passez donc une journée entière à bosser sur de l'encodage de vidéo en Node.js, vous allez vous pendre avec votre câble ethernet lol). Perso, je ne sais pas les aspirations de Cedmeu concernant CC sur le serveur, mais personnellement je préfère peut de programmes mais qui sont de qualités : bien écrit, compréhensible, optimisés, qui vont pas merder le serveur car codés n'importe comment etc. que beaucoup de programmes mais qui sont très mal fait.


Dernière édition par Christophedlr34 le Mar 12 Avr - 21:44, édité 1 fois

Christophedlr34

Messages : 69
Date d'inscription : 30/03/2016

Revenir en haut Aller en bas

Re: Les bonnes pratiques de codage

Message par Link712011 le Lun 18 Avr - 17:41

J'aimerai rajouter que la récursivité est à bannir. En effet, elle consomme beaucoup plus de ressources pour souvent le même résultat qu'une boucle, en plus lent bien sur.
avatar
Link712011

Messages : 80
Date d'inscription : 04/04/2016
Age : 21
Localisation : Entre ma chaise et mon clavier

Revenir en haut Aller en bas

Re: Les bonnes pratiques de codage

Message par Christophedlr34 le Lun 18 Avr - 19:02

Là je suis pas d'accord avec toi Link. Si tu as une simple boucle standard oui la boucle est mieux, si maintenant dans cette boucle tu as une autre boucle voir une autre et que tout cela s'évite facilement avec de la récursivité, il faut utiliser la récursivité.

Prend par exemple la suite de Fibonacci (qui permet de calculer la reproduction des lapins par exemple). La formule c'est : Fx = Fx-1+Fx-2, avec x = 5, on aurait donc :
F5 = F5-1+F5-2.

Ce qui revient à dire, que pour calculer F5, nous devons calculer d'abord F4 + F3, mais pour calculer F4 c'est F3+F2 sachant que nous avons F3 déjà à calculer avec F2+F1 et ainsi de suite jusqu'à descendre sur F0.

Ca tombe bien, en cours j'ai vu la suite de Fibonacci, et ont a testé. Avec une boucle, le calcule de F15, ça rame à mort. Par contre avec de la récursivité, on monte jusqu'à F23 avant que PHP nous envoi bouler (en ayant un peut de mal quand même).

L'exemple que je t'ai donné est typique (c'est pourquoi c'est l'exemple qu'on nous enseigne en algorithmie ET en codage), tu ne peux pas le faire dans un délais raisonnable sans passer par la récursivité. En plus avec ta boucle, déjà il t'en faudra deux et des tableaux pour stocker les résultats de chaque calcul, faut ensuite trier le tableau, retiré les doublons et l'exploiter pour fournir le résultat final. Tout ça prend du temps et de la RAM.
Avec la récursivité, tu récupères directement le résultat à chaque fois.

Avec la récursivité, quand tu vas faire F5, tu auras comme résultat : 3+2, parce que F4 a donné 2+1 et que F3 a donné 1+1. Chaque fois que la fonction récursive s'est appelée elle même, elle a calculé la suite de fibonacci indiquée, puis à renvoyé son résultat, ici donc pas de variables temporaires, pas de tableaux qui grossit, grossit et grossit encore avec plusieurs boucles itératives. Seulement un return qui a été fait et rien d'autres, donc un calcul et un renvoi du calcul, le renvoi étant utilisé à chaque fois pour le nouveau calcul, tu n'as QUE ce renvoi qui est à retenir, tu économises du CPU et de la RAM.

Exemple en LUA de ce que ça donne :

print('Calcule d'une suite de Fibonacci : ');
print('Exemple avec F18 devant donner 2584 : '+fibonacci(18));

function fibonacci(x) {
if ( x <= 2 ) then
return 1;
end

return fibonacci(x-1)+fibonacci(x-2);
}

Au total 10 lignes pour ce programme dont 5 seulement pour la fonction en comprenant la ligne vide. Tu tests, et tu verras qu'il te fera assez vite le calcul. Maintenant implémente avec tes boucles, tu verras que c'est plus long.

Pour en rajouter une couche, avec les boucles tu es sur une complexité O(n), alors que là tu es sur une complexité algorithmique O(n-1), n-1 car à chaque récursivité, c'est un appel de moins.

Christophedlr34

Messages : 69
Date d'inscription : 30/03/2016

Revenir en haut Aller en bas

Re: Les bonnes pratiques de codage

Message par Pyeroh le Lun 18 Avr - 22:04

J'ajouterais à la très bonne démonstration de Christophe qu'on peut également, si vous craignez pour l'utilisation des ressources, mettre en place un système de cache dans son code pour éviter de recalculer plusieurs fois les mêmes valeurs.

Avec l'exemple de la suite de Fibonacci, si vous devez calculer F18 régulièrement, créez un tableau, et associez 18 au résultat de F18. Ainsi, vous pourrez faire appel au cache au lieu d'appeler plusieurs fois un re-calcul de la valeur. Ce que vous perdez en utilisation de stockage, vous le gagnez en RAM et CPU.
avatar
Pyeroh

Messages : 33
Date d'inscription : 29/03/2016
Age : 22
Localisation : Nouvelle-Calédonie

https://github.com/Pyeroh

Revenir en haut Aller en bas

Re: Les bonnes pratiques de codage

Message par Link712011 le Mar 19 Avr - 0:49

Je serai d'accord avec toi Christophedlr34 dans un seul cas: la récursivité terminale, auquel cas c'est possible de faire en effet une récursivité peu couteuse en ressources.

La récursivité terminale actualise les paramètres, c'est plus un goto qu'un appel de fonction. C'est pas le cas pour les récursivités non-terminales qui elles, empilent sur la stack des nouvelles valeurs en faisant des appels de fonctions évitables. La récursivité c'est pratique, mais optimisé que quand elle est bien utilisée.

L'exemple le plus révélateur qui me vient en tète c'est quand j'ai du comparer un chiffrement RSA en récursif et le même sans récursivité. Résultat, l'algo avec récursivité prenait 1/3 plus de temps et 2 fois plus de stack.
avatar
Link712011

Messages : 80
Date d'inscription : 04/04/2016
Age : 21
Localisation : Entre ma chaise et mon clavier

Revenir en haut Aller en bas

Voir le sujet précédent Voir le sujet suivant Revenir en haut


 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum