Maison / Skype / Critères d'un bon code en programmation. Règles de programmation PHP (14 règles) Règles de programmation

Critères d'un bon code en programmation. Règles de programmation PHP (14 règles) Règles de programmation

Aujourd'hui, nous parlerons de l'apparence du code et de la raison pour laquelle nous avons besoin d'un code beau et lisible.

Malgré le fait que le programme soit exécuté par une machine, le code du programme est écrit par des personnes et pour des personnes - ce n'est pas un hasard si les langages de programmation de haut niveau ont une syntaxe et des commandes lisibles par l'homme. Les projets logiciels modernes sont développés par des groupes de programmeurs, parfois séparés non seulement par l'espace de bureau, mais aussi par les continents et les océans. Heureusement, le niveau de développement technologique permet d'utiliser les compétences des meilleurs développeurs, quelle que soit la localisation de leurs employeurs. Cette approche du développement impose de sérieuses exigences sur la qualité du code, en particulier sur sa lisibilité et son intelligibilité.

Il existe de nombreuses approches bien connues des critères de qualité du code, que presque tous les développeurs découvriront tôt ou tard. Par exemple, certains programmeurs adhèrent au principe de conception KISS (Keep It Simple, Stupid !). Cette méthode de développement est tout à fait juste et mérite le respect, et reflète également règle universelle bon code - simplicité et clarté. Cependant, la simplicité doit avoir ses limites : l'ordre dans le programme et la lisibilité du code ne doivent pas être le résultat de la simplification. En plus de la simplicité, il existe plusieurs règles plus simples. Et ils résolvent un certain nombre de problèmes.

  • Fournissez une couverture de code facile avec des tests et du débogage. Les tests unitaires sont le processus de test de modules, c'est-à-dire de fonctions et de classes qui font partie d'un programme. Lors de la création d’un programme, un développeur doit envisager de tester les capacités dès le début de l’écriture du code.
  • Facilitez la compréhension du code et l’utilisation du programme. Ceci est facilité par une dénomination logique et un bon style d’interface et d’implémentation.
  • Garantir une facilité de prise en charge. La structure bien pensée et mise en œuvre du programme vous permet de résoudre les problèmes liés au fonctionnement du programme sur un nouveau matériel ou une nouvelle plateforme.
  • Simplifiez le processus de modification supplémentaire. Plus la structure est optimisée, plus il est facile de modifier le code, d'ajouter de nouvelles fonctionnalités, d'améliorer les performances et de modifier l'architecture.
  • Assurer la pérennité du programme. Si des modifications sont apportées ou si des problèmes surviennent, des corrections peuvent être facilement apportées. Et une gestion correcte des erreurs facilite grandement le fonctionnement du produit logiciel.
  • Assurez-vous que le projet peut être pris en charge par plusieurs développeurs ou des communautés entières (particulièrement important pour les projets open source).

Tout code est la mise en œuvre des idées d'un développeur qui a un objectif précis : créer du divertissement, écrire des logiciels d'entreprise, développer des compétences en programmation, créer des logiciels industriels, etc... Il est important d'accepter dans un premier temps les règles de création d'un bon code et appliquez-les - une telle habitude fonctionnera d'autant plus intensément pour le programmeur. Le projet atteindra une grande échelle.

Critères d'un bon code en programmation – 8 règles de GeekBrains

Suivez le même style de code. Si un programmeur vient travailler dans une organisation, notamment une grande, il est le plus souvent initié aux règles de formatage du code dans un projet spécifique (accord de style de code). Il ne s'agit pas d'un caprice aléatoire de l'employeur, mais de la preuve d'une approche sérieuse.

Voici quelques-uns règles générales que vous pourriez rencontrer :

observer les ruptures d'accolades et les indentations - cela améliore considérablement la perception des blocs de code individuels
suivez la règle verticale - les parties d'une demande ou d'une condition doivent être au même indentation

if (typeof a ! == "indéfini" &&
type de b ! == "non défini" &&
typeof c === "string") (
//vos trucs
}

maintenir l'espace - mettre des espaces là où ils améliorent la lisibilité du code ; Ceci est particulièrement important dans les conditions composées, telles que les conditions de boucle.

pour (var je = 0; je< 100; i++) {
}

Dans certains environnements de développement, vous pouvez initialement définir des règles de formatage du code en chargeant les paramètres fichier séparé(disponible dans Visual Studio). Ainsi, tous les programmeurs du projet reçoivent automatiquement le même type de code, ce qui améliore considérablement la perception. On sait qu’il est assez difficile de réapprendre après de nombreuses années de pratique et de s’habituer aux nouvelles règles. Cependant, dans toute entreprise, le style de code est une loi qui doit être strictement respectée.

N'utilisez pas de chiffres magiques. Ce n'est pas un hasard si les nombres magiques sont classés comme modèles d'anti-programmation, en d'autres termes, les règles interdisant d'écrire du code de programme. Le plus souvent, un nombre magique comme anti-modèle est une constante utilisée dans le code, dont la signification n'est pas claire sans commentaire. De tels nombres compliquent non seulement la compréhension du code et nuisent à sa lisibilité, mais causent également des problèmes lors de la refactorisation.

Par exemple, le code contient la ligne :
DrawWindow(50, 70, 1000, 500);

Évidemment, cela ne provoquera pas d’erreurs dans le code, mais sa signification n’est pas claire pour tout le monde. Il vaut mieux ne pas être paresseux et écrire immédiatement comme ceci :

int gauche = 50 ;
int haut = 70 ;
largeur int = 1000 ;
hauteur int = 500 ;
DrawWindow(gauche, haut, largeur, hauteur) ;

Parfois, des nombres magiques apparaissent lors de l'utilisation de constantes généralement acceptées, par exemple lors de l'écriture du nombre π. Disons que les éléments suivants ont été ajoutés au projet :

