JavaRush /Blog Java /Random-FR /Pause café #64. Comment écrire du code propre. Pourquoi J...

Pause café #64. Comment écrire du code propre. Pourquoi Java est meilleur que C++ pour les systèmes à faible latence

Publié dans le groupe Random-FR

Comment écrire du code propre

Source : Dev.to Écrire du code propre, c'est comme écrire de la poésie. C'est une poésie qui doit être concise, compréhensible et accessible au changement. Un code propre implique une organisation évolutive. Cela signifie qu’apporter des changements ne provoque pas le chaos. La capacité à écrire un tel code est l’une des qualités clés d’un développeur expérimenté. Après que plusieurs personnes m'ont recommandé de lire le livre Clean Code, j'ai finalement eu le courage de le lire. Il s’est avéré que c’est l’un de ces livres dont la couverture est à la hauteur du battage médiatique qui l’entoure. Les recommandations du livre sont claires, précises, pratiques et même présentées avec humour. Aujourd'hui, je souhaite partager avec vous les principaux points à retenir de ce livre.Pause café #64.  Comment écrire du code propre.  Pourquoi Java est meilleur que C++ pour les systèmes à faible latence - 1

1. Le code doit non seulement fonctionner, mais aussi être lisible

La majeure partie du coût des logiciels est liée au support à long terme. Par conséquent, le code que vous écrivez doit exprimer clairement vos intentions. Il doit être tel que les nouveaux développeurs rejoignant l'équipe puissent facilement comprendre ce qui se passe exactement dans le code et pourquoi. Plus le code écrit par l'auteur est compréhensible, moins il faudra de temps aux autres développeurs pour le comprendre. Cela réduit les défauts et les coûts de maintenance. Comment y parvenir ? Bon nommage + classes et fonctions à responsabilité unique + tests d'écriture.

2. Plus tard signifie jamais

Soyons honnêtes : on se promet tous parfois de revenir nettoyer le code plus tard, mais on finit par l'oublier. Ne laissez pas de morceaux de code inutiles qui ne sont plus nécessaires. Ils confondent les autres développeurs et n'ont aucune valeur. Par conséquent, lorsque vous apportez des modifications aux fonctionnalités, supprimez toujours l’ancien code. Si quelque chose se brise quelque part, les tests le montreront quand même immédiatement. Comment y parvenir ? Supprimer du code peut être effrayant, surtout dans les grandes architectures. Les tests sont donc essentiels ici. Ils vous permettent de supprimer du code en toute confiance.

3. Les fonctionnalités doivent être petites

La première règle d'écriture des fonctions est qu'elles doivent être petites, jusqu'à environ 20 lignes . Plus la fonction est petite et plus elle est concentrée sur une tâche, plus il est facile de lui trouver un bon nom. Quant aux arguments des fonctions, leur nombre idéal est 0. Viennent ensuite 1, 2, mais vous devriez essayer de ne pas avoir plus de 3 arguments . Les fonctions doivent être écrites conformément aux principes de responsabilité unique et ouvertes/fermées.

4. La duplication de code est mauvaise

La duplication est l’ennemi d’un système bien organisé. C'est un travail supplémentaire, un risque supplémentaire et une complexité supplémentaire inutile. Que faire à ce sujet ? Assurez-vous que votre code est écrit selon le principe DRY, isolé et modulaire.

5. Le seul bon commentaire est celui que vous avez trouvé un moyen de ne pas écrire.

« Il n’y a rien de plus utile qu’un bon commentaire au bon endroit. Mais les commentaires, même dans le meilleur des cas, sont un mal nécessaire.» Les commentaires sont destinés à compenser notre incapacité à exprimer nos pensées sous forme de code. Autrement dit, il s’agit d’abord d’un aveu de défaite. Oui, nous devons les utiliser car nous ne pouvons pas toujours exprimer clairement nos intentions avec du code, mais ce n'est pas une raison de se réjouir. Le fait est que les commentaires mentent souvent. Pas toujours et pas volontairement, mais trop souvent. Plus le commentaire est ancien et plus il est éloigné du code qu’il décrit, plus il est probable qu’il soit incorrect. La raison en est simple : les programmeurs ne peuvent pas très bien gérer à la fois le code et tous les commentaires. Par conséquent, très souvent, les commentaires sont séparés du code auquel ils font référence et deviennent des annotations orphelines avec une précision minimale. Que faire à ce sujet ? Des méthodes de dénomination descriptives doivent être utilisées. Lorsque vous lisez le nom d’une variable, vous devez immédiatement comprendre de quoi il s’agit. Des tests sont également nécessaires pour que les autres développeurs comprennent quelle fonctionnalité est la plus importante.

