Écrire du code élégant et lisible

Dans ce tutoriel, nous allons vous présenter neuf techniques pratiques pour écrire du code élégant et lisible. Nous ne parlerons pas d'architectures, de langages ou de plates-formes spécifiques. L'accent est mis sur l'écriture d'un meilleur code. Commençons.

"Mesurer la progression de la programmation par lignes de code revient à mesurer le progrès de la construction d'un avion en poids." - Bill Gates

introduction

Si vous êtes développeur, il est probable que vous ayez parfois écrit du code et que, après quelques jours, quelques semaines ou quelques mois, vous ayez jeté un œil sur lui et vous vous êtes dit: "À quoi sert cette partie de code?" La réponse à cette question aurait pu être "je ne sais vraiment pas!" Dans ce cas, la seule chose que vous pouvez faire est de parcourir le code du début à la fin, en essayant de comprendre ce que vous pensiez lorsque vous l'avez écrit..

Cela se produit principalement lorsque nous sommes paresseux et que nous souhaitons simplement implémenter la nouvelle fonctionnalité demandée par le client. Nous voulons juste faire le travail avec le moins d'effort possible. Et quand cela fonctionne, nous ne nous soucions pas du code lui-même, car le client ne verra jamais le laid la vérité, encore moins la comprendre. Droite? Faux. De nos jours, la collaboration sur les logiciels est devenue la méthode par défaut et les utilisateurs voient, lisent et inspectent le code que vous écrivez. Même si vos collègues ne scrutent pas votre code, vous devriez prendre l'habitude d'écrire un code clair et lisible. Toujours.

La plupart du temps, vous ne travaillez pas seul sur un projet. Nous voyons souvent du code laid avec des variables ayant des noms comme je, une, p, pro, et rqs. Et si cela devient vraiment mauvais, ce modèle est visible dans tout le projet. Si cela vous semble familier, je suis presque sûr que vous vous êtes posé la question "Comment cette personne peut-elle écrire du code comme celui-ci?" Bien sûr, cela vous rend d'autant plus reconnaissant lorsque vous rencontrez un code clair, lisible et même magnifique. Un code clair et propre peut être lu en quelques secondes et vous permet, ainsi qu'à vos collègues, de vous faire gagner beaucoup de temps. Cela devrait être votre motivation pour écrire un code de qualité.

1. Facile à comprendre

Nous sommes tous d'accord pour dire que le code doit être facile à comprendre. Droite? Le premier exemple porte sur l'espacement. Regardons deux exemples.

 retourne le genre == "1"? poids * (taille / 10): poids * (taille * 10);
 si (sexe == "1") poids de retour * (taille / 10);  else poids de retour * (hauteur * 10); 

Même si le résultat de ces exemples est identique, ils sont très différents. Pourquoi devriez-vous utiliser plus de lignes de code si vous pouvez écrire moins? Explorons deux autres exemples, je parie que vous voyez souvent.

 for (nœud * nœud = liste-> tête; nœud! = NULL; nœud = nœud-> suivant) print (nœud-> données);
 Nœud * nœud = liste-> tête; if (node ​​== NULL) return; while (node-> next! = NULL) Imprimer (node-> data); noeud = noeud-> suivant;  if (node! = NULL) Imprimer (node-> data);

Encore une fois, le résultat de ces exemples est identique. Lequel est le meilleur? Et pourquoi? Moins de lignes de code signifie-t-il un meilleur code? Nous reviendrons sur cette question plus tard dans ce tutoriel..

2. Est-ce toujours plus petit?

En informatique, vous entendez souvent l'expression "moins, c'est plus". En règle générale, mieux vaut résoudre un problème en moins de lignes de code. Il vous faudra probablement moins de temps pour comprendre une classe de 200 lignes qu’une classe de 500 lignes. Cependant, est-ce toujours vrai? Regardez les exemples suivants.

 réservation ((! room = FindRoom (room_id))) || ! room-> isOupupied ());
 room = FindRoom (room_id); if (room! = NULL) réservation (! room-> isOccupied ());