CercleCarré = 3,14*rad*rad

Qu'est-ce qui ne va pas avec ça? Mais il y a de mauvaises choses. Par exemple, si pendant le travail vous devez effectuer un calcul avec une grande précision, vous devrez rechercher toutes les occurrences d'une constante dans le code, ce qui constitue un gaspillage de ressources en main-d'œuvre. Il est donc préférable de l'écrire ainsi :

const flotteur pi = 3,14 ;
CercleCarré = pi rad rad

À propos, parfois, d'autres programmeurs ne se souviennent pas de la signification de la constante que vous avez utilisée - ils ne la reconnaîtront tout simplement pas dans le code. Par conséquent, il est préférable d'éviter d'écrire des nombres sans déclaration dans des variables, et même les valeurs constantes sont préférables à déclarer. À propos, ces constantes se trouvent presque toujours dans les bibliothèques intégrées, le problème se résout donc de lui-même.

Utilisez des noms significatifs pour les variables, les fonctions et les classes. Tous les programmeurs connaissent le terme « obfuscation de code » - obscurcissement délibéré de l'année du programme à l'aide d'une application d'obscurcissement. Ceci est fait afin de masquer l'implémentation et transforme le code en un ensemble incompréhensible de symboles, renomme les variables, modifie les noms des méthodes, des fonctions, etc... Malheureusement, il arrive que le code semble déroutant même sans obscurcissement - précisément à cause aux noms insignifiants de variables et de fonctions : var_3698, myBestClass, NewMethodFinal, etc... Cela non seulement dérange les développeurs impliqués dans le projet, mais conduit également à une infinité de commentaires. Pendant ce temps, en renommant la fonction, vous pouvez vous débarrasser des commentaires - son nom parlera lui-même de ce qu'elle fait.

Le résultat est ce qu'on appelle un code auto-documenté - une situation dans laquelle les variables et les fonctions sont nommées de telle manière que lorsque l'on regarde le code, son fonctionnement est clair. L'idée d'un code auto-documenté a de nombreux partisans et opposants, dont les arguments méritent d'être écoutés. En général, nous recommandons de maintenir un équilibre et d'utiliser judicieusement à la fois les commentaires, les noms de variables « révélateurs » et les capacités de code auto-documenté lorsque cela est justifié.

Par exemple, prenons un code comme celui-ci :

// trouve une feuille, l'écrit dans r
si (x != nul) (
while (x.a != null) (
x = x.a;
r = x.n;
}
}
autre(
r = "" ;
}

Le commentaire doit indiquer clairement ce que fait exactement le code. Mais on ne sait absolument pas ce que signifient x.a et x.n. Essayons d'apporter des modifications comme ceci :
// trouve la feuille, écris le nom dans leafName
if (noeud ​​!= null) (
while (node.next != null) (
noeud = noeud.next;
leafName = node.name;
}
}
autre(
nomfeuille = "";
}

À ce stade, il est nécessaire de parler séparément des commentaires, car les auditeurs se posent toujours beaucoup de questions sur l'opportunité et la nécessité de leur utilisation. Lorsqu'il y a beaucoup de commentaires, ils conduisent à une faible lisibilité du code. Il est presque toujours possible d'apporter des modifications au code de telle sorte que le besoin de commentaires disparaisse. Dans les grands projets, les commentaires sont justifiés en cas d'utilisation de l'API, indiquant la connexion du code d'un module tiers, indiquant des questions controversées ou des points nécessitant un traitement ultérieur.

Combinons deux règles plus importantes en une seule explication. Créez des méthodes comme nouveau niveau abstractions avec des noms significatifs Et garder les méthodes compactes. En général, la modularité du code est aujourd'hui accessible à tous les programmeurs, ce qui signifie qu'il faut s'efforcer de créer des abstractions lorsque cela est possible. L'abstraction est l'un des moyens de masquer les détails d'implémentation des fonctionnalités. En créant de petites méthodes distinctes, le programmeur obtient un bon code, divisé en blocs contenant l'implémentation de chacune des fonctions. Cette approche augmente souvent le nombre de lignes de code. Certaines recommandations indiquent même que la longueur de la méthode ne doit pas dépasser 10 lignes. Bien entendu, la taille de chaque méthode est entièrement à la discrétion du développeur et dépend de nombreux facteurs. Notre conseil : tout est simple, rendez la méthode compacte pour qu'une méthode effectue une tâche. Il est plus facile d'améliorer des entités distantes individuelles, par exemple en insérant une vérification des données d'entrée dès le début de la méthode.

Pour illustrer ces règles, reprenons l'exemple du paragraphe précédent et créons une méthode dont le code ne nécessite pas de commentaires :
string GetLeafName (nœud de nœud) (
if (noeud ​​!= null) (
while (node.next != null) (
noeud = noeud.next;
}
renvoie le nœud.nom ;
}
retour "";
}

Et enfin, masquez l'implémentation de la méthode :

LeafName = GetLeafName (nœud); ...

Au début des méthodes, vérifiez les données d'entrée. Au niveau du code, il est impératif de faire des contrôles de saisie dans toutes ou presque toutes les méthodes. Cela est dû au comportement des utilisateurs : les futurs utilisateurs peuvent saisir toutes les données susceptibles de provoquer un dysfonctionnement du programme. Quelle que soit la méthode, même utilisée une seule fois, il est impératif d’organiser la vérification des données et de créer une gestion des erreurs. Cela en vaut la peine car la méthode agit non seulement comme une couche d’abstraction, mais est également nécessaire à la réutilisation. En principe, il est possible de diviser les méthodes entre celles dans lesquelles il est nécessaire de faire une vérification et celles dans lesquelles il n'est pas nécessaire de le faire, mais pour une confiance totale et une protection contre un « utilisateur rusé », il est préférable de vérifier toutes les données d'entrée.

