Expliquant la différence entre la rigueur des langues et les paradigmes à un de mes collègues, j'ai fini par affirmer que:
Les langues tolérantes, telles que les langues dynamiques et interprétées, sont mieux utilisées pour les prototypes et les petits projets ou les applications Web de taille moyenne. Lorsque vous choisissez des langages dynamiques élégants tels que Python ou JavaScript avec Node.js, les avantages sont les suivants:
Développement rapide,
Code passe-partout réduit,
Capacité d'attirer de jeunes programmeurs créatifs qui fuient les "langages d'entreprise" comme Java.
Les langages typés/compilés statiquement conviennent mieux aux applications qui nécessitent une plus grande rigueur, telles que les applications critiques ou les applications pour les applications de taille moyenne à grande.
Paradigmes et schémas bien connus développés depuis des décennies,
Facilité de vérification statique,
Capacité à trouver de nombreux développeurs professionnels avec des décennies d'expérience.
Les langages stricts tels que Haskell, Ada ou des techniques telles que les contrats de code en C # conviennent mieux aux systèmes qui privilégient la sécurité à la flexibilité (même si Haskell peut être extrêmement flexible), tels que les systèmes vitaux et les systèmes qui devraient être extrêmement stables. Les avantages sont les suivants:
Possibilité d'attraper autant de bugs que possible au moment de la compilation,
Facilité de vérification statique,
Facilité de preuves formelles.
Cependant, en regardant les langages et technologies utilisés pour les projets à grande échelle par les grandes entreprises, il semble que mon affirmation soit fausse. Par exemple, Python est utilisé avec succès pour les grands systèmes tels que YouTube ou d'autres applications Google qui nécessitent une quantité importante de rigueur.
Existe-t-il encore une corrélation entre l'échelle du projet et la rigueur du langage/paradigme à utiliser?
Y a-t-il un troisième facteur que j'ai oublié de prendre en compte?
Où ai-je tort?
Une étude de cas intéressante sur les questions de mise à l'échelle des projets qui utilisent un langage dynamique et interprété peut être trouvée dans Beginning Scala par David Pollak.
J'ai commencé à chercher un moyen d'exprimer le code dans mon cerveau d'une manière plus simple et plus directe. J'ai trouvé Ruby et Rails. Je me suis sentie libérée. Ruby m'a permis d'exprimer des concepts dans beaucoup moins de lignes de code. Rails était tellement plus facile à utiliser que Spring MVC, Hibernate et les autres frameworks Web "rationalisés" Java. Avec Ruby et Rails, j'ai pu exprimer beaucoup plus de ce qui était dans ma tête en moins de temps. C'était similaire à la libération que j'ai ressentie lorsque je suis passé de C++ à Java ...
Au fur et à mesure que mes projets Ruby et Rails dépassaient quelques milliers de lignes de code et que j'ajoutais des membres de l'équipe pour mes projets, les défis des langages dynamiques sont devenus apparents.
Nous passions plus de la moitié de nos tests d'écriture de temps de codage, et une grande partie des gains de productivité que nous avons vus ont été perdus lors de l'écriture de tests . La plupart des tests auraient été inutiles dans Java car la plupart d'entre eux visaient à nous assurer que nous avions mis à jour les appelants lorsque nous avons refactorisé le code en modifiant les noms de méthode ou le nombre de paramètres. De plus, j'ai trouvé que travailler dans des équipes où il y avait des mélanges d'esprit entre deux à quatre membres de l'équipe, les choses se passaient bien dans Ruby, mais comme nous avons essayé d'amener de nouveaux membres dans l'équipe, les connexions mentales étaient difficiles à transmettre aux nouveaux membres de l'équipe .
Je suis parti à la recherche d'un nouvel environnement de langage et de développement. Je cherchais un langage aussi expressif que Ruby mais aussi sûr et aussi performant que Java ...
Comme vous pouvez le voir, les principaux défis de la mise à l'échelle des projets pour les auteurs se sont révélés être le développement de tests et le transfert de connaissances.
En particulier, l'auteur explique plus en détail les différences d'écriture de test entre les langues typées dynamiquement et statiquement dans le chapitre 7. Dans la section "Poignantly Killing Bunnies: Dwemthy's Stairs", l'auteur discute Scala du port d'un particulier Ruby exemple:
Pourquoi le Lucky Stiff ... introduit certains des concepts de métaprogrammation de Ruby dans Dwemthy’s Array dans lequel un lapin se bat contre un éventail de créatures. N8han14 a mis à jour l'exemple pour fonctionner dans Scala ...
Par rapport au code Ruby, les parties de bibliothèque du code Scala étaient plus complexes. Nous avons dû faire beaucoup de travail pour nous assurer que nos types étaient corrects. Nous avons dû réécrire manuellement les propriétés de Creature dans les classes DupMonster et CreatureCons. C'est plus de travail que
method_missing
. Nous avons également dû faire beaucoup de travail pour soutenir l'immuabilité dans nos créatures et nos armes.En revanche, le résultat était beaucoup plus puissant que la version Ruby. Si nous devions écrire des tests pour notre Ruby code pour tester ce que le compilateur Scala nous assure, nous aurions besoin de beaucoup plus de lignes de code. Par exemple, nous pouvons être sûrs que notre lapin ne pouvait pas manier une hache. Pour obtenir cette assurance dans Ruby, nous devons écrire un test qui garantit que l'invocation de
|^
Sur un lapin échoue. Notre Scala la version garantit que seules les armes définies pour une créature donnée peuvent être utilisées par cette créature, ce qui nécessiterait beaucoup de réflexion d'exécution dans Ruby ...
La lecture ci-dessus peut faire penser que les projets devenant encore plus grands, la rédaction des tests peut devenir trop lourde. Ce raisonnement serait erroné, comme en témoignent les exemples de très gros projets réussis mentionnés dans cette même question ("Python est utilisé avec succès pour ... YouTube").
Le fait est que la mise à l'échelle des projets n'est pas vraiment simple. De très grands projets à longue durée de vie peuvent "se permettre" différents processus de développement de tests, avec des suites de tests de qualité de production, des équipes professionnelles de développement de tests et d'autres éléments lourds.
Les suites de tests YouTube ou le kit de compatibilité Java ont une vie différente de celle des tests d'un petit projet de didacticiel comme Dwemthy's Array .
Votre affirmation n'est pas fausse. Vous avez juste besoin de creuser un peu plus profondément.
En termes simples, les grands systèmes utilisent plusieurs langues, pas seulement une langue. Il peut y avoir des parties qui sont construites en utilisant des langages "stricts", et il peut y avoir des parties qui sont construites en utilisant des langages dynamiques.
Quant à votre exemple Google et YouTube, j'ai entendu dire qu'ils utilisent Python principalement comme "colle" entre divers systèmes. Seul Google sait avec quoi ces systèmes sont construits, mais je parie que bon nombre des critiques de Google les systèmes sont construits en utilisant des langages stricts et "d'entreprise" comme C++ ou Java, ou peut-être quelque chose qu'ils ont eux-mêmes créé comme Go.
Ce n'est pas que vous ne pouvez pas utiliser des langages tolérants pour les systèmes à grande échelle. Beaucoup de gens disent que Facebook utilise PHP, mais ils oublient de mentionner que Facebook a dû créer des directives de programmation extrêmement strictes pour l'utiliser efficacement à cette échelle.
Alors oui, un certain niveau de rigueur est requis pour les projets à grande échelle. Cela peut provenir soit de la rigueur du langage ou du framework, soit des directives de programmation et des conventions de code. Vous ne pouvez pas simplement attraper quelques diplômés universitaires, leur donner Python/Ruby/JavaScript et s'attendre à ce qu'ils écrivent des logiciels qui s'adaptent à des millions d'utilisateurs.
Mon expérience avec les grands systèmes est qu'ils se maintiennent ou ne tombent pas par choix de langue, mais par des problèmes de conception/architecture ou couverture de test. Je préfère avoir une équipe talentueuse Python sur mon grand projet d'entreprise, plutôt qu'une équipe médiocre Java.
Cela dit, tout langage qui vous permet d'écrire de manière significative moins de code, doit être examiné (par exemple Python vs Java). Peut-être que l'avenir est intelligent, langages de type statique avec inférence de type avancée (par exemple dans le moule Scala). Ou hybride, tel que C # tente avec son qualificatif dynamic
...?
Et n'oublions pas les "autres" avantages de la frappe statique: bon IDE complétion de code/intellisense, qui, à mon avis, est une fonctionnalité essentielle, pas un élément indispensable.
Il existe deux types d'erreurs à vérifier: les erreurs de type (concaténer un entier + liste de flottants) et les erreurs de logique métier (transférer de l'argent sur un compte bancaire, vérifier si le compte source a de l'argent).
La partie "dynamique" d'un langage de programmation dynamique est juste l'endroit où la vérification de type a lieu. Dans un langage de programmation "typé dynamiquement", la vérification du type est effectuée lors de l'exécution de chaque instruction, tandis que dans un langage "langage typé typiquement", la vérification est effectuée au moment de la compilation. Et vous pouvez écrire un interpréteur pour un langage de programmation statique (comme emscriptem ne), et vous pouvez également écrire un compilateur statique pour un langage de programmation dynamique (comme gcc-python ou shed-skin le fait).
Dans un langage de programmation dynamique comme Python et Javascript, vous devez écrire des tests unitaires non seulement pour la logique métier du programme, mais également pour vérifier si votre programme n'a pas de syntaxe ou d'erreurs de type. Par exemple, si vous ajoutez "+" un entier à une liste de flottants (ce qui n'a pas de sens et générera une erreur), dans un langage dynamique, l'erreur sera déclenchée lors de l'exécution lors de la tentative d'exécution de l'instruction. Dans un langage de programmation statique comme C++, Haskell et Java, ce type d'erreur de type sera détecté par le compilateur.
Une petite base de code dans un langage de programmation vérifié dynamiquement est plus facile à rechercher des erreurs de type car il est plus facile d'avoir un 100% couverture de code source. Voilà, vous exécutez le code à la main plusieurs fois avec des valeurs différentes et vous avez terminé. Avoir une couverture à 100% du code source vous donne une bonne idée que votre programme peut ne pas avoir erreurs de type .
Avec une grande base de code dans un langage de programmation vérifié dynamiquement, il est plus difficile de tester chaque instruction avec toutes les combinaisons de types possibles, surtout si vous êtes imprudent et écrivez une fonction qui peut renvoyer une chaîne, une liste ou un objet personnalisé en fonction de ses arguments.
Dans un langage de programmation à vérification statique, le compilateur détectera la plupart des erreurs de type au moment de la compilation. Je dis le plus parce qu'une erreur de division par zéro ou une erreur de tableau hors limites sont également des erreurs de type.
Le plus souvent, la véritable discussion ne porte pas sur les langages de programmation mais sur les personnes utilisant ces langages. Et cela est vrai parce que, par exemple, le langage d'assemblage est aussi puissant que tout autre langage de programmation, mais nous écrivons du code sur JavaScript. Pourquoi? Parce que nous sommes humains. Tout d'abord, nous commettons tous des erreurs et il est plus facile et moins sujet aux erreurs d'utiliser un outil dédié spécialisé pour une tâche spécifique. Deuxièmement, il y a une contrainte de ressources. Notre temps est limité et l'écriture de pages Web sur Assembly prendrait beaucoup de temps.
Une autre considération est le qui derrière l'écriture d'applications à grande échelle. J'ai travaillé dans de nombreux endroits qui souhaitent utiliser Ruby ou Python sur certains grands projets de style entreprise, mais sont systématiquement "abattus" par les responsables informatiques) et les équipes de sécurité d'entreprise précisément en raison de la nature open source des projets.
On m'a dit: "Nous ne pouvons pas utiliser Ruby on Rails parce qu'il est open source et que quelqu'un pourrait y mettre des hacks qui volent des informations critiques ou protégées) "Je suis désolé, mais une fois que quelqu'un a cet état d'esprit que l'open source == le mal, il est presque impossible de le changer. Cette ligne de pensée est une maladie d'entreprise.
C # et Java sont des langages de confiance avec des plates-formes de confiance. Ruby et Python ne sont pas des langues de confiance.