Ne croyez-vous pas que le deuxième exemple est plus facile à lire et à comprendre? Vous devez être capable d'optimiser la lisibilité. Bien sûr, vous pouvez ajouter quelques commentaires au premier exemple pour faciliter la compréhension, mais ne vaut-il pas mieux omettre les commentaires et écrire un code plus facile à lire et à comprendre?

 // Détermine où le monstre doit apparaître le long de l'axe des ordonnées. CGSize winSize = [CCDirector sharedDirector] .winSize; int minY = monster.contentSize.width / 2; int maxY = winSize.width - monster.contentSize.width / 2; int gammeY = maxY - minY; int actualY = (arc4random ()% rangeY) + minY;

3. Nommer

Choisir des noms descriptifs pour des éléments tels que les variables et les fonctions est un aspect clé de l'écriture de code lisible. Cela aide vos collègues et vous-même à comprendre rapidement le code. Nommer une variable tmp ne vous dit rien d'autre que le fait que la variable est temporaire pour une raison quelconque, qui n'est rien de plus qu'une supposition éclairée. Il ne dit pas si la variable stocke un nom, une date, etc..

Un autre bon exemple est de nommer une méthode Arrêtez. Ce n'est pas une mauvaise réputation en soi, mais cela dépend vraiment de la mise en œuvre de la méthode. S'il effectue une opération dangereuse qui ne peut pas être annulée, vous voudrez peut-être le renommer en tuer ou pause si l'opération peut être reprise. Avez-vous eu l'idée?

Si vous utilisez une variable pour le poids des pommes de terre, pourquoi la nommeriez-vous? tmp? Lorsque vous revisitez ce code quelques jours plus tard, vous ne vous souviendrez pas de ce que tmp est utilisé pour.

Nous ne disons pas que tmp est un mauvais nom pour une variable, car il y a des moments où tmp est parfaitement raisonnable comme nom de variable. Regardez l'exemple suivant dans lequel tmp n'est pas un mauvais choix du tout.

 tmp = first_potato; first_potato = second_potato; second_potato = tmp;

Dans l'exemple ci-dessus, tmp décrit ce qu’il fait, il stocke temporairement une valeur. Il n'est pas transmis à une fonction ou à une méthode, et il n'est pas incrémenté ou modifié. Sa durée de vie est bien définie et aucun développeur expérimenté ne sera rebuté par le nom de la variable. Parfois, cependant, c'est simplement de la paresse. Jetez un coup d'œil au prochain exemple.

 NSString * tmp = user.name; tmp + = "" + user.phone_number; tmp + = "" + user.email;… [template setObject: tmp forKey: @ "user_info"];

Si tmp stocke les informations de l'utilisateur, pourquoi n'est-il pas nommé informations utilisateur? Nommer correctement les variables, fonctions, méthodes, classes, etc. est important lors de l’écriture de code lisible. Non seulement cela rend votre code plus lisible, mais vous gagnerez du temps dans le futur.

Objective-C est assez bavard, mais très facile à lire. Apple utilise une convention de dénomination bien définie que vous pouvez adopter dans la plupart des langages de programmation. Vous pouvez en savoir plus sur cette convention d'appellation dans Programmation avec Objective-C.

4. Ajouter une signification aux noms

Comme nous l'avons vu dans le précédent conseil, il est important de choisir les noms judicieusement. Cependant, il est également important d'ajouter du sens aux noms que vous utilisez pour les variables, les fonctions, les méthodes, etc. Cela permet non seulement d'éviter les confusions, mais facilite également la compréhension du code que vous écrivez. Choisir un nom qui a du sens revient à ajouter des métadonnées à une variable ou à une méthode. Choisissez des noms descriptifs et évitez les noms génériques. Le mot ajouter, par exemple, n'est pas toujours idéal comme vous pouvez le voir dans l'exemple suivant.

 bool addUser (Utilisateur u) …

On ne sait pas quoi addUser est censé faire. Est-ce que cela ajoute un utilisateur à une liste d'utilisateurs, à une base de données ou à une liste de personnes invitées à une soirée? Comparez ceci à enregistrerUtilisateur ou signupUser. Cela fait plus de sens. Droite? Regardez la liste suivante pour avoir une meilleure idée de ce que nous conduisons.