Dans l'exemple ci-dessous, nous insérons une vérification pour nous assurer que nous ne recevons pas de valeur nulle en entrée.
Lister GetEvenItems(Éléments de la liste) (
Assert(éléments != null);

Résultat de la liste = new List();
foreach (int i en éléments) (
si (je % 2 == 0) (
result.add(i);
}
}
renvoyer le résultat ;
}

Implémentez uniquement la relation « est » en utilisant l'héritage. Dans d'autres cas - composition. La composition est l'un des modèles clés visant à rendre le code plus facile à lire et, contrairement à l'héritage, ne viole pas le principe d'encapsulation. Disons que vous avez une classe Steering wheel et une classe Wheel. La classe Car peut être implémentée en tant que successeur de la classe ancêtre Steering Wheel, mais la classe Car a également besoin des propriétés de la classe Wheel.

En conséquence, le programmeur commence à créer un héritage. Mais même du point de vue de la logique philistine, la classe Car est une composition d'éléments. Disons qu'il existe un code comme celui-ci, lorsqu'une nouvelle classe est créée par héritage (la classe ScreenElement hérite des champs et des méthodes de la classe Coordonnée et étend cette classe) :

Coordonnée de classe (
public int x ;
intégration publique ;
}
classe ScreenElement : Coordonnée (
symbole de caractère public ;
}

Nous utilisons la composition :
Coordonnée de classe (
public int x ;
intégration publique ;
}
classe ScreenElement (
Coordonnées publiques ;
symbole de caractère public ;
}

La composition est un bon remplacement pour l'héritage ; ce modèle est plus simple pour une meilleure compréhension du code écrit. Vous pouvez suivre cette règle : choisissez l'héritage uniquement si la classe souhaitée est similaire à la classe ancêtre et n'utilisera pas les méthodes d'autres classes. De plus, la composition évite au programmeur un autre problème : elle élimine les conflits de noms qui se produisent lors de l'héritage. La composition présente également un inconvénient : multiplier le nombre d’objets peut avoir un impact sur les performances. Mais encore une fois, cela dépend de l’ampleur du projet et doit être évalué par le promoteur au cas par cas.

Séparez l'interface de l'implémentation. Toute classe utilisée dans un programme se compose d'une interface (ce qui est accessible lorsque la classe est utilisée en externe) et d'une implémentation (méthodes). Dans le code, l'interface doit être séparée de l'implémentation à la fois pour respecter l'un des principes de la POO, l'encapsulation, et pour améliorer la lisibilité du code.

Prenons un cours :

class Square (bord flottant public; zone flottante publique; )

Une autre classe :

classe Carré( flotteur public GetEdge(); flotteur public GetArea(); public void SetEdge ( flotter e) ; public vide SetArea ( faire flotter un) ; bord flottant privé ; zone flottante privée; )

Le deuxième cas est préférable car il masque l'implémentation à l'aide du modificateur d'accès privé. En plus d'améliorer la lisibilité du code, séparer l'interface de l'implémentation, combiné au maintien d'une interface petite, présente un autre avantage important : en cas de dysfonctionnement du programme, il suffit de vérifier quelques fonctions pour trouver la cause de l'échec. Plus les fonctions et les données sont ouvertes, plus il est difficile de localiser la source de l'erreur. Cependant, l’interface doit être complète et doit permettre de faire tout ce qu’il faut faire, sinon elle ne sert à rien.

Lors du webinaire, la question a été posée : « Est-il possible de bien écrire tout de suite et de ne pas refactoriser ? Probablement, après quelques années, voire décennies de programmation, cela sera possible, surtout s'il existe une première vision de l'architecture du programme. Mais vous ne pouvez jamais prédire l’état final d’un projet après plusieurs versions et itérations. C'est pourquoi il est important de toujours garder à l'esprit les règles énumérées qui garantissent la pérennité et la capacité de développement de votre programme.

La plupart des articles écrits sur le thème de l'embauche de programmeurs semblent plus ou moins identiques. En règle générale, ces articles recommandent de « n’embaucher que les meilleurs ». J'avoue que je ne suis pas ravi de ce conseil car il semble trop vague. C’est comme si vous veniez chez un concessionnaire automobile et demandiez au vendeur quelle voiture il vous recommanderait, et il vous répondrait que « Meilleur » n’est indiqué pour personne chez le concessionnaire.

Ne vous méprenez pas, je ne vous conseille pas de rechercher délibérément des programmeurs médiocres. Bien entendu, tout le monde souhaite embaucher uniquement les programmeurs les plus talentueux et les plus expérimentés. Les décisions d’embauche comportent des enjeux élevés. Votre décision affectera le travail de toute l’équipe et de ses membres individuels. Comme ils disent:

"Mieux vaut rejeter un bon candidat que d'en accepter un mauvais... Si vous avez le moindre doute, n'embauchez pas"

Mais les conseils standards m'énervent toujours. Ce n’est pas tant le conseil lui-même qui compte, mais plutôt le fait que les gens ont tendance à mal le comprendre. Si elle est appliquée sans autres ajustements, cette pratique crée principalement un sentiment d’auto-supériorité. Cet effet est particulièrement courant chez les programmeurs, car l'élitisme nous est en quelque sorte inhérent. Lorsque nous entendons dire que nous ne devrions embaucher que « les meilleurs », ce conseil subit une transformation subconsciente :

"Le meilleur?" Mais c'est moi! Je suis le meilleur". Bien sûr, je dois embaucher des personnes aussi douées, aussi intelligentes et aussi belles que moi. Et pourquoi salir ma merveilleuse équipe avec toutes sortes de canailles ?