6. L'objet révèle un comportement, mais pas des données.

Un module ne doit pas connaître les composants internes des objets qu'il manipule. Les objets cachent leurs données et révèlent leurs opérations. Cela signifie qu'un objet ne doit pas exposer sa structure interne via des méthodes d'accès. Il n'est pas nécessaire que tout le monde vous voie nu. Que faire à ce sujet ? La portée des variables doit être aussi locale que possible afin de ne pas en exposer plus que nécessaire.

7. Tests

Le code de test est tout aussi important que ce qui entre en production. Il doit donc évoluer et grandir au fur et à mesure que le projet se développe. Les tests maintiennent votre code flexible, maintenable et réutilisable. Sans eux, tout changement peut entraîner des bugs. Les tests vous permettent de nettoyer votre code sans craindre que quelque chose ne se casse. Par conséquent, le maintien de la pureté des tests est d’une grande importance. La propreté des tests garantit leur lisibilité. Les tests sont l'occasion d'expliquer aux autres développeurs dans un langage simple les intentions de l'auteur du code. Par conséquent, nous testons un seul concept dans chaque fonction de test. Cela rend le test descriptif, plus facile à lire et, s’il échoue, il est plus facile d’en retrouver la raison. Comment y parvenir ? Il faut suivre les principes des PREMIERS tests propres . Les tests doivent être :
  • Rapide. Les tests doivent être exécutés rapidement. Si vous devez attendre trop longtemps pour qu'un test soit exécuté, vous aurez moins de chances de l'exécuter plus souvent.
  • Indépendant/isolé (Indépendant). Les tests doivent être aussi isolés et indépendants les uns des autres que possible.
  • Répétable. Les tests doivent être reproductibles dans n’importe quel environnement : développement, préparation et production.
  • Auto-validation. Le résultat du test doit être une valeur booléenne. Le test doit réussir ou échouer.
  • Complet. Nous devons nous efforcer de couvrir tous les cas extrêmes, tous les problèmes de sécurité, chaque cas d'utilisation (cas d'utilisation) et le chemin heureux (le scénario le plus favorable pour le code) avec des tests.

8. Gestion des erreurs et des exceptions

Chaque exception que vous lancez doit fournir suffisamment de contexte pour déterminer la source et l'emplacement de l'erreur. En règle générale, vous disposez d'une trace de pile de toute exception, mais une trace de pile ne vous indiquera pas le but de l'opération qui a échoué. Si possible, évitez de passer null dans votre code. Si vous êtes tenté de renvoyer null à partir d’une méthode, envisagez plutôt de lever une exception. Faites de la gestion des erreurs une tâche distincte qui peut être visualisée indépendamment de la logique principale. Comment y parvenir ? Créez des messages d'erreur informatifs et transmettez-les avec vos exceptions. Spécifiez l'opération qui a échoué et le type d'erreur.

9. Cours

Les classes devraient être petites. Mais ce ne sont pas les lignes de code qu’il faut compter, mais la responsabilité. Les noms de classe sont essentiels pour décrire de quoi ils sont responsables. Nos systèmes devraient être constitués de nombreuses petites classes, et non de quelques grandes classes. Chacune de ces petites classes doit encapsuler une seule responsabilité. Il ne doit y avoir qu'une seule raison spécifique pour que chaque classe existe, et chaque classe doit « coopérer » avec plusieurs autres classes pour obtenir le comportement souhaité du système. Il y a rarement une bonne raison de créer une variable publique. L’affaiblissement de l’encapsulation est toujours un dernier recours. De plus, il devrait y avoir peu de variables d'instance. Une bonne conception logicielle permet d’apporter des modifications sans investissements ni retouches importants. Réduire la gamme de variables rend cette tâche plus facile. Comment y parvenir ? La séparation des préoccupations est l’une des techniques de conception les plus anciennes et les plus importantes. Les classes doivent être ouvertes à l’extension, mais fermées à la modification. Dans un système idéal, nous activons de nouvelles fonctionnalités en étendant le système plutôt qu'en apportant des modifications au code existant.

10. Formatage