Mot Synonymes
faire faire, exécuter, exécuter, composer, ajouter début lancer, créer, commencer, ouvrir exploser détoner, exploser, partir, éclater

5. Taille du nom

Beaucoup de programmeurs n'aiment pas les noms longs, car ils sont difficiles à retenir et difficiles à taper. Bien sûr, un nom ne devrait pas être ridiculement long comme newClassForNavigationControllerNamedFirstViewController. Ce est difficile à retenir et rend simplement votre code laid et illisible.

Comme nous l'avons vu précédemment, l'inverse, les noms courts, ne sont pas bons non plus. Quelle est la bonne taille pour un nom de variable ou de méthode? Comment décidez-vous entre nommer une variable len, longueur, ou nom_utilisateur_longueur? La réponse dépend du contexte et de l'entité à laquelle le nom est lié..

Les noms longs ne sont plus un problème lorsqu’on utilise un environnement de développement intégré (IDE) moderne. La complétion du code vous aide à éviter les fautes de frappe et à faire des suggestions pour que la mémorisation des noms soit moins pénible.

Vous pouvez utiliser des noms courts si la variable est locale. De plus, il est recommandé d'utiliser des noms plus courts pour les variables locales afin que votre code reste lisible. Regardez l'exemple suivant.

 NSString * link = [[NSString alloc] initWithFormat: @ "http: // localhost: 8080 / WrittingGoodCode / resources / GoodCode / getGoodCode /% @", idCode]; NSURL * infoCode = [NSURL URLWithString: link];

6. Nommer des booléens

Les noms booléens peuvent être difficiles à nommer, car ils peuvent avoir une signification différente selon la façon dont vous lisez ou interprétez le nom. Dans le prochain extrait de code, read_password peut signifier que le mot de passe a été lu par le programme, mais cela signifie également que le programme doit lire le mot de passe.

 BOOL readPassword = YES;

Pour éviter ce problème, vous pouvez renommer le booléen ci-dessus en didReadPassword pour indiquer que le mot de passe a été lu ou shouldReadPassword pour montrer que le programme doit lire le mot de passe. C’est quelque chose que vous voyez souvent dans Objective-C, par exemple.

7. Commenter ou ne pas commenter

L'ajout de commentaires au code est important, mais il est également important de les utiliser avec parcimonie. Ils devraient être utilisés pour aider quelqu'un à comprendre votre code. Lire des commentaires, cependant, prend aussi du temps et si un commentaire n'ajoute pas beaucoup de valeur, ce temps est perdu. L'extrait de code suivant montre comment ne pas utiliser les commentaires.

 // Cela se produit lorsque l'avertissement de mémoire est reçu - (void) didReceiveMemoryWarning [super didReceiveMemoryWarning]; // Élimine toutes les ressources pouvant être recréées.  // Ceci valide les champs - (BOOL) validateFields 

Ces extraits de code vous sont-ils utiles? La réponse est probablement "non" Les commentaires dans les exemples ci-dessus n'apportent aucune information supplémentaire, d'autant plus que les noms de méthodes sont déjà très descriptifs, ce qui est courant dans Objective-C. N'ajoutez pas de commentaires qui expliquent l'évidence. Jetez un oeil à l'exemple suivant. N'est-ce pas une bien meilleure utilisation des commentaires?

 // Détermine la vitesse du monstre int minDuration = 2.0; int maxDuration = 8,0; int rangeDurée = maxDuration - minDuration; int actualDuration = (arc4random ()% rangeDuration) + minDuration;

De tels commentaires facilitent la navigation rapide et efficace dans une base de code. Cela vous évite d'avoir à lire le code et vous aide à comprendre la logique ou l'algorithme.

8. Style et cohérence

Chaque langue ou plate-forme a un (ou plusieurs) guide de style et même la plupart des entreprises en ont un. Placez-vous les accolades d’une méthode Objective-C sur une ligne distincte ou non??

 - (void) CalculateOffset 
 - (void) CalculateOffset 

La réponse est que cela n'a pas d'importance. Il n'y a pas de bonne réponse. Bien sûr, il existe des guides de style que vous pouvez adopter. L'important est que votre code soit cohérent en termes de style. Même si cela n’affectera pas la qualité de votre code, cela affectera certainement la lisibilité et risque fort d’ennuyer vos collègues ou ceux qui liront votre code. Pour la plupart des développeurs, le code laid est le pire type de code.