Qui sont les meilleurs programmeurs ?

Bien entendu, cette approche ne crée pas les meilleures conditions pour la prise de décision. La règle standard fonctionne bien mieux si nous la comprenons un peu différemment :

« Je veux former l’équipe la plus efficace possible. En embauchant un employé supplémentaire, je m'efforce non seulement d'augmenter le nombre d'employés. Chaque personne embauchée doit améliorer mon équipe d’une manière ou d’une autre. Je ne recherche pas du tout une personne aussi douée que moi. J’ai plutôt besoin de quelqu’un qui soit plus doué que moi dans au moins un domaine important.

Chef

Le pire patron est celui qui se sent menacé par son équipe. Consciemment ou non, il craint « les meilleurs » et embauche donc constamment des personnes contre lesquelles il aura l'air avantageux.

Vous pouvez probablement vous en sortir dans une grande entreprise avec cette approche. Je soupçonne fortement que le Shaggy Boss dans les bandes dessinées de Dilbert était basé sur la vie.

Mais dans le monde des petites sociétés de développement, les choses sont complètement différentes. Si vous êtes le fondateur ou le « gourou en chef » d’une petite entreprise, essayez de vous examiner attentivement, honnêtement et objectivement. Si vous faites partie de ceux qui se sentent menacés par leurs propres employés, arrêtez-vous et réfléchissez. Tant que vous ne parviendrez pas à résoudre ce problème, les chances de constituer une équipe efficace seront nulles.

Personnel des programmeurs

Le véritable objectif de la règle standard n’est pas de caresser notre ego, mais de nous rappeler de ne pas avoir peur de rechercher de meilleurs travailleurs. Il est néanmoins nécessaire de clarifier plus précisément ce que signifie réellement le mot « meilleur ».

Recherchez des personnes conscientes d’elles-mêmes

Les « meilleurs » employés n’arrêtent jamais d’apprendre.

Je considère que l’un des critères les plus importants lors de l’évaluation des candidats est ce que j’appelle personnellement la « dérivée première ». Cette personne étudie-t-elle ? Est-ce qu'il avance ou reste immobile ? (Certaines de mes réflexions sur ce sujet sont publiées dans l'article « Career Calculus » sur mon blog).

Les personnes qui prennent au sérieux leur réussite future ont plus de chances de réussir. Cet état d’esprit est souvent l’attribut le plus important dans les décisions d’embauche.

Cela ne signifie pas que vous devez embaucher uniquement des personnes qui souhaitent réussir. Tout le monde veut réussir. Mon conseil est d’embaucher des personnes qui prennent au sérieux la formation continue. Ces gens ne perdent pas de temps à essayer de vous convaincre de ce qu'ils savent. Ils se concentrent sur le passé plutôt que sur le futur. Pendant que vous les interviewez, ils vous interviewent, essayant de voir ce qu'ils peuvent apprendre de vous.

Comment trouver une telle personne ?

Un signe clair est que les personnes qui s'engagent dans une formation continue savent bien ce qu'elles ne savent pas. Ils connaissent leurs faiblesses et n’ont pas peur d’en parler.

Lors des entretiens, il est souvent demandé aux candidats de décrire leur principale faiblesse. Même si cette question est terriblement traditionnelle, je l’aime bien.

Malheureusement, de nombreux candidats tentent d'éviter de répondre à la question. Ils vont dans une librairie et achètent un livre sur les entretiens. Le livre me prévient que je leur poserai cette question, et suggère des moyens « créatifs » pour éviter de répondre sincèrement :

  • Parfois, je travaille trop.
  • Parfois, mon souci du détail irrite les autres membres du groupe.

Lorsque je demande à un candidat de parler de ses faiblesses, j’attends une réponse intelligente, sincère et confiante. Quand j’entends un candidat admettre une faiblesse, cela fait forte impression. Mais si un candidat donne une réponse évasive directement tirée du livre, je commence à penser au prochain candidat.

Embauchez des développeurs, pas des programmeurs

Dans une petite entreprise, les « meilleurs » programmeurs sont ceux qui font plus que simplement programmer. Essayez d'embaucher des développeurs, pas des programmeurs. Bien que ces mots soient souvent utilisés de manière interchangeable, je les différencie. Il s'agit de sur les différences entre une programmation simple et la participation à un groupe travaillant sur un produit. Permettez-moi de citer un article que j'ai écrit sur ce sujet sur mon blog :

« Dans cet article, un « programmeur » est quelqu'un qui est uniquement impliqué dans le codage de nouvelles fonctionnalités et [si vous avez de la chance] la correction des bugs. Les programmeurs n'écrivent pas de spécifications. Ils ne créent pas de cas de test automatisés. Ils n'aident pas à soutenir systèmes automatisés les assemblées sont à jour. Ils n'aident pas les clients à décider problèmes techniques. Ils n'aident pas à rédiger la documentation, ne participent pas aux tests et ne lisent même pas le code. Tout ce qu'ils font, c'est écrire du nouveau code. Une petite entreprise ne devrait pas garder de telles personnes.

Au lieu de « programmeurs » (des personnes spécialisées dans l’écriture de code), vous avez besoin de « développeurs » (des personnes qui contribuent de plusieurs manières au succès du produit).

Que signifie la règle standard ? Quelle est exactement l’attribut qui doit être mesuré pour déterminer si un candidat est le « meilleur » ?