Chaque ligne vide est un repère visuel permettant d'identifier qu'un nouveau concept distinct a commencé. Les variables locales doivent apparaître en haut de la fonction. Les variables d'instance doivent être déclarées en haut de la classe. Les lignes courtes valent mieux que les longues. Habituellement, la limite est de 100 à 120 caractères ; vous ne devriez pas l’allonger. Comment y parvenir ? La plupart des paramètres peuvent être transmis à un linter dans votre CI ou votre éditeur de texte. Utilisez ces outils pour rendre votre code aussi propre que possible.

Principes de développement de programmes

Utilisez les techniques suivantes et votre code sera toujours propre : Nommer les variables. Choisir des noms appropriés (une bonne dénomination) est essentiel pour rendre le code lisible et donc maintenable. "Vous devez choisir un nom pour une variable de manière aussi responsable que vous le feriez pour votre premier-né." Choisir de bons noms est souvent un défi pour les développeurs. Cela nécessite de bonnes compétences descriptives et un bagage culturel partagé. Un code propre est un code lu et amélioré par des développeurs complètement différents. Le nom d'une variable, d'une fonction ou d'une classe doit répondre à toutes les questions fondamentales : pourquoi cette entité existe, à quoi et comment elle est utilisée. Si un nom nécessite un commentaire, c’est qu’il ne révèle pas suffisamment l’essence de ce qu’il décrit. Les noms plus longs sont plus importants que les noms plus courts, et tout nom consultable vaut mieux qu'une constante. Les noms à une seule lettre ne peuvent être utilisés que comme variables locales dans des méthodes courtes : la longueur du nom doit correspondre à la portée. Les noms de méthodes doivent être des verbes ou des phrases verbales ; le nom de la classe ne doit pas être un verbe. Les dépendances doivent être réduites au minimum. Il vaut mieux compter sur ce que l’on contrôle que sur ce que l’on ne peut pas contrôler. Sinon, ces choses vous contrôleront. Précision. Chaque morceau de code doit se trouver à un endroit où le lecteur s'attend à le trouver. La navigation dans la base de code doit être intuitive et les intentions du développeur doivent être claires. Nettoyage. Ne laissez pas de code inutile dans la base de code (ancien et qui n'est plus utilisé ou créé "juste au cas où"). Réduisez la duplication et créez des abstractions simples dès le début. Standardisation. Lors de l'écriture du code, vous devez suivre le style et les pratiques établis pour le référentiel. Autodiscipline. À mesure que les technologies utilisées se développent et que de nouvelles apparaissent, les développeurs souhaitent souvent modifier et améliorer quelque chose dans le code existant. Ne cédez pas trop vite au battage médiatique : étudiez les nouveaux stacks en profondeur et uniquement dans un but précis. Garder votre base de code propre ne se limite pas à être poli envers vos collègues actuels et futurs. C’est essentiel pour la survie à long terme du programme. Plus votre code est propre, plus les développeurs sont satisfaits, meilleur est le produit et plus il durera longtemps.

Pourquoi Java est meilleur que C++ pour les systèmes à faible latence

Source : StackOverflow En tant que développeurs, nous savons tous qu'il existe deux manières de faire les choses : manuellement, lentement et de manière ennuyeuse, ou automatiquement, difficilement et rapidement. Je pourrais utiliser l’intelligence artificielle pour écrire cet article à ma place. Cela pourrait me faire gagner beaucoup de temps - l'IA peut générer des milliers d'articles par seconde, mais mon éditeur ne serait probablement pas content d'apprendre qu'il faudrait deux ans pour générer le premier article. Pause café #64.  Comment écrire du code propre.  Pourquoi Java est meilleur que C++ pour les systèmes à faible latence - 2Une situation similaire se produit lors du développement de systèmes logiciels à faible latence. L’idée reçue est qu’il serait fou d’utiliser autre chose que C++ car tout le reste a trop de latence. Mais je suis ici pour vous convaincre de la notion opposée, contre-intuitive, presque hérétique : lorsqu'il s'agit d'obtenir une faible latence dans les systèmes logiciels, Java est meilleur. Dans cet article, je souhaite prendre un exemple précis de logiciel qui valorise une faible latence : les systèmes de trading. Cependant, les arguments présentés ici peuvent être appliqués à presque toutes les circonstances dans lesquelles une faible latence est requise ou souhaitée. C'est juste plus facile de discuter par rapport au domaine de développement dans lequel j'ai de l'expérience. Et la vérité est que la latence est difficile à mesurer. Tout dépend de ce que vous entendez par faible latence. Voyons cela maintenant.

