A la veille de Moscou Python Conf ++, nous avons discuté avec Nikita Sobolev, CTO de la société We Do Services, du problème global de la gestion de la complexité du code dans le cadre du développement des langages de programmation. Et aussi pourquoi ici, au fil du temps, la situation ne fait qu'empirer. De plus, ils ont demandé pourquoi il avait besoin de créer son propre linter.
- Parlez-nous de vous et de votre travail.Je suis le directeur technique de "We do services". En prononçant le nom de l'entreprise, je pose généralement la question: "Que pensez-vous, que faisons-nous?". En fait, nous sommes spécialisés dans le développement web: frontend et backend pour les entreprises. Et nous travaillons selon notre propre méthodologie, que nous améliorons parallèlement au développement de l'entreprise - Processus de développement logiciel répétable (RSDP).
- À Moscow Python Conf ++, vous parlerez, y compris de votre propre linter. Comment votre travail est-il lié à l'audit et à la gestion de la complexité du code?En général, nous avons deux domaines principaux: le développement lui-même et tout ce qui l'entoure: le conseil, l'élaboration des exigences et, en particulier, l'audit, au cours duquel je vois beaucoup de code d'autres personnes. Le code est complètement différent: celui qui est actuellement en développement et l'héritage, que personne ne réparera jamais; et le code que les spécialistes du client écrivent, et celui qu'ils ont commandé sur le côté. Et dans toutes les versions du code, il y a beaucoup de problèmes: identiques et différents.
- Vous parlerez aux développeurs spécifiquement en Python. Python possède-t-il des fonctionnalités en termes de gestion de la complexité du code?Bien sûr!
Premièrement, toutes les langues à typage dynamique souffrent dans une plus grande mesure d'une complexité injustifiée, du moins en raison du manque de contexte supplémentaire lors de la lecture du code. Et vous avez droit à plus de saleté.
Deuxièmement, Python se développe activement. Il a de nouveaux éléments de syntaxe, de nouveaux concepts et modules dans des bibliothèques standard qui cassent tout ce qui était auparavant.
- À quel point tout est mauvais en Python? Après tout, il existe d'autres langages en développement actif, par exemple JavaScript, qui est souvent critiqué pour cela. JavaScript est-il meilleur?Non. Je dirais même qu'en termes de complexité, Python est plutôt bon par rapport aux autres langages. JavaScript est vraiment mauvais pour une raison simple: dans le code du projet JS, plusieurs entités qui ne sont pas liées au langage lui-même sont mélangées à la fois - des plugins et des bibliothèques tiers qui sont utilisés pour construire le projet. Par exemple, si vous utilisez Webpack, vous pouvez écrire la fonction `import ()`, qui charge les modules de manière asynchrone. Il s'avère que le collecteur enfonce une partie de son intérieur dans votre langage de programmation, et à la fin, il est généralement difficile de savoir ce qui se passe.
La gestion de la complexité est difficile lorsque la langue change de l'installation de Babel ou de ses plugins. Et pour comprendre comment ils fonctionnent, vous devez suivre les normes linguistiques, la mise en œuvre spécifique, etc.
En Python, la situation est bien meilleure. Le langage se développe de manière assez systématique, et ce développement a des jalons compréhensibles. Dans ce document, vous ne pouvez pas changer radicalement la syntaxe avec deux lignes dans la configuration. Et c'est toujours un backend, auquel nous sommes habitués à faire des demandes plus élevées qu'au frontend. Cependant, à mon avis, en Python, il y a pas mal de nouveaux changements qui cassent ce qui était avant, apportant des avantages douteux.
- Autrement dit, avec le développement de la langue, tout devient pire?Si vous vous souvenez qu'AsyncIO est apparu - essentiellement une deuxième langue à l'intérieur de Python - bien sûr, la complexité a beaucoup augmenté. En fait, il existe maintenant deux langages de programmation complètement indépendants avec une syntaxe similaire: Python et Python + AsyncIO. C'est-à-dire que Python en tant qu'entité est devenu plus compliqué deux fois plus, car il a deux descendants distincts travaillant selon des règles différentes.
L'opinion qu'il s'agit de langages de programmation différents n'est pas populaire. Cependant, lorsque vous demandez à des opposants à cette opinion, par exemple, d'exécuter une fonction asynchrone à partir d'un code synchrone, ils échouent. Les bibliothèques sont également complètement différentes. Vous souhaitez utiliser une bibliothèque synchrone pour travailler avec la base de données - s'il vous plaît. Et vous voulez asynchrone - ce n'est pas le cas.
Mais en Python, qui a été écrit il y a cinq ans, rien n'a vraiment changé, et même vice versa, des outils sont apparus pour simplifier le code, par exemple, les annotations et la vérification de type.
- La gestion de la complexité affecte-t-elle le fait que dans la programmation il y a maintenant beaucoup de gens avec une base technique faible?Bien sûr. Pour ces personnes, ils ont même proposé un langage de programmation spécial. Ça s'appelle Go. Je ne plaisante pas. En effet, l'objectif de la création du langage Go était une tentative d'engager les étudiants et les stagiaires de Google qui ne peuvent pas apprendre le C ++ en écrivant du code. Python ne leur convenait pas en termes de performances, ils avaient besoin d'autre chose et Google a proposé Go. Il s'est avéré que beaucoup de gens sont prêts à écrire dessus, car c'est très simple. Mais à quel prix cette simplicité a-t-elle été atteinte? Ils ne nous donnent pas un langage de programmation normal, mais sa version très tronquée - il n'y a pratiquement pas de concepts compliqués par conception. Il n'y a pas de génériques, il n'y a pas d'exceptions, etc. Et il y a beaucoup de fans de cette approche.
Mais il y a d'autres développeurs, et pour eux, le problème est qu'il existe des langages dans lesquels il n'y a pas d'équilibre: vous pouvez faire des choses simples simplement, et vous ne pouvez pas du tout faire des choses complexes. Ou du moins par la douleur - vous devez vous battre avec un outil pour faire quelque chose. Voilà, me semble-t-il, le problème de la gestion de la complexité.
- Quels sont les problèmes typiques du code de quelqu'un d'autre?Ils sont généralement divisés en deux parties.
Le premier est les problèmes liés au fait que les gens ne peuvent s'entendre sur l'endroit où mettre les virgules conditionnelles. Vous lisez un code et voyez des virgules à un endroit, passez à un autre fichier - et voyez des virgules à un autre endroit. Cela complique la perception, comme si vous lisiez un livre imprimé à un endroit en gras et à un autre en italique. Cela détourne l'attention du contenu, car le cerveau doit reconnaître qu'il s'agit d'une manière différente d'écrire la même chose.
Lorsque vous corrigez la syntaxe, vous commencez à prêter attention à la sémantique, car les gens écrivent différemment sur le plan conceptuel. Malheureusement, il n'y a aucun moyen de s'entendre sur ce niveau - il est impossible de parvenir à un accord pour résoudre de tels problèmes de cette manière, mais ceux-ci sont tels. Il n'est pas possible de couvrir tous les cas initialement. Ce processus se produit lors de la révision du code d'une tâche immédiate: lorsque le développeur est expliqué pourquoi sa décision ne peut pas être prise. Si la pratique de la révision du code est appliquée et que les réviseurs sont bons, ils coupent les courbes de solution et il n'y a aucun problème dans le code. Mais généralement, nous arrivons à l'audit où un tel processus n'est pas établi. Et les problèmes de sémantique et d'architecture sont beaucoup plus difficiles à résoudre, car ils sont parfois difficiles à formuler et à définir par eux-mêmes.
- Et à quoi ça ressemble en pratique?Par exemple, les utilisateurs peuvent résoudre le même problème dans des modèles, des vues ou des modèles. Et il n'y a pas de compréhension généralement acceptée où exactement cette tâche devrait être résolue: pas de documentation ou de modèles applicables spécifiquement à ce projet (par exemple, ici nous utilisons des modèles épais et y mettons toute la logique, mais ici nous utilisons des modèles minces; bons ou mauvais, maintenant cela n'a pas d'importance, mais nous en avons convenu).
«Selon vous, quelle est la principale raison pour laquelle ces problèmes existent même?»Tout le monde ne sait pas écrire du code.
Cette thèse est décryptée comme suit: le problème est que nous sommes des personnes. Et en général, il nous est très difficile d'écrire quelque chose de structuré et de logique. Et ici, nous avons également deux types de destinataires différents. Premièrement, c'est la personne qui va lire ce code, et deuxièmement, c'est la machine qui doit l'exécuter. Le code de la machine doit être créé conformément aux critères de performance, de consommation de mémoire et de temps CPU, et le code de la personne doit être basé sur les principes de lisibilité, d'intelligibilité, etc. Ce sont deux tâches opposées. Et une personne qui, en fait, ne peut pas résoudre complètement même l'un d'entre eux, est obligée de résoudre les deux tâches contradictoires en même temps.
"Mais l'utilisation de différents modèles de programmation est essentiellement une recherche d'ingénierie?" C'est vraiment mauvais?Bien sûr, la recherche en ingénierie est importante et nécessaire. Mais il doit également être gérable. Avant chacune de ces tâches, il est nécessaire de fixer des critères et des limites clairs: en fonction du temps passé, des exigences métiers, des pratiques et outils d'ingénierie.
Je suis beaucoup plus susceptible d'observer des recherches créatives. Il n'y a pas de telles restrictions, la validation des résultats obtenus non plus. La qualité - comme dans l'art contemporain - ne peut pas être mesurée.
Presque tous les clients qui se tournent vers nous pour un audit souffrent d'une situation typique: quelqu'un leur a fait quelque chose, ils ont engagé un développeur pour développer une solution, mais il est venu et a écarté les mains: «Je ne sais pas du tout ici pour le faire, réécrivons tout. " Serait-il agréable de réécrire? Ne le sera pas. Lorsque vous décidez de réécrire, vous marchez exactement sur le même rake: vous confiez la tâche à un autre développeur qui fait d'autres erreurs, mais finalement tout se passe exactement de la même manière.
- Besoin d'une autre approche?Oui Au cours de l'audit, nous essayons de trouver la cause des problèmes avec le code: pourquoi personne n'a-t-il pris et gonflé le module au point qu'il serait difficile de le faire défiler, et pourquoi la mauvaise décision a été prise au départ. Et nous essayons d'automatiser ou de simplifier autant que possible les bonnes décisions dans les limites données.
Je vais donner un petit intérieur au rapport. Tout le monde comprend que le code est composé de lignes - c'est l'entité la plus simple qu'il puisse comprendre. Chaque ligne peut s'écrire
x = 1
ou peut-être comme
x = Math.median(forecast_data) if forecast_data else compute_probability(default_model)
.
Il y a une très grande différence entre ces deux lignes, car vous comprenez facilement la première, et beaucoup de logique est concentrée dans la seconde. Il faut l'exécuter dans la tête en parallèle avec l'interprète. Par conséquent, vous devez commencer à contrôler la façon dont vous écrivez le code, avec le contrôle d'une seule ligne de code. De plus, la ligne se transforme en concepts plus complexes - fonctions, classes, modules, etc. Mais les règles que vous acceptez doivent en être une.
Par conséquent, nous n'interdisons pas beaucoup de choses. Parce que la gestion concerne les interdictions imposées.
- Avez-vous rencontré des choses amusantes dans le code de quelqu'un d'autre?Bien sûr. J'ai même un
référentiel où je collecte de tels exemples de code.
L'exemple le plus effrayant que j'ai vu m'a montré qu'à l'intérieur d'une boucle d'une centaine d'itérations, vous pouvez définir une fonction. Pour être honnête, quand je l'ai regardé, mon interprète s'est cassé. J'ai deviné, mais je ne savais pas que c'était possible.
Il y a eu un cas où nous avons vu beaucoup de commentaires drôles dans le code. Quelqu'un s'est plaint de la vie, du travail, il y avait ceux qui ont écrit: "Je comprends que j'écris des bêtises, mais le client m'y oblige." Cependant, les clients ne vous obligent généralement pas à écrire un mauvais code. Ils demandent à résoudre leur problème, et quel code vous y écrivez, ils s'en moquent.
- Linter, révision du code - ne pas enregistrer?J'ai deux réponses. Oui, ils le font. Non, ils n’économisent pas. Cela aide si vous suivez strictement les règles et les réglementations qui vous sont données par les lanternes alignées (ceux qui font beaucoup de travail difficile pour vous: vérifiez la complexité des fonctions, la sémantique du code, etc.). Cet élément doit être bloquant. Vous ne pouvez pas simplement exécuter le linter parfois pour regarder le résultat. Si vous ne respectez pas ces règles, vous ne devez pas du tout publier le code en production.
Mais en fait - ils ne sauvent pas. Parce que les projets qui l'utilisent sont rares.
Soit dit en passant, ils me demandent souvent: comment introduire cela? Et je réponds: c'est très simple, vous mettez une ligne dans CI - vérifiez mon code - et si ça plante, c'est tout, vous l'avez implémenté. Il ne reste plus qu'à tout refaçonner. Heureusement, il existe maintenant des formats automatiques et la possibilité de refactoriser le code fichier par fichier. La question suivante est traditionnelle: comment expliquer à l'entreprise que c'est important?
- Y a-t-il une réponse générale à cette question?Pour chaque cas, les réponses sont différentes, donc dans le cas général il est difficile de formuler (il faut y penser, à ce sujet ...). Mais généralement, les entreprises qui traitent ce problème viennent du côté technique. C'est-à-dire les technophiles nous demandent, car les gens qui savent comment parler des affaires et de la technologie comprennent comment expliquer cela aux entreprises dans leur cas particulier. Avec une telle déclaration du problème, cela fonctionne très simplement. Quand vous venez, tout est déjà mauvais et tout le monde le comprend. Une conversation avec les entreprises commence comme ceci: "Vous pensez probablement que vos programmeurs sont assis et ne font rien?" Et l'entreprise hoche la tête. Et vous dites que ce n'est pas le but. Les programmeurs sont des gars formidables qui essaient de résoudre vos problèmes. Mais sans une approche intégrée de la gestion de projet, tout tombe dans le chaos, et c'est normal.
Et nous proposons de proposer des règles pour éviter certains problèmes. Nous considérons le coût de l'introduction de différentes pièces, puis nous évaluons les pertes réelles (accomplies) du fait qu'il n'y en a pas encore. Par exemple, les programmeurs ont corrigé un bogue pendant un mois qui n'existe pas ou qui peut être trouvé en 30 secondes, si vous utilisez une approche et un outil spécifiques. Les chiffres convaincent bien.
- Au final, est-ce un problème administratif?Bien sûr. Je suis convaincu que les programmeurs veulent écrire du bon code. Mais il existe divers obstacles. Quelqu'un ne sait pas comment à cause de l'inexpérience. Quelqu'un a perdu sa motivation, parce que tout le monde s'en fout. Quelqu'un ne sait pas exactement ce qu'est un bon code pour la raison, par exemple, de lancer créatif. Ils font pression sur quelqu'un - il veut et peut écrire, mais ils lui disent que ce devrait être demain. Et au lieu de nouer des partenariats avec les entreprises et d'expliquer pourquoi cela ne se produira pas demain (ou si c'est le cas, il faudra alors statuer pendant encore trois jours), il le fait de toute façon. Et ces partenariats sont intéressants pour l'entreprise elle-même. Il doit également le faire fonctionner pendant longtemps et être bon marché à entretenir.
Autrement dit, tous les problèmes sont résolus ici: il n'y a pas de contradictions insolubles.
- Il existe un style de code - PEP 8. Cela n'aide pas à comprendre rapidement ce qui est bon?En termes de virgules, cela aide. Mais à quoi ça sert si vous mettez les virgules à droite et que tout le reste est mauvais?
- Vous manquez des trucs de haut niveau bien connus?En théorie, il existe certaines meilleures pratiques d'ingénierie. Mais ils sont soit inconnus, soit ignorés. Lorsque vous demandez pourquoi le développeur n'a pas suivi cette pratique, il répond qu'il a entendu que c'est un bon sujet, mais le code fonctionne comme ça. Lorsque le code cesse de fonctionner, vous lui demandez s'il a compris d'où provenait la meilleure pratique correspondante et pourquoi la suivre? Non, je ne comprends pas. Il pense qu'il s'est simplement trompé.
Il est assez difficile d'expliquer à une personne que faire des erreurs est normal. Tout le monde a tort, nous sommes tous humains. Mais la meilleure pratique d'ingénierie vient d'être inventée pour vous éviter une erreur ou vous protéger des conséquences. C'est-à-dire c'est un outil de sécurité, comme dans les entreprises. Ce n'est écrit qu'avec du sang, mais avec du temps et de l'argent.
En général, notre tâche globale inaccessible est d'automatiser la révision du code afin que Python lui-même (si nous parlons de notre cas) sache comment l'écrire. Cela devrait être un outil qui offre non seulement des opportunités, mais aussi des limitations aux développeurs.
- Pourquoi développez-vous même un linter? Est-il possible d'utiliser (ou de développer) ceux existants?En fait, nous le faisons. Notre linter est en fait un plugin pour Flake8. Nous le positionnons simplement comme un outil à part entière, et pas seulement comme un plug-in.
Pourquoi Flake8 et pas Pylint? Pylint fait beaucoup de ce que le linter ne devrait pas faire. Par exemple, il implémente un très grand nombre de vérifications de type, bien que le vérificateur de type doive traiter les types. De plus, il produit un très grand nombre d'erreurs, qui ne le sont pas. Et je n'aime pas sa documentation, et j'ai peur de sa propre implémentation de ast. Il est difficile à configurer. En activant la configuration, vous laissez les gens faire les mauvais choix. Par conséquent, notre tâche consiste à créer un outil qui ne peut pas être configuré. Donc, vous le dites - c'est tout.
- Quels guides ont formé la base de ce linter? Ou est-ce seulement votre propre expérience ici?Maintenant, il est basé sur les règles que nous avons formulées pour nous-mêmes lors de la révision du code depuis de nombreuses années. Certaines règles ont été portées à partir d'autres linters: ESLint, Pylint, SonarQube, Credo. Beaucoup a été tiré de l'excellent travail
de CognitiveComplexity . J'ai toujours regardé le portefeuille de Miller. Des règles distinctes - c'est ma vision, qui est apparue après avoir évalué un grand nombre de codes d'autres personnes. Autrement dit, à ce stade, c'est un "méli-mélo".
- De quoi allez-vous parler à Moscou Python Conf ++?Tout d'abord, sur
la gestion de la complexité . Ce sujet est proche et compréhensible pour tous les développeurs. Nous examinerons différentes métriques, sur les façons de transférer la complexité du code de composant le plus simple - les lignes - au module le plus complexe. Et puis nous parlerons de la partie holivaire, où je présenterai ma vision de la façon d'écrire ou de ne pas écrire en Python, et demander aux utilisateurs de voter sur ce qu'ils aiment ou non. Pour de nombreux développeurs, les restrictions (faire A, mais pas B) sont une tentative sur leur espace créatif, ils réagissent donc très violemment à cela. Et juste ici, vous pouvez commencer une discussion intéressante.
- Sur qui porte le rapport?Je pense que ce sont encore des développeurs établis, car les programmeurs débutants n'ont pas encore formé leur opinion claire. Bien qu'il soit intéressant pour eux d'écouter et de s'exprimer. Ce sont certainement nos utilisateurs.
, ,
Moscow Python Conf++ . . ,
.