Cette règle est généralement considérée comme s’appliquant uniquement aux compétences en codage. Mais les vrais bons programmeurs sont intelligents. Ils comprennent des choses qui ne sont généralement pas enseignées et peuvent travailler 10 fois plus efficacement que le programmeur moyen. Bien entendu, il serait judicieux de rechercher l'une de ces personnalités « décuplées », notamment dans les grandes organisations où des spécialistes comme les programmeurs « purs » conviennent tout à fait. Mais une petite entreprise a besoin de polyvalence. Souvent, les membres de l’équipe doivent exécuter plusieurs fonctions au-delà de la simple écriture de code. Dans de tels cas, il est très important de trouver le meilleur développeur, et cette personne ne sera pas nécessairement le meilleur programmeur.

Ainsi, la règle standard fonctionne plutôt bien, mais à partir de recommandations générales, il est nécessaire de passer à des recommandations plus spécifiques. Pour résumer ce qui a été discuté dans les sections précédentes, voici 10 questions à vous poser lorsque vous envisagez un candidat pour un poste de développeur :

  1. Ce candidat peut-il faire quelque chose pour le groupe que personne d’autre ne peut faire ?
  2. Est-il dans un processus d’apprentissage constant ?
  3. Ce candidat est-il conscient de ses faiblesses et peut-il en discuter sereinement ?
  4. Dans quelle mesure ce candidat est-il polyvalent et capable de faire « tout ce qu’il faut » pour faire du produit un succès commercial ?
  5. Le candidat fait-il partie des 10x programmeurs ?
  6. A-t-il un baccalauréat d'une université réputée ?
  7. Si le candidat est titulaire d'un doctorat, existe-t-il d'autres indications indiquant qu'il a la capacité de développer des produits commerciaux ?
  8. Le candidat a-t-il une expérience de travail au sein d’équipes ayant développé des produits commerciaux ?
  9. Le candidat peut-il fournir des exemples de bon code ?
  10. Le candidat aime-t-il suffisamment programmer pour écrire du code pendant son temps libre ?

Une réponse positive aux 10 questions n’est pas requise. Je ne vais même pas préciser le nombre maximum de réponses positives requis pour accepter un candidat. L'embauche est une loterie et chaque question peut servir de guide pour évaluer les aptitudes d'un candidat.

En fin de compte, toute décision d’embauche est une décision discrétionnaire et aucune garantie n’est possible. Pourtant, en prêtant attention à ces problèmes, vous aurez plus de chances de ne pas regretter votre décision plus tard.

Alors maintenant, vous avez un problème si vous écrivez une bibliothèque qui sera utilisée à la fois par du code old-school écrit avec wchar_t défini comme un alias pour un code court non signé et par du code new-school écrit avec wchar_t comme type interne distinct. Quel type de données devez-vous utiliser pour les paramètres de chaîne ?

Ceci est une traduction de La triste histoire des spécificateurs de format Unicode printf-style dans Visual C++.

Windows a implémenté Unicode plus tôt que la plupart des autres systèmes d'exploitation. Par conséquent Solutions Windows car de nombreux problèmes sont différents des solutions apportées par ceux qui ont attendu que la poussière retombe¹. L’exemple le plus frappant en est en utilisant Windows UCS-2 comme encodage Unicode. C'était alors l'encodage recommandé par le Consortium Unicode car Unicode 1.0 ne supportait que 65"536 caractères². Le Consortium Unicode a changé d'avis cinq ans plus tard, mais il était alors trop tard pour Windows, qui avait déjà sorti Win32s, Windows NT 3.1, Windows NT 3.5, Windows NT 3.51 et Windows 95, qui utilisaient tous UCS-2³.

Mais aujourd'hui, nous allons parler des chaînes de format de style printf.

C'est la traduction de Si FlushInstructionCache ne fait rien, pourquoi faut-il l'appeler, revisité .

Vous êtes censé appeler la fonction FlushInstructionCache lorsque vous générez ou modifiez du code exécutable au moment de l'exécution - afin que le processeur, lors de l'exécution de votre code généré/modifié, lise les instructions que vous avez écrites, plutôt que les anciennes instructions qui peuvent rester dans l'instruction du processeur. cache.

Nous l'avons appris auparavant. En effet, un simple appel de fonction suffisait pour vider le cache des commandes.

Mais sous Windows NT, la fonction FlushInstructionCache le fait vrai travail, car il doit demander à tous les autres processeurs de vider leurs caches.

Cependant, si vous regardez Windows 10, vous constaterez que la fonction FlushInstructionCache ressemble à la version Windows 95 : elle ne fait rien.

Quel est le problème?

Dernièrement, j'ai vu peu de code vraiment bon, beaucoup de code médiocre et Très beaucoup de mauvaises choses. (Une grande partie de ce que j'ai écrit auparavant - surtout quand je débutais - s'applique hélas à ce dernier.) En lisant des articles aléatoires sur Internet et des livres professionnels, je suis arrivé à la conclusion qu'écrire du bon code est facile. Incroyablement difficile, mais en même temps facile. En fait, c’est si simple que cela se résume à trois règles.

  1. Écrivez du code pour les personnes, pas pour les machines.
  2. Chaque morceau de code doit effectuer une tâche.
En les suivant systématiquement, vous écrirez du bon code. Dans n’importe quel langage de programmation et dans n’importe quel paradigme. Le problème est que c'est très difficile. Tous nécessitent de la discipline, et les deux derniers nécessitent dans la plupart des cas également une longue réflexion.
Écrivez du code pour les personnes, pas pour les machines.
C’est la plus importante des trois règles et elle sous-tend les deux autres. Écrivez du code facile à lire pour les humains ; Laissez le travail acharné à l’ordinateur. Utilisez des noms de variables et de méthodes significatifs. Ne créez pas de chaînes logiques complexes là où des chaînes logiques simples peuvent être utilisées. N'essayez pas d'en mettre autant que possible sur une seule ligne. Observer style uniformeécrire du code qui a une indentation significative. Si vos fichiers sont si volumineux qu’il devient difficile de les parcourir, divisez-les en plusieurs fichiers plus petits.