Sagesse acquise

Le C++ étant beaucoup plus proche du matériel, la plupart des développeurs vous diront que le codage dans ce langage offre un avantage en termes de rapidité. Dans les situations de faible latence, telles que les échanges à grande vitesse, où quelques millisecondes peuvent faire la différence entre un logiciel viable et un gaspillage d'espace disque, le C++ est considéré comme la référence. Du moins, c'était comme ça avant. Mais la réalité est que de nombreuses grandes banques et courtiers utilisent désormais des systèmes écrits en Java. Et je veux dire écrit nativement en Java, non écrit en Java puis interprété en C++ pour réduire la latence. Ces systèmes deviennent la norme même pour les banques d’investissement de premier rang, malgré le fait qu’ils soient (supposément) plus lents. Alors que se passe-t-il? Oui, le C++ peut avoir une « faible latence » lorsqu'il s'agit d'exécuter du code, mais ce n'est certainement pas une faible latence lorsqu'il s'agit de déployer de nouvelles fonctionnalités ou même de trouver des développeurs capables de l'écrire.

(Réelles) différences entre Java et C++

Le problème du temps de développement n’est qu’un début lorsqu’il s’agit des différences entre Java et C++ dans les systèmes du monde réel. Pour comprendre la vraie valeur de chaque langue dans ce contexte, approfondissons un peu. Tout d’abord, il est important de se rappeler la véritable raison pour laquelle C++ est plus rapide que Java dans la plupart des situations : un pointeur C++ est l’adresse d’une variable en mémoire. Cela signifie que le logiciel peut accéder directement aux variables individuelles et n'a pas besoin d'explorer des tableaux gourmands en calcul pour les rechercher. Ou du moins, cela peut être résolu en spécifiant où ils se trouvent, car avec C++, vous devez souvent gérer explicitement la durée de vie et la propriété des objets. Par conséquent, à moins que vous ne soyez vraiment doué pour écrire du code (une compétence qui peut prendre des décennies à maîtriser), le C++ nécessitera des heures (ou des semaines) de débogage. Et comme vous le dira tous ceux qui ont essayé de déboguer un moteur Monte Carlo ou un outil de test PDE, essayer de déboguer l’accès à la mémoire à un niveau fondamental peut prendre beaucoup de temps. Un seul pointeur défectueux peut facilement faire tomber un système entier, donc publier une nouvelle version écrite en C++ peut être vraiment terrifiant. Bien sûr, ce n'est pas tout. Les personnes qui aiment programmer en C++ souligneront que le garbage collector de Java souffre de pics de latence non linéaires. Cela est particulièrement vrai lorsque vous travaillez avec des systèmes existants, donc l'envoi de mises à jour du code Java sans interrompre les systèmes clients peut les rendre si lents qu'ils deviennent inutilisables. En réponse, je tiens à souligner que beaucoup de travail a été réalisé au cours de la dernière décennie pour réduire la latence créée par le GC Java. Perturbateur LMAX, par exemple, est une plateforme de trading à faible latence écrite en Java, également conçue comme un framework qui a une « interaction mécanique » avec le matériel sur lequel elle s'exécute et ne nécessite pas de verrouillage. Les problèmes peuvent être encore atténués si vous créez un système qui utilise un processus d'intégration et de livraison continues (CI/CD), car CI/CD permet le déploiement automatisé des modifications de code testées. En effet, CI/CD fournit une approche itérative pour réduire la latence du garbage collection, dans laquelle Java peut s'améliorer et s'adapter progressivement à des environnements matériels spécifiques sans le processus gourmand en ressources consistant à préparer le code pour différentes spécifications matérielles avant de l'expédier. Étant donné que la prise en charge Java de l'EDI est beaucoup plus large que C++, la plupart des frameworks (Eclipse, IntelliJ IDEA) vous permettent de refactoriser Java. Cela signifie que les IDE peuvent optimiser le code pour des performances de faible latence, bien que cette capacité soit encore limitée lorsque l'on travaille avec C++. Même si le code Java n'atteint pas tout à fait la vitesse du C++, la plupart des développeurs trouvent toujours plus facile d'atteindre des performances acceptables en Java qu'en C++.

Qu'entend-on par « plus rapide » ?