9. Méthodes et fonctions ciblées

Une erreur courante parmi les développeurs est d’intégrer autant de fonctionnalités dans des fonctions et des méthodes. Cela fonctionne, mais c'est inélégant et rend le débogage une douleur dans le cou. Votre vie et celle de vos collègues deviendront beaucoup plus faciles si vous divisez de gros problèmes en petits problèmes et que vous les abordez dans des fonctions ou des méthodes distinctes. Jetez un coup d'œil au prochain exemple dans lequel nous écrivons une image sur un disque. Cela semble être une tâche triviale, mais il y a beaucoup plus à faire si vous voulez le faire correctement.

 - (BOOL) saveToImage: (UIImage *) image withNomFichier: (NSString *) nomFichier BOOL result = NO; NSString * documents = nil; NSArray * path = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); if (path.count) documents = [path objectAtIndex: 0]; NSString * basePath = [documents stringByAppendingPathComponent: @ "Archive"]; if (! [[NSFileManager defaultManager] fileExistsAtPath: basePath]) NSError * error = nil; [[NSFileManager defaultManager] createDirectoryAtPath: basePath avecIntermediateDirectories: YES attributs: aucune erreur: & erreur]; if (! erreur) NSString * filePath = [basePath stringByAppendingPathComponent: nomFichier]; resultat = [UIImageJPEGRepresentation (image, 8.0) writeToFile: filePath atomically: YES];  else NSLog (@ "Impossible de créer le répertoire en raison de l'erreur% @ avec les informations utilisateur% @.", erreur, error.userInfo);  return result; 

Si une unité de code essaie de faire trop, vous vous retrouvez souvent avec des instructions conditionnelles profondément imbriquées, de nombreuses vérifications d'erreurs et des instructions conditionnelles trop complexes. Cette méthode permet d'effectuer trois opérations: rechercher le chemin du répertoire de documents de l'application, récupérer et créer le chemin du répertoire d'archives, puis écrire l'image sur le disque. Chaque tâche peut être associée à sa propre méthode, comme indiqué ci-dessous..

 - (BOOL) saveToImage: (UIImage *) image withFileName: (NSString *) nom_fichier NSString * archivesDirectory = [auto applicationArchivesDirectory]; if (! archivesDirectory) renvoie NO; // Créer un chemin NSString * filePath = [archivesDirectory stringByAppendingPathComponent: fileName]; // Write Image to Disk return [UIImageJPEGRepresentation (image, 8.0) writeToFile: filePath atomically: YES]; 
 - (NSString *) applicationDocumentsDirectory NSArray * path = NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES); chemins de retour.count? [chemins objectAtIndex: 0]: nil; 
 - (NSString *) applicationArchivesDirectory NSString * documentsDirectory = [auto applicationDocumentsDirectory]; NSString * archivesDirectory = [documentsDirectory stringByAppendingPathComponent: @ "Archives"]; NSFileManager * fm = [NSFileManager defaultManager]; if (! [fm fileExistsAtPath: archivesDirectory]) NSError * error = nil; [fm createDirectoryAtPath: archivesDirectory avecIntermediateDirectories: YES attributs: aucune erreur: & erreur]; if (error) NSLog (@ "Impossible de créer le répertoire en raison de l'erreur% @ avec les informations utilisateur% @.", error, error.userInfo); retourne zéro;  return archivesDirectory; 

C'est beaucoup plus facile à déboguer et à maintenir. Vous pouvez même réutiliser le applicationDocumentsDirectory méthode utilisée à d’autres endroits du projet, ce qui constitue un autre avantage de la résolution des problèmes plus importants en éléments gérables. Tester le code devient aussi beaucoup plus facile.

Conclusion

Dans cet article, nous nous sommes penchés sur l'écriture de code lisible en choisissant judicieusement les noms des variables, des fonctions et des méthodes, en étant cohérents lors de l'écriture de code et en décomposant des problèmes complexes en blocs gérables. Si vous avez des questions ou des commentaires, n'hésitez pas à laisser un commentaire ci-dessous.