De nombreux programmeurs essaient d'écrire quelque chose qui, à leur avis, fonctionne plus rapidement, réduit la taille de l'application - en un mot, « facilite » le travail de l'ordinateur. C'est bien, mais n'oubliez pas qu'il est plus important d'écrire du code facile à lire et à maintenir pour les autres.

Votre compilateur (ou interpréteur) peut gérer des styles de code complètement différents. Pour lui n Et nombre d'objets- C'est le même. Pour les gens - non. Leur lecture dans le code sera longue, même si le but de la variable vous semble évident.

Imaginez que vous ayez créé un petit script pour vous-même et qu'après quelques années, vous deviez le modifier un peu. Que préféreriez-vous voir : un script bien structuré, avec des commentaires et un nom clair, ou une fonction sans un seul commentaire et avec des variables dont le but est presque impossible à comprendre ?

Si vous faites quelque chose de non évident pour optimiser un morceau de code, décrivez dans un commentaire ce qu'il fait exactement. Mais n'oubliez pas que dans la plupart des cas, vous ne pourrez pas optimiser le programme mieux que le compilateur. La réalité est qu’il est plus intelligent que vous. C'est un fait : les compilateurs se sont améliorés au fil des décennies de travail acharné des professionnels. Il existe des exceptions, mais elles ne font que confirmer la règle.

Écrivez du code que les gens peuvent comprendre.

Ne te répète pas
Je ne peux pas compter combien de fois j'ai vu le même morceau de code dans différentes parties d'un programme. Aujourd'hui encore, je travaillais sur une grande fonction dans du code existant et j'ai vu les mêmes conditions dans deux parties différentes de l'expression conditionnelle. J'ai dû passer du temps à m'assurer qu'il ne s'agissait que d'une erreur de programmation.

Lorsque vous répétez le même fragment à plusieurs endroits, vous devrez tôt ou tard y revenir pour corriger une erreur ou ajouter quelque chose de nouveau. Cela rend le code difficile à maintenir. Au lieu de vous répéter, placez l'extrait dans une classe ou une fonction distincte à laquelle vous pourrez faire appel dès que vous en aurez besoin. Si vous appelez plusieurs méthodes dans le même ordre à différents endroits, enveloppez-les dans une fonction distincte.

Pensez à ce qui sera plus facile à comprendre en regardant le code : un fragment de 30 lignes qui libère un bloc de mémoire, ou un appel de fonction clearMapVariableMemory()?
Vous devrez peut-être étudier l'extrait plus tard, mais même dans ce cas, travailler avec une fonction distincte sera plus facile.

Le même principe peut être appliqué aux données. Si vous utilisez fréquemment les mêmes variables, déplacez-les dans une classe ou un type de données distinct.

Si vous suivez cette règle, tous les changements seront universels - vous n'aurez pas à retravailler des dizaines d'endroits pour apporter un petit amendement.

Ne vous répétez pas.

Chaque morceau de code doit effectuer une tâche
La dernière règle s’appuie sur les deux précédentes : chaque élément de votre code ne doit faire qu’une seule chose. C'est vrai à tous les niveaux : pour les expressions, les fonctions et méthodes, les classes et les objets.

Il y a quelques années, un développeur m'a montré un morceau de code qui ne fonctionnait pas. Il a fallu plusieurs heures au programmeur pour le comprendre. Finalement, le problème a été découvert dans les opérateurs post-incrémentaux C (dans des cas particuliers, leur comportement varie d'un compilateur à l'autre). Par la suite, en lisant un livre sur le développement, j'ai remarqué que le véritable problème n'était pas les déclarations, mais le fait qu'un seul fragment était chargé d'effectuer de nombreuses tâches différentes.

Autant que je me souvienne, la ligne contenant l'erreur faisait partie d'une opération ternaire. Celui-ci, à son tour, effectuait plusieurs opérations sur les pointeurs pour calculer la condition, et plusieurs autres, en fonction du résultat de l'expression conditionnelle. C'était bon exempleécrire du code principalement pour une machine, pas pour une personne : personne, à l'exception de l'auteur du fragment, ne comprendra ce que fait exactement la ligne, même après l'avoir lue plusieurs fois. Si le programmeur qui a écrit le code avait divisé la logique en plusieurs parties, il aurait fallu beaucoup moins de temps pour résoudre le problème.

Vous ne devez pas récupérer, traiter et modifier les données de la même manière. La description verbale de chaque fonction doit être contenue dans une phrase. Le but de chaque ligne doit être clair. Cela rend le code compréhensible pour les gens. Aucun de nous ne peut stocker dans sa tête une fonction de plusieurs milliers de lignes. Il n’y a aucune raison impérieuse de créer de telles fonctions au lieu de plusieurs petites méthodes utilisées ensemble.

Il convient de noter que ce n'est pas si difficile : pour accomplir une grande tâche, il suffit de la diviser en plusieurs plus petites, chacune étant dans une fonction distincte. Il est important de s’assurer que le but de chaque fonction reste clair, sinon le code devient trop confus.

Chaque morceau de votre code doit faire une chose.

Conclusion
Écrire du bon code est un travail difficile. Je programme depuis quatre ans - pas si longtemps, mais suffisamment pour constater pas mal de problèmes, dont le mien. Il m'est apparu clairement que nous compliquons le développement en ne suivant pas ces règles simples. Il est difficile de les suivre correctement : il n'est pas toujours évident de savoir où une classe ou une méthode distincte est nécessaire. C'est une compétence. Il faut beaucoup de temps pour devenir un bon programmeur. Mais si nous ne respectons pas ces règles, l’écriture et la maintenance du code deviendront encore plus difficiles.

Traduction de l'article

15 règles pour rédiger un code de qualité