En fait, il y a de bonnes raisons de douter que C++ soit vraiment « plus rapide » ou même ait « une latence plus faible » que Java. Je me rends compte que je m'engage dans des eaux assez troubles et que de nombreux développeurs vont commencer à remettre en question ma santé mentale. Mais écoutez-moi. Imaginons cette situation : vous avez deux développeurs : l'un écrit en C++ et l'autre en Java, et vous leur demandez d'écrire une plateforme de trading à haut débit à partir de zéro. En conséquence, un système écrit en Java mettra plus de temps à effectuer des transactions commerciales qu'un système écrit en C++. Cependant, Java a beaucoup moins d'instances de comportement non défini que C++. Pour ne prendre qu'un exemple, l'indexation en dehors d'un tableau est un bug à la fois en Java et en C++. Si vous faites cela accidentellement en C++, vous risquez d'obtenir une erreur de segmentation ou (plus souvent) vous vous retrouverez simplement avec un nombre aléatoire. En Java, sortir des limites génère toujours une erreur ArrayIndexOutOfBoundsException . Cela signifie que le débogage en Java est beaucoup plus facile car les erreurs sont généralement immédiatement identifiées et leur emplacement est plus facile à localiser. De plus, du moins d'après mon expérience, Java reconnaît mieux quels morceaux de code n'ont pas besoin d'être exécutés et lesquels sont essentiels au fonctionnement de votre logiciel. Vous pouvez, bien sûr, passer des jours à peaufiner votre code C++ afin qu'il ne contienne absolument aucun code superflu, mais dans le monde réel, chaque logiciel contient une certaine surcharge, et Java est meilleur pour le reconnaître automatiquement. Cela signifie que dans le monde réel, Java est souvent plus rapide que C++, même selon les mesures de latence standard. Et même lorsque ce n’est pas le cas, la différence de latence entre les langues est souvent dépassée par d’autres facteurs qui ne sont pas suffisamment importants pour avoir de l’importance même dans le trading à grande vitesse.

Avantages de Java pour les systèmes à faible latence

Tous ces facteurs, à mon avis, constituent un argument assez convaincant en faveur de l'utilisation de Java pour écrire des plateformes de trading à grande vitesse (et des systèmes à faible latence en général, nous y reviendrons dans un instant). Cependant, pour influencer un peu les passionnés de C++, examinons quelques raisons supplémentaires d'utiliser Java :
  • Premièrement, toute latence excessive introduite par Java dans votre logiciel sera probablement bien inférieure à d'autres facteurs qui affectent la latence, tels que les problèmes Internet. Cela signifie que tout code Java (bien écrit) peut facilement fonctionner aussi bien que C++ dans la plupart des situations commerciales.

  • Le temps de développement plus court de Java signifie également que, dans le monde réel, les logiciels écrits en Java peuvent s'adapter aux changements matériels (ou même aux nouvelles stratégies de trading) plus rapidement que le C++.

  • Si vous approfondissez cela, vous verrez que même l'optimisation d'un logiciel Java peut être plus rapide (si l'on considère l'ensemble du logiciel) qu'une tâche similaire en C++.

En d’autres termes, vous pouvez très bien écrire du code Java pour réduire la latence. Il vous suffit de l'écrire en C++, en gardant à l'esprit la gestion de la mémoire à chaque étape du développement. L’avantage de ne pas écrire en C++ est que le débogage, le développement agile et l’adaptation à plusieurs environnements sont plus faciles et plus rapides en Java.

conclusions

À moins que vous ne développiez des systèmes de trading à faible latence, vous vous demandez probablement si l'une des situations ci-dessus s'applique à vous. La réponse, à quelques rares exceptions près, est oui. Le débat sur la manière d’atteindre une faible latence n’est ni nouveau ni propre au monde de la finance. C’est pourquoi de précieux enseignements peuvent en être tirés pour d’autres situations. En particulier, l'argument ci-dessus selon lequel Java est « meilleur » parce qu'il est plus flexible, plus tolérant aux pannes et, en fin de compte, plus rapide à développer et à maintenir, peut être appliqué à de nombreux domaines du développement logiciel. Les raisons pour lesquelles je préfère (personnellement) écrire des systèmes à faible latence en Java sont les mêmes qui ont fait le succès du langage au cours des 25 dernières années. Java est facile à écrire, compiler, déboguer et apprendre. Cela signifie que vous pouvez passer moins de temps à écrire du code et plus de temps à l’optimiser. En pratique, cela conduit à des systèmes de trading plus fiables et plus rapides. Et c’est tout ce qui compte pour le trading à grande vitesse.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION