Fermer

juin 30, 2020

Comment garantir un code PHP flexible et réutilisable avec Insphpect –


Insphpect est un outil que j'ai écrit dans le cadre de mon projet de doctorat. Il analyse le code à la recherche de techniques de programmation orientées objet qui entravent la réutilisation et la flexibilité du code.

Pourquoi?

Permettez-moi de commencer par deux observations banales:

  1. Les exigences commerciales changent au fil du temps.
  2. Les programmeurs ne sont pas clairvoyants.

    19659006] Lancement de nouveaux produits, réglementations de verrouillage d'urgence, expansion sur de nouveaux marchés, facteurs économiques, lois sur la protection des données mises à jour: il existe de nombreuses causes potentielles de mise à jour des logiciels d'entreprise.

    De ces deux observations, nous pouvons déduire que les programmeurs savent que le code qu'ils écrivent va changer, mais pas ce que ces changements seront ni quand ils se produiront.

    Écrire du code de telle manière qu'il puisse être facilement adapté est une compétence qui prend des années à maîtriser.

    Vous êtes probablement déjà familier avec les pratiques de programmation qui reviennent et vous hantent. Les programmeurs débutants réalisent rapidement que les variables globales sont plus problématiques qu'elles n'en valent, et le modèle Singleton, incroyablement populaire, a été un gros mot pour la dernière décennie .

    La ​​façon dont vous codez votre application a une grande impact sur la facilité d'adaptation pour répondre aux nouvelles exigences. Au fil de votre carrière, vous apprenez des techniques qui facilitent l'adaptation du code. Une fois que vous avez compris les principes de base de la programmation orientée objet, vous vous demandez comment vous vous en êtes sorti!

    Si vous demandez à dix développeurs de produire des logiciels, compte tenu des mêmes exigences, vous obtiendrez dix solutions différentes. Certaines de ces solutions seront inévitablement meilleures que d'autres.

    Considérons un navire en bouteille et un modèle réduit de navire en Lego. Les deux sont des modèles réduits de navires, mais changer les voiles sur le navire dans une bouteille est très difficile, et la réutilisation des pièces est presque impossible. Cependant, avec un vaisseau Lego, vous pouvez facilement échanger les voiles ou utiliser les mêmes composants pour construire une maquette de fusée, une maison ou une voiture.

    Certaines techniques de programmation conduisent au bateau-en-bouteille approche et rend votre code difficile à modifier et à adapter.

    Insphpect

    Insphpect est un outil qui analyse votre code pour des pratiques de programmation qui conduisent à ce type de vaisseau dans une conception de bouteille.

    Il note votre code en fonction de sa souplesse et met en évidence les domaines dans lesquels la flexibilité peut être améliorée.

    Que recherche Insphpect?

    Actuellement, Insphpect recherche les éléments suivants:

    • couplage étroit
    • configuration codée en dur
    • singletons
    • injection de setter
    • en utilisant le mot-clé nouveau dans un constructeur
    • localisateurs de services
    • héritage
    • méthodes statiques
    • état global
    • fichiers qui ont plus d'un rôle (par exemple, définir une classe et r unning un code)

    S'il détecte quelque chose qu'il identifie comme inflexible, il met en évidence le code, explique pourquoi il a mis en évidence le problème, puis note tout votre projet et vos classes individuelles sur une note de 0 à 100 (100 étant aucun problème détecté ). Comme preuve de concept, pour certaines détections, il est capable de générer automatiquement un fichier correctif qui réécrit le code pour supprimer complètement l'inflexibilité.

    Jetez un œil à un exemple de rapport ici .

    Inspecter est actuellement en phase de test, et cela aiderait vraiment mes progrès de recherche si vous pouvez le vérifier et remplir le sondage dans la section "Donnez votre avis" du site.

    Contexte

    Ces mauvaises pratiques sont-elles vraiment mauvaises

    C'était l'une des parties les plus difficiles de la recherche de base, et vous pouvez lire comment cela a été fait en détail sur le site Web Insphpect .

    Cependant, cela peut être résumé comme:

    • Les opinions de chaque mauvaise pratique ont été recueillies auprès de 100 auteurs par pratique.
    • L'opinion de l'auteur sur la pratique a été notée sur une échelle de 1 à 5.
    • La rigueur méthodologique de l'auteur a été notée sur une échelle de 1 à 7 sur la base du score de Jadad utilisé pour les essais cliniques. [19659029] Ceux-ci ont ensuite été tracés comme le graphique ci-dessous:

       Résultats du motif singleton

      Chaque ligne horizontale représente un article, et la barre de gauche (orange) pour chaque article est la recommandation allant de 5 – Évitez cette pratique à tout prix (Extrême gauche) – à 1 – Privilégiez cette pratique aux alternatives.

      La ​​barre de droite (bleue) pour chaque article est le score de style Jadad mesurant la rigueur analytique. Un score de sept signifie que l'article décrit la pratique, fournit des exemples de code, discute des approches alternatives, fournit des échantillons de code similaires, discute des avantages / inconvénients de chaque approche et fait une recommandation de l'approche à utiliser.

      Dans le cas du singleton ci-dessus, les auteurs qui comparent le singleton à des approches alternatives, discutent des avantages / inconvénients, etc., sont beaucoup plus susceptibles de suggérer d'utiliser des approches alternatives.

      Procédure pas à pas

      Actuellement, Insphpect permet de télécharger du code via une URL de référentiel Git ou un fichier ZIP.

      Donc, pour ne pas signaler les failles dans le travail des autres, jetons un œil à l'un de mes propres projets pour voir ce qu'il identifie.

      Nous utiliserons https : //github.com/Level-2/Transphporm comme exemple de projet.

      Ceci est un assez bon exemple, car il a un score très élevé sur un autre outil de qualité de code Scrutinizer .

      Tout d'abord, entrez l'URL git https: // github .com / Level-2 / Transphporm dans la zone de texte en haut de la page d'accueil et appuyez sur "Go". Cela prendra quelques secondes à quelques minutes, selon la taille du projet, et générera un rapport qui ressemble à ceci:

       Rapport Transphporm

      Une fois que vous êtes sur la page du rapport , vous verrez un résumé en haut avec une note globale de 100, 100 étant très bon et 0 étant très mauvais.

      Sous le résumé, vous verrez une liste de toutes les classes du projet, chacun avec sa propre note.

      Ne vous inquiétez pas si votre code n'obtient pas un score parfait. Il est peu probable que ce soit le cas. N'oubliez pas, Insphpect est un outil qui identifie la flexibilité de votre code. Il y a des parties de votre code (comme le point d'entrée) où la flexibilité n'est pas garantie.

      Pour Transphporm, il a mis en évidence des problèmes dans sept classes.

      Jetons un coup d'œil à certains d'entre eux. Faites défiler jusqu'à Transphporm Parser CssToXpath et cliquez sur le lien. Vous verrez un score pour cette classe particulière et une liste des problèmes qui ont été identifiés.

      Dans ce cas, il a identifié une variable statique et une méthode statique. En cliquant sur l'une des lignes rouges, vous découvrirez pourquoi la ligne a été signalée.

      Par exemple, en cliquant sur la ligne 12, vous expliquerez pourquoi les variables statiques sont moins flexibles que les variables d'instance.

       Single rapport de classe

      Bien qu'il y ait une explication plus approfondie des problèmes causés par les propriétés statiques dans le rapport en guise de rappel rapide, les variables statiques ont une valeur qui est partagée entre toutes les instances

      Ceci est intrinsèquement moins flexible qu'une variable d'instance, car l'utilisation d'une variable d'instance permet à chaque instance d'avoir une valeur différente.

      Par exemple, considérez ce qui suit:

       class User {
          public statique $ db;
          public $ id;
          public $ name;
          public $ email;
      
          fonction publique save () {
              $ stmt = self :: $ db-> prepare ('REPLACE INTO user (id, name, email) VALUES (: id,: name,: email)');
      
              $ stmt-> execute ([
                  'id' => $this->id,
                  'name' => $this->name.
                  'email' => $this->email
              ]);
          }
      }
      

      Parce que $ db est statique, chaque instance de cette classe partage la même instance $ db et les enregistrements seront toujours insérés dans la même base de données.

      Bien que cela semble raisonnable , permettez-moi de vous donner un exemple concret.

      Dans le monde réel

      Un de nos clients était une agence de recrutement. Environ deux ans après avoir développé leur site, ils ont repris une autre petite entreprise. Ils voulaient conserver le site Web et l'image de marque de la deuxième entreprise, car ils étaient assez bien connus dans le créneau dans lequel ils se trouvaient.

      Notre client nous a demandé ce qui suit:

      Sur le site de la deuxième entreprise, pouvez-vous ajouter une case à cocher lors de l'ajout d'un travail qui ajoute également le travail à notre base de données afin que les personnes qui consultent notre site puissent également voir le travail et vice versa.

      Une demande assez simple. Exécutez une requête d'insertion dans deux bases de données différentes.

      Mais parce que le site Web utilisait une instance de base de données globale statique, cela était inutilement difficile!

      Les développeurs de ce site ont écrit le code confiant qu'une seule connexion à la base de données serait jamais nécessaire. Ils avaient tort.

      Souvenez-vous, vous n'êtes pas clairvoyant et il est impossible d'anticiper quelle flexibilité pourrait être nécessaire à l'avenir.

      La solution

      Comme suggéré par Insphpect, la solution consiste à utiliser des variables d'instance :

       utilisateur de classe {
          privé $ db;
          public $ id;
          public $ name;
          public $ email;
      
          fonction publique __construct ( PDO $ db) {
              $ this-> db = $ db;
          }
      
          fonction publique save () {
              $ stmt = self :: $ db-> prepare ('REPLACE INTO user (id, name, email) VALUES (: id,: name,: email)');
      
              $ stmt-> execute ([
                  'id' => $this->id,
                  'name' => $this->name.
                  'email' => $this->email
              ]);
          }
      }
      

      Une instance User peut désormais être utilisée avec différentes instances de base de données:

       new User ($ database1);
      nouvel utilisateur ($ database2);
      

      Pour Transphporm Parser CssToXpath nous pourrions faire de même, supprimer la variable statique et envisager d'en faire une variable d'instance plutôt qu'une variable statique.

      Utilisation de new dans le constructeur

      Prenons un aperçu de l'une des autres classes: Transphporm Builder .

       Rapport de classe Builder

      Ceci a un score de zéro, ce qui est plutôt mauvais. En examinant le rapport en détail, Insphpect a relevé le même problème à trois reprises: en utilisant le nouveau mot-clé dans un constructeur.

      L'entraîneur de programmation Google Misko Hevery explique très bien pourquoi cela est une mauvaise pratique de programmation mais voici un exemple simple de la sortie d'Insphpect:

       class Car {
          moteur $ privé;
      
          fonction publique __construct () {
              $ this-> engine = new PetrolEngine ();
          }
      }
      

      Ici, chaque fois qu'une instance de Car est créée, une instance de PetrolEngine est créée. Cela le rend très rigide, car il n’existe aucun moyen de construire une voiture avec un type de moteur différent. Chaque voiture modélisée dans ce système doit avoir un PetrolEngine .

      Au lieu de cela, nous pouvons utiliser l'injection de dépendance:

       class Car {
          moteur $ privé;
      
          fonction publique __construct ($ engine) {
              $ this-> engine = $ engine;
          }
      }
      

      Différentes voitures peuvent être créées avec une instance de PetrolEngine DieselEngine ElectricEngine JetEngine ou tout autre type de moteur existant dans le projet.

      Pour corriger cette erreur dans Transphporm Builder toutes les variables qui ont actuellement des noms de classe codés en dur doivent utiliser à la place des arguments de constructeur.

      Il y a d'autres problèmes identifiés par Inspectez, mais vous pouvez l'essayer par vous-même et voir comment se déroule votre projet.

      Dans les coulisses

      Vous vous demandez peut-être comment les scores sont calculés et pourquoi cette classe a obtenu un zéro. À l'heure actuelle, les pondérations sont susceptibles de changer une fois que d'autres projets ont été analysés et que davantage de commentaires ont été fournis.

      Les notes sont conçues pour être indicatives pour comparer un projet / classe à une autre.

      La ​​note globale du projet est juste une moyenne de toutes les classes du projet. Cela a été implémenté car un projet avec deux problèmes dans 1000 classes est globalement bien meilleur qu'un projet avec deux problèmes dans deux classes.

      Chaque mauvaise pratique est pondérée selon qu'elle entrave la flexibilité pour l'ensemble de la classe ou seulement la flexibilité pour

      Conclusion

      Insphpect peut être utilisé pour identifier les zones de votre code qui rendent les modifications futures plus difficiles qu'elles ne le pourraient, et il propose des suggestions sur la façon d'écrire le code de manière plus flexible. Rappelez-vous, vous n'êtes pas clairvoyant et n'avez aucun moyen de savoir comment votre code va devoir changer!

      Insphpect est actuellement en cours d'élaboration, et plus il y a de gens qui l'utilisent (et complète l'enquête), mieux cela deviendra.

      Comment votre projet ou votre bibliothèque préférée a-t-il marqué? Assurez-vous de remplir le sondage, car il fournira des données précieuses pour mon projet de doctorat et aidera l'outil à s'améliorer!




Source link