JeuWeb - Crée ton jeu par navigateur
Lutter contre du code trop générique ? - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Lutter contre du code trop générique ? (/showthread.php?tid=4061)

Pages : 1 2


Lutter contre du code trop générique ? - Shao - 08-06-2009

Hop je lance ce débat car je le trouve super important pour tout les développeurs qui s'amuse à simplifier, améliorer, regrouper leurs petits morceaux de code afin de pouvoir les réutiliser.

Ce genre d'exemple, je le retrouve dans pas mal de cas mais travaillant essentiellement sur l'aspect graphique, je vais donc partir de ce point de vue.

De nombreuses fois, je remarque que le développeur s'amuse à ranger son code, à certains moments il se dit même "mince ce que je fais ici, c'est exactement la même chose, je pourrai peut être le simplifier dans un morceau plus générique", et voilà la boucle est lancée.

Cette boucle infernale, je suis déjà tombé dedans, à plusieurs reprises... Et le pire c'est que ça continue. Mais je retiens des leçons à chaque fois et je trouve que c'est intéressant de voir à quel point je vois d'autres personnes reproduire ce schéma sans pour autant se rendre compte que cela impliquera dans le long terme un rebricolage d'un code simple au départ qui est devenu une vraie usine à gaz. :/

Je donne un exemple : je dispose d'une page de statistiques de joueurs ainsi qu'une page de statistiques de pnj. Pourtant je remarque qu'après avoir fait mes deux pages, la quasi-totalité des statistiques sont identiques à l'exception près que le pnj lui n'a pas d'amis (le pauvre :p). Bien entendu cette liste d'amis est mis en évidence dans un endroit tellement bloquant que je ne peux pas dans un premier temps faire ma fiche de personnage, puis greffer cette liste d'amis.

C'est alors que vient souvent l'idée suivante : "Au final c'est la même page web, il me suffirait juste de faire exactement la même page pour les pnj et les joueurs, et de vérifier si c'est un pnj ou un joueur pour afficher ma liste d'amis".
Et je suis absolument contre cette idée. Smile
Tout simplement parce que même si ça simplifierait le code, même si c'est le même bloc de code qui est utilisé, je trouve que c'est archi-faux de s'amuser à vérifier l'état du personnage (joueur ou pnj) dans la page , pour afficher cette liste.

Et quitte à avoir deux pages différentes qui utilise des blocs de code qui seront probablement identique, je privilégierai cette dernière solution car au moins je suis sur d'une chose : si demain je change d'avis en me disant que pour les pnj, certaines statistiques n'ont pas besoin d'être affichées, et bien je n'ai pas une nouvelle condition qui se balade dans la page générique pour vérifier si je dois les afficher.

Cette histoire, beaucoup se diront :
"C'est évident que la deuxième solution est plus rentable, il n'y avait pas besoin de post pour ça..."
Et pourtant des personnes ne seront pas d'accord avec vous tout en vous répondant :
"Pourquoi j'utiliserai cette solution, de toute façon on ne compte pas changer cette page là... et puis ça fait du code en plus à maintenir des deux côtés !".

Voilà, et je remarque que chacun des deux avis est tout autant réparti équitablement alors du coup je me pose (et je vous pose) des questions sur ces deux méthodes :
En pratiquez-vous une en particulière ?
Pratiquez-vous les deux ?
Ou aucune des deux , peut-être avez-vous une autre méthode encore plus simple selon vous ?

PS : Bien entendu, vous aurez remarqué que j'ai une petite préférence sur le fait de dupliquer une partie du code pour différencier deux cas différent, cela ne m'empêche pas de regrouper certains composants entre-eux pour éviter justement d'avoir trop de duplication et du coup, une double maintenance à effectuer.


RE: Lutter contre du code trop générique ? - Allwise - 09-06-2009

Salut, si le code est rangé intelligemment, il ne devrait y avoir aucun problème la suite, on ne devrait pas être bloqué le jour où on décide de faire modif à un endroit mais pas à d'autres. Si c'est le cas, c'est qu'une partie du code qui a été factorisée n'aurait pas dû l'être, et ça peut aussi révéler un problème structurel.

Tu peux très bien factoriser une partie du code responsable de l'affichage des stats d'un pnj et d'un joueur : code responsable de la récupération des données, de leur traitement... Et pour leur affichage, on peut envisager de partir sur le même fichier template ; rien n'empêchera par la suite de dupliquer le fichier et de le différencier de l'autre. Ce schéma s'apparente à une structure MVC. Pour faire plus simple, dans ton exemple de la page stats, tout ce qui pourrait changer c'est l'affichage des données, qui n'est qu'une partie du problème. Donc c'est cette partie là qu'il ne faut pas factoriser. Pour le reste, si un joueur et un npc sont identiques, unifier le code dans des fonctions prend tout son sens.
L'utilisation des templates permet de s'affranchir de ce genre de problèmes, je t'invite à les utiliser si c'est pas encore le cas, quelque soit la structure de ton jeu / site / programme Wink.

Par exemple pour ton problème, on peut imaginer 4 fichiers templates :
- fichier "stats" => Affiche les stats communes aux joueurs et aux npc
- fichier "liste_amis" => Affiche uniquement la liste des amis d'un joueur
- fichier "joueur_stats" => Affiche les stats du joueur, fait appel au fichier stats et au fichier liste_amis
- fichier "pnj_stats" => Affiche les stats du npc, fait uniquement appel au fichier stats,.

Tu as ainsi du code générique pour l'affichage des stats, mais tu es totalement libre d'afficher ce que tu veux pour les pnj et les joueurs.

A l'extrême, ton raisonnement s'oppose à la factorisation du code et à l'utilisation des fonctions. Or, la possibilité de créer des fonctions a une utilité indéniable, je pense que tu es d'accord avec moi sur ce point... Le tout, c'est d'utiliser des fonctions génériques pour ce qui est réellement générique.


RE: Lutter contre du code trop générique ? - wild-D - 09-06-2009

+1 allwise

c'est un faux postulat d'imaginer la situation "tout générique" vs "tout spécifique". Généralement c'est entre les 2 que l'on navigue le mieux. (bon je suis pas encore un vieux briscard des mers, mais à chaque projet je peaufine mon instinct marin )

en PPO, l'héritage, c'est quelque part bien fait pour prendre en charge cette problématique. (partager le code "générique/commun" d'un coté, et le code spécifique de l'autre).

en procédurale on cherche aussi généralement, à regrouper dans des include le code "générique"; et le reste du code plus spécifique dans des fichiers séparés.


RE: Lutter contre du code trop générique ? - Shao - 09-06-2009

(09-06-2009, 12:09 AM)Allwise a écrit : Par exemple pour ton problème, on peut imaginer 4 fichiers templates :
- fichier "stats" => Affiche les stats communes aux joueurs et aux npc
- fichier "liste_amis" => Affiche uniquement la liste des amis d'un joueur
- fichier "joueur_stats" => Affiche les stats du joueur, fait appel au fichier stats et au fichier liste_amis
- fichier "pnj_stats" => Affiche les stats du npc, fait uniquement appel au fichier stats,.

Tu as ainsi du code générique pour l'affichage des stats, mais tu es totalement libre d'afficher ce que tu veux pour les pnj et les joueurs.
Je suis tout à fait d'accord avec cette manière de ranger ces morceaux de code, et d'ailleurs j'ai orienté beaucoup mon débat sur ce point de vue. (c'est à dire, j'ai un bloc de code et je l'utilise autre part).
Mais comme je l'ai dit plus haut, des personnes nous diront toujours que c'est du code en plus et que ça sert à rien et il préfère la premier méthode qui est "j'utilise une seule page avec un if(isJoueur)". Ici l'exemple paraît d'une évidence même qu'on se rend compte à quel point c'est absurde.
Ce genre de cas se retrouve partout et pourtant, dans le monde d'aujourd'hui, on se retrouve beaucoup avec du code blindé de condition pour vérifier des choses absurdes.
Je ne dis pas non à la généricité mais non à la généricité absurde ce n'est pas pareil. :p

(09-06-2009, 11:17 AM)wild-D a écrit : en PPO, l'héritage, c'est quelque part bien fait pour prendre en charge cette problématique. (partager le code "générique/commun" d'un coté, et le code spécifique de l'autre).
Pour l'héritage je suis pas tout à fait d'accord, l'héritage c'est un peu le gros piège de généricité si on sait pas s'en servir.

En tout cas ça me rassure de voir que je ne suis pas seul à penser comme ça Smile


RE: Lutter contre du code trop générique ? - lcfseth - 09-06-2009

Personellement je suis de l'avis de Shao. Certe je suis quelque peu bordelique et donc c'est plus dur pour moi de faire des provisions Smile

Le probléme vient je pense du fait qu'une fois rangé dans une case, le code se fige, le meilleur code d'aujourd'hui n'etant pas necessairement le meilleur code de demain.
Je me surprend toujours à trouver de meilleure solution au probléme que je revisite.
D'ailleurs ma methode d'apprentissage ( je suis un autodidacte ) à un certain moment était de me lancer dans un projet, trouver une n'importe quel solution pour atteindre mon objectif, aussi moche soit elle. Ensuite une fois que je maitrise les differents aspects, je recommence à zéro et généralement je sors un logiciel qui au minimum 2 fois mieux en 2 fois moins de temps.