Il existe une myriade de façons d’écrire du mauvais code. Heureusement, pour s’élever au niveau du code de qualité, il suffit de suivre 15 règles. Les suivre ne fera pas de vous un maître, mais cela vous permettra de l'imiter de manière convaincante.

Règle 1 : Suivez les normes de codage.

Chaque langage de programmation possède sa propre norme de formatage de code, qui indique comment mettre en retrait, où placer les espaces et les parenthèses, comment nommer les objets, comment commenter le code, etc.

Par exemple, dans ce bout de code, selon la norme, il y a 12 erreurs :

Pour(i=0 ;i

Étudiez attentivement la norme, apprenez les bases par cœur, suivez les règles comme les commandements, et vos programmes seront meilleurs que la plupart des programmes rédigés par des diplômés universitaires.

De nombreuses organisations adaptent leurs normes à leurs besoins spécifiques. Par exemple, Google a développé des normes pour plus de 12 langages de programmation. Ils sont bien pensés, alors n'hésitez pas à les consulter si vous avez besoin d'aide pour programmer avec Google. Les normes incluent même des paramètres d'éditeur pour vous aider à respecter le style, ainsi que des outils spéciaux pour vérifier que votre code est conforme à ce style. Utilise les.

Règle 2 : Donnez des noms descriptifs.

Limités par des télétypes lents et encombrants, les programmeurs des temps anciens utilisaient des contrats pour les noms de variables et de procédures afin d'économiser du temps, des frappes au clavier, de l'encre et du papier. Cette culture est présente dans certaines communautés dans un souci de maintien de la compatibilité ascendante. Prenez, par exemple, la fonction C révolutionnaire wcscspn (large étendue de complément de chaîne de caractères). Mais cette approche n’est pas applicable dans le code moderne.

Utilisez des noms longs et descriptifs comme complémentSpanLength pour vous aider, vous et vos collègues, à comprendre votre code à l'avenir. Les exceptions sont quelques variables importantes utilisées dans le corps d'une méthode, telles que les itérateurs de boucle, les paramètres, les valeurs temporaires ou les résultats d'exécution.

Il est bien plus important de réfléchir longuement et sérieusement avant de nommer quelque chose. Le nom est-il exact ? Vouliez-vous dire highPrice ou bestPrice ? Le nom est-il suffisamment spécifique pour éviter son utilisation dans d’autres contextes pour des objets similaires ? Ne serait-il pas préférable d'appeler la méthode getBestPrice au lieu de getBest ? Est-ce qu'il convient mieux que d'autres noms similaires ? Si vous disposez d'une méthode ReadEventLog, vous ne devez pas en appeler une autre NetErrorLogRead. Si vous nommez une fonction, le nom décrit-il la valeur de retour ?

Enfin, quelques règles de dénomination simples. Les noms de classe et de type doivent être des noms. Le nom de la méthode doit contenir un verbe. Si une méthode détermine si certaines informations sur un objet sont vraies ou fausses, son nom doit commencer par « est ». Les méthodes qui renvoient les propriétés des objets doivent commencer par « get » et les méthodes qui définissent les valeurs des propriétés doivent commencer par « set ».

Règle 3 : Commentaire et document.

Commencez chaque méthode et procédure par une description dans un commentaire de ce que fait la méthode ou la procédure, les paramètres, la valeur de retour et erreurs possibles et les exceptions. Décrivez dans les commentaires le rôle de chaque fichier et classe, le contenu de chaque champ de classe et les principales étapes d'un code complexe. Écrivez des commentaires au fur et à mesure que vous développez le code. Si vous pensez les écrire plus tard, vous vous trompez.

De plus, assurez-vous que votre application ou bibliothèque dispose d'un manuel qui explique ce que fait votre code, définit ses dépendances et fournit des instructions pour le créer, le tester, l'installer et l'utiliser. Le document doit être court et pratique ; un simple fichier README suffit souvent.

Règle 4. Ne vous répétez pas.

Ne copiez et ne collez jamais de code. Au lieu de cela, isolez la partie commune dans une méthode ou une classe (ou une macro, si nécessaire) et utilisez-la avec les paramètres appropriés. Évitez d'utiliser des données et des morceaux de code similaires. Utilisez également les techniques suivantes :

  • Générez des références API à partir de commentaires à l'aide de Javadoc et Doxygen.
  • Génération automatique de tests unitaires basés sur des annotations ou des conventions de dénomination.
  • Générez des PDF et des HTML à partir d'une seule source balisée.
  • Récupérer la structure de classe de la base de données (ou vice versa).

Règle 5 : Vérifiez les erreurs et répondez-y.

Les méthodes peuvent renvoyer des symptômes d’erreur ou lever des exceptions. Traitez-les. Ne comptez pas sur le fait que le disque ne se remplira jamais, que votre fichier de configuration sera toujours là, que votre application fonctionnera avec tous les droits dont elle a besoin, que les demandes d'allocation de mémoire réussiront toujours ou que votre connexion n'échouera jamais. Oui, une bonne gestion des erreurs est difficile à écrire, et cela rend le code plus long et plus difficile à lire. Mais ignorer les erreurs ne fait que balayer le problème sous le tapis, où un utilisateur peu méfiant le découvrira un jour.

Règle 6 : divisez votre code en parties courtes et discrètes.

Chaque méthode, fonction ou bloc de code doit tenir dans une fenêtre d'écran normale (25 à 50 lignes). S'il est plus long, divisez-le en morceaux plus courts. Même au sein d'une méthode, divisez le code long en blocs, dont vous pouvez décrire l'essence dans un commentaire au début de chaque bloc.

De plus, chaque classe, module, fichier ou processus doit effectuer un certain type de tâche. Si un morceau de code effectue des tâches complètement différentes, divisez-le en conséquence.

Règle 7. Utilisez des API de framework et des bibliothèques tierces.

Découvrez les fonctionnalités disponibles via l'API de votre framework. et aussi ce que les bibliothèques tierces matures peuvent faire. Si les bibliothèques sont prises en charge par votre gestionnaire de packages système, elles seront probablement bon choix. Utilisez un code qui décourage l’envie de réinventer la roue (et un code carré inutile en plus).

Règle 8 : Ne sur-concevez pas.

Concevez uniquement ce qui est pertinent actuellement. Votre code peut être rendu assez général afin qu'il prenne en charge la poursuite du développement, mais seulement si cela ne devient pas trop compliqué. Ne créez pas de classes paramétrées, d'usines, de hiérarchies profondes et d'interfaces cachées pour résoudre des problèmes qui n'existent même pas - vous ne pouvez pas deviner ce qui se passera demain. En revanche, lorsque la structure du code ne convient pas à la tâche, n'hésitez pas à le refactoriser.

Règle 9 : Soyez cohérent.

Faites les mêmes choses de la même manière. Si vous développez une méthode dont la fonctionnalité est similaire à celle d’une méthode existante, utilisez un nom similaire, un ordre de paramètres similaire et une structure de corps similaire. Il en va de même pour les cours. Créez des champs et des méthodes similaires, attribuez-leur des interfaces similaires et faites correspondre les nouveaux noms à ceux existants dans des classes similaires.

Votre code doit suivre les conventions de votre framework. Par exemple, il est de bonne pratique de rendre les plages semi-ouvertes : fermées (incluses) à gauche (au début de la plage) et ouvertes (exclusives) à droite (à la fin). S'il n'y a pas d'accord pour un cas particulier, alors faites un choix et respectez-le fanatiquement.

Règle 10 : Évitez les problèmes de sécurité.

Le code moderne fonctionne rarement de manière isolée. Il existe un risque imminent de devenir la cible d’une attaque. Il n'est pas nécessaire qu'ils proviennent d'Internet ; l'attaque peut se produire via les données d'entrée de votre application. En fonction de votre langage de programmation et de votre domaine, vous devrez peut-être vous soucier des débordements de tampon, des scripts intersites, de l'injection SQL et d'autres problèmes similaires. Étudiez ces problèmes et évitez-les dans votre code. Ce n'est pas difficile.

Règle 11 : Utilisez des structures de données et des algorithmes efficaces.

Un code simple est souvent plus facile à maintenir que le même code mais modifié pour plus d’efficacité. Heureusement, vous pouvez combiner maintenabilité et efficacité en utilisant les structures de données et les algorithmes fournis par votre framework. Utilisez des cartes, des ensembles, des vecteurs et des algorithmes qui fonctionnent avec eux. Cela rendra votre code plus propre, plus rapide, plus évolutif et plus efficace en termes de mémoire. Par exemple, si vous stockez mille valeurs dans un ensemble trié, alors l'opération d'intersection trouvera éléments communs avec un autre ensemble pour le même nombre d'opérations, et non pour un million de comparaisons.

Règle 12. Utilisez des tests unitaires.

La complexité des logiciels modernes les rend plus coûteux à installer et plus difficiles à tester. Une approche productive consisterait à accompagner chaque morceau de code de tests vérifiant l’exactitude de son fonctionnement. Cette approche simplifie le débogage car cela permet de détecter les erreurs plus tôt. Les tests unitaires sont nécessaires lorsque vous programmez dans des langages typés dynamiquement comme Python et JavaScript, car ils ne détectent les erreurs qu'au moment de l'exécution, tandis que les langages typés statiquement comme Java, C# et C++ peuvent en détecter certaines au moment de la compilation. temps. Les tests unitaires vous permettent également de refactoriser votre code en toute confiance. Vous pouvez utiliser XUnit pour faciliter l'écriture de tests et automatiser leur exécution.

Règle 13 : Gardez votre code portable.

Sauf si vous avez une raison spécifique, n'utilisez pas de fonctionnalités disponibles uniquement sur une plate-forme spécifique. Ne comptez pas sur certains types de données (comme les entiers, les pointeurs et les horodatages) pour avoir une longueur spécifique (par exemple, 32 bits), car ce paramètre diffère selon les plates-formes. Gardez les messages du programme séparés du code et ne codez pas en dur les paramètres spécifiques à la culture (tels que les séparateurs décimaux ou les formats de date). Des conventions sont nécessaires pour garantir que le code peut s'exécuter dans différents pays, alors rendez la localisation aussi simple que possible.

Règle 14 : Rendez votre code composable.

Une simple commande devrait assembler votre code dans un formulaire prêt à être distribué. La commande devrait vous permettre de créer et d'exécuter rapidement les tests nécessaires. Pour atteindre cet objectif, utilisez des outils de construction automatisés tels que Make, Apache Maven ou Ant. Idéalement, vous devriez installer un système d'intégration qui vérifiera, créera et testera votre code à chaque fois qu'il change.

Règle 15 : Placez tout dans le contrôle de version.

Tous vos éléments - code, documentation, sources d'outils, scripts de build, données de test - doivent être sous contrôle de version. Git et GitHub rendent cette tâche peu coûteuse et sans tracas. Mais de nombreux autres outils et services puissants sont également à votre disposition. Vous devriez pouvoir créer et tester votre programme sur un système configuré simplement en le téléchargeant depuis le référentiel.

Conclusion.

En intégrant ces 15 règles à votre pratique quotidienne, vous finirez par créer un code plus facile à lire, bien testé, plus susceptible de fonctionner correctement et beaucoup plus facile à modifier le moment venu. Vous éviterez également à vous-même et à vos utilisateurs bien des maux de tête.