Le second probléme vient du fait qu'au départ souvent, on écrit du code pour notre logiciel, et qu'une fois términé, en essaye d'en faire un code générique. Ce n'est absolument pas la chose à faire.
C'est d'ailleurs pour ca que dans la plupart des environnement professionel, on sépare la conception du FrameWork ( donc tous les outils générique ) de la conception propre d'un projet donné (d'ailleurs généralement on ne leur parle pas du projet avant que le FrameWork ne soit Up).

Enfin faire du bon code générique n'est pas donné à tout le monde. Il faut optimiser au maximum ( c'est souvent lourd un framework ), prévoir les différents cas d'utilisations et faire du code evolutif. Il faut aussi être plus stricte niveau codage. Beaucoup commenté... Bref à moins d'êtres un pro, de travailler pour une société qui vous donnera 100 projet similaires, ca ne vaut probablement pas le coup.

Je donne un exemple simple pour le PHP : Un mode de gestion des utilisateurs.

Pour un simple site, un peux de HTML/CSS couplé à une base de donné légére fera l'affaire,2 classes d'utilisateurs : user/admin.
Mais si on veut faire un module générique, il faut concevoir un systéme de template (un vrai, pas un gestionnaire de theme), un gestionnaire de module,la base de donné doit contenir beaucoup plus de champs, un gestionnaire de groupes, un gestionnaire de droits...


Bien sûr, il y'a toujours un entre deux, reinventer la roue à chaque fois est idiot.
Il faut réutiliser son code, c'est normale, mais faut aussi être critique envers ce code. Relire le code et voir si entre temps on à pas appris une technique qui pourrait améliorer ce code avant de le réutiliser me parait être la chose à faire.


RE: Lutter contre du code trop générique ? - Sephi-Chan - 09-06-2009

Désolé de le citer souvent, mais les fonctionnalités de Ruby on Rails en matière de factorisation intelligente du code sont très pratiques.

Ruby on Rails invite en permanence à respecter la logique DRY - Don't Repeat Yourself.

On peut voir un aperçu de cela en jetant un œil à l'article "RailsGuides - Getting Started", qui montre comment développer un blog simple. Une partie de ce tutoriel est dédié à la factorisation du code, aussi bien dans les vues que dans les contrôleurs.

Un autre article également très intéressant sur le sujet : RailsGuides - Layouts and Rendering in Rails

Même si pas mal de gens travaillent avec PHP, ces articles sont tout de même intéressant puisqu'ils présentent des approches transférables d'un langage à l'autre.

L'utilisations des vues partielles est géniale pour ça. Par exemple, dans le cas d'une carte, j'ai crée une vue partielle pour une case, et j'appelle cette vue partielle lors de la génération de la carte, mais également lors des appels Ajax : ainsi, le template HTML d'une case est toujours le même, que ce soit un appel Ajax ou non.

Cette pratique garantie l'homogénéité et évite que lors d'un chargement dynamique par Ajax, la case se charge. Ça évite les petits tracas qui arrivent quand on modifie l'un ou l'autre des code HTML (Ajax/non Ajax). Smile


Sephi-Chan


RE: Lutter contre du code trop générique ? - Holy - 09-06-2009

Personnellement je centralise énormément mes fonctions avec éventuellement des "jetons" pour les différencier quand il doit y avoir différenciation.

Pour reprendre l'exemple de Sephi sur le couple ajax/non-ajax et sur le formatage html, j'ai une fonction "buildMap()" qui comprend un jeton qui me permet de savoir si on est en ajax ou pas. Si oui, j'ajoute simplement l'encodage en utf8 à la fin et c'est bingo.

Sinon pour moi l'une des difficultés liées aux fonctions génériques c'est la redondance des appels aux fichiers. J'ai toujours pas trouvé de solution technique, donc il faut vraiment bien "penser" son système pour éviter d'appeler 10 fois un même fichier dans 10 fonctions différentes.

Y a bien la globalisation des données mais ça exige une rigueur de codage assez exemplaire et surtout de nommage. Faudrait que je reformalise mon code de ce point de vue là ^^


RE: Lutter contre du code trop générique ? - phenix - 09-06-2009

Personnellement je pense que tout est affaire d'organisation.

Le mieux reste de bien ranger ses fichiers, de leur donnée un nom explicite et de mettre les actions "générique" dans des fonctions, c'est un peu la base de la programmation. Si tu es ordonné tu n'aura jamais de problème.

Maintenant, je pense que si tu as un partie "statistique" en 4 partie, il faut 1 pages et 4 includes. Simplement parce que c'est 4 spécification d'une seul fonction... Tu fais toujours des statistiques, mais tu les ranges autrement.

Avoir 4 page différente, c'est chaque fois devoir modifier 4 fois...

Il faut choisir la méthode en fonction de la fonction à remplir...


RE: Lutter contre du code trop générique ? - Shao - 09-06-2009

(09-06-2009, 02:33 PM)phenix a écrit : Le mieux reste de bien ranger ses fichiers, de leur donnée un nom explicite et de mettre les actions "générique" dans des fonctions, c'est un peu la base de la programmation. Si tu es ordonné tu n'aura jamais de problème.

Je ne suis pas trop d'accord avec ce point de vue. Pour moi, on peut avoir la meilleure organisation qui existe, et passer à coté de ce genre de cas.

Souvent je procède de la façon suivante :
- je copie les bouts de code que j'ai déjà effectué qui m'intéresse dans mon nouveau système.
- je regarde les morceaux de code qui se ressemblent énormément et qui pourrait partir dans une fonction commune.
- A la fin de la deuxième étape je garde une idée en tête : Si demain on me dit que finalement les deux morceaux vont commencer à avoir des spécificités que ce soit que dans un seul cas ou dans les deux, je ne dois avoir peur de tout reconstruire.

Au final la simplification du code me sert juste dans le cadre d'une maintenance qui concerne une partie commune de mon code, cela m'évite d'avoir à faire une mise à jour dans les deux cas.

A l'inverse ce système peut se retourner contre le développeur, car il fait sa modif dans le premier cas ce qui directement impacte le second cas alors qu'il ne le voulait pas. Smile

C'est un peu comme une librairie ou un framework, avant de mettre à jour un framework, on vérifie si ce qu'on a fait fonctionne avec cette dernière mise à jour. Certains framework prévoit de la rétro compatibilité mais ça devient vite des usines à gaz.

Je pense que construire des fonctions/des blocs , c'est un moyen simple de maintenir son code et dans certains cas ça peut s'avérer super pratique si c'est bien fait et si on ne compte pas faire énormément de maintenance dessus.
Cependant cela fige le code, et en plus les codeurs ont souvent une âme conservatrice (ils ont souvent peur de jeter leur code à la poubelle), pourtant ce n'est pas le code le plus important mais bien le dev qui travaillent derrière. Smile


RE: Lutter contre du code trop générique ? - naholyr - 10-06-2009

J'ai envie de dire que comme Joueur et Pnj ont normalement un parent commun, l'affichage peut prendre en compte cette particularité...
Code :
class PersonnageJoueur extends Personnage { ... }
class PersonnageNonJoueur extends Personnage { ... }
Ton exemple me semble à partir de là être un contre-exemple de ce que tu essaies de démontrer, je ne vois absolument pas en quoi ceci serait vraiment abherrant ou bloquant de quelque manière que ce soit :
Code :
... stats d'un objet Personnage ...
<?php if ($personnage instanceof PersonnageJoueur) include_partial('stats_joueur', array('joueur' => $personnage)) ?>
<?php if ($personnage instanceof PersonnageNonJoueur) include_partial('stats_pnj', array('pnj' => $personnage)) ?>
... fin des stats communes ...


Ceci étant dit, je comprends ton interrogation de départ : le "tout générique" te semble mauvais parce qu'une course éternelle.
Le mot-clé c'est **pragmatisme**
- Si un bout de code strictement identique aux variables près est utilisé à N endroits différents (N étant supérieur ou égal à 2), alors le factoriser est une bonne chose. C'est toujours vrai, et d'autant plus que N est grand.
- Si dans les bouts de code qui se ressemblent il y a des différences de traitement, alors ça s'étudie au cas par cas (c'est le cas de ton exemple, en l'occurrence je préfèrerais factoriser, mais sans avoir le détail difficile d'être vraiment catégorique).
- Si un bout de code n'est utilisé qu'à un endroit, mais qu'on le met dans un coin pour qu'il soit réutilisable à l'avenir, c'est quasiment toujours mauvais, parce que d'une part on anticipe un besoin qui n'existe pas encore et n'existera peut-être jamais, mais surtout parce que le jour où le besoin apparaitra on devra très certainement paufiner à ce moment-là. Autant tout faire au moment où le besoin apparait. Note : c'est évidemment faux lorsqu'on est dans l'optique de l'écriture d'une librairie d'outils, ou lorsqu'on déplace ce code non pas dans l'objectif de factoriser mais de le ranger au bon endroit par rapport à son architecture Wink

Bref, ce n'est que du pragmatisme et du bon sens, donc être "pour" ou "contre" n'a pas de sens.