KISS ("garder les choses simples, stupides" ou "garder les choses simples stupides", voir par exemple ici ) est un principe important dans le développement de logiciels, même s'il semble provenir de l'ingénierie. Citant de l'article de wikipedia:
Le principe est mieux illustré par l'histoire de Johnson remettant à une équipe d'ingénieurs concepteurs une poignée d'outils, avec le défi que l'avion à réaction qu'ils concevaient doit être réparable par un mécanicien moyen sur le terrain dans des conditions de combat avec uniquement ces outils. Par conséquent, le «stupide» fait référence à la relation entre la façon dont les choses se brisent et la sophistication disponible pour les réparer.
Si je voulais l'appliquer au domaine du développement logiciel, je remplacerais "avion à réaction" par "logiciel", "mécanicien moyen" par "développeur moyen" et "dans des conditions de combat" par "dans le cadre du développement / de la maintenance logicielle attendue". conditions "(délais, contraintes de temps, réunions / interruptions, outils disponibles, etc.).
C'est donc une idée communément acceptée que l'on devrait essayer de garder un logiciel simple (ou simplement stupide , au cas où vous omettez la virgule) afin qu'il soit facile de travailler dessus plus tard.
Mais le principe KISS peut-il s'appliquer également à la conception d'un langage de programmation? Connaissez-vous des langages de programmation spécialement conçus avec ce principe à l'esprit, c'est-à-dire "permettre à un programmeur moyen dans des conditions de travail moyennes d'écrire et de maintenir autant de code que possible avec le moins d'effort cognitif"?
Si vous citez une langue spécifique, ce serait bien si vous pouviez ajouter un lien vers un document dans lequel cette intention est clairement exprimée par les concepteurs de la langue. Dans tous les cas, je serais intéressé à en savoir plus sur les intentions (documentées) des concepteurs plutôt que sur votre opinion personnelle sur un langage de programmation particulier.
Réponses:
Quand je pense au minimalisme, je pense à Lisp and Go . Avec Lisp, vous n'avez que des fonctions et des listes, ce qui est à peu près aussi simple que possible (enfin, il y en a un peu plus, mais peu importe). Cependant, je pense que l'affaire Go est plus intéressante.
Go a été conçu pour être simple (c'est une lecture décente). Le terme qu'ils utilisent est «orthogonalité des entités», ce qui signifie que toute entité ne doit être ajoutée que si elle fournit quelque chose de vraiment unique. Cela semble découler de l' implication des auteurs ( Russ Cox et Rob Pike ) dans Plan9 , qui était une réimagination d'UNIX avec la simplicité à l'esprit. (Si vous êtes intéressé par un design minimal, le document de Rob Pike sur un système de fenêtrage simple est une bonne lecture.)
Voici quelques exemples simples de la syntaxe:
Une seule construction en boucle
Une boucle peut ressembler à l'un des éléments suivants:
Boucle infinie
Boucle while
Boucle traditionnelle
Boucle Foreach
Interrupteur polyvalent
Retour multiple
Interfaces
Incorporation
Chaînes
Peut être utilisé pour implémenter des sémaphores
Utilisé pour le message passant entre les threads
Peut être utilisé pour gérer des événements asynchrones
Conclusion
Je ne vais pas entrer dans toutes les parties de la syntaxe, mais j'espère que vous pourrez voir ce que le minimalisme peut faire. Le langage intrigue non pas parce qu'il ajoute une tonne de nouvelles fonctionnalités, mais parce qu'il utilise les meilleures fonctionnalités d'autres langues sans rien de plus.
Il existe généralement une «meilleure» façon de résoudre un problème. Par exemple, sur la liste de diffusion, de nombreux utilisateurs se plaignent de ne pas avoir de génériques. Après discussion, ils se rendent compte que tout ce qu'ils veulent faire peut se faire avec des interfaces. Lisez sur go efficace pour des exemples sur la syntaxe idiomatique.
L'avantage des langues KISS est qu'il est possible d'écrire du code idiomatique, car le style de code est limité par la langue. Par exemple, dans Go, vous ne pouvez pas écrire quelque chose comme ceci:
Vous devez utiliser des accolades:
Il existe de nombreux autres exemples de cela dans la syntaxe, ce qui facilite la lecture du code d'autres personnes.
Avantages du langage KISS par rapport aux langages riches en fonctionnalités:
la source
for i=1 to 10
for item in group
for i = 1 to 10
est de savoir sii
sera jamais 10. Cela peut dépendre de la langue (bash inclut 10, python non). La boucle for traditionnelle est universelle.Je pense que le Zen de Python expliquera pourquoi Python est un langage simple beaucoup mieux que moi:
Modifier en réponse à @Giorgio
Comme l'indique votre question,
Le python est, pour moi, ce qui me vient immédiatement à l'esprit. Le design de Python est en réponse directe à la méthodologie de Perl, le fameux "Il y a plus d'une façon de le faire". Bien que ce soit génial, permettant aux programmeurs d'écrire très facilement du code, cela n'aide pas à la maintenance. Ayant auparavant géré un programme (très mal écrit, je l'admets) écrit en Perl, j'apprécie Python forçant à la fois de bonnes pratiques de codage et un langage concis.
Python ne vous oblige pas non plus à suivre une méthodologie particulière lors de l'écriture de programmes. Je peux choisir de suivre un style de programmation orienté objet strict, ou je peux écrire un script simple à exécuter séquentiellement. Ne pas avoir à initialiser une classe, puis appeler la
main()
méthode comme vous êtes obligé de le faire en Java est très agréable. (De plus, l'impression sur stdout en Python est merveilleuse, mais c'est un point plutôt nul).Enfin, la méthodologie "Batteries incluses" consistant à inclure une bibliothèque standard étendue avec le langage est merveilleuse. Au lieu de parcourir un référentiel externe pour les packages, la plupart de ce dont j'ai besoin est déjà inclus dans la langue. C'est aussi bien d'avoir ce dépôt externe, mais ne pas avoir à creuser pour effectuer une opération de base est vraiment pratique.
la source
import this
commande.Une clé majeure pour maintenir la "simplicité" est de reconnaître quand la complexité sera nécessaire, et de faire en sorte que les parties du système qui puissent le mieux y faire face. Le fait d'avoir un seul type de référence d'objet qui ne fait aucune distinction entre les valeurs immuables, les valeurs mutables et les entités, rend Java "simple", n'élimine pas la nécessité de faire la distinction entre les valeurs et les entités; il prive simplement les programmeurs d'outils pour les aider à le faire.
Plus généralement, si l'on essaie de faire en sorte qu'un langage de programmation ou une fonctionnalité de structure prennent en charge plusieurs cas d'utilisation, il faut s'assurer qu'il n'y aura pas de situations où des comportements différents seraient appropriés dans différents cas d'utilisation, mais le compilateur serait incapable de dire les séparer. Ajouter plus de types à un langage ou à un framework peut sembler une complication, mais dans de nombreux cas, cela peut en fait faciliter les choses.
Considérez, par exemple, le désordre des règles entourant les types signés et non signés en C. La complexité de ces règles provient du fait que certains codes utilisent des types entiers non signés pour représenter les nombres, tandis que d'autres codes les utilisent pour représenter les membres d'un anneau algébrique enveloppant (spécifiquement, l'ensemble des entiers congruents mod 2ⁿ). Les règles de conversion de type se comportent de manières qui sont parfois appropriées à une utilisation, et parfois de manière appropriée à l'autre. Le fait d'avoir des types d'habillage et de non-habillage séparés doublerait le nombre de types entiers, mais pourrait simplifier les règles qui leur sont associées:
Tout type entier non-anneau de n'importe quelle taille peut être affecté à un anneau de n'importe quelle taille; un anneau ne peut être attribué qu'à un anneau de taille égale ou inférieure .
Les opérations autres que les opérateurs relationnels impliquant un entier non-anneau et un anneau convertiront implicitement l'entier en type d'anneau.
Les anneaux peuvent être explicitement convertis en nombres ou en anneaux plus grands; la valeur d'un anneau non signé est le plus petit entier non négatif qui, ajouté au zéro de l'anneau, donnerait la valeur de l'anneau. La valeur d'un anneau signé est le plus petit nombre entier qui, ajouté au zéro de l'anneau, donnerait la valeur de l'anneau, la valeur négative étant préférée en cas d'égalité.
Sauf comme mentionné ci-dessus, les anneaux sont limités aux opérations avec des anneaux de même taille ou plus petits.
Les opérations sur des entiers non-ring de différents types doivent transposer les nombres en un type qui peut prendre en charge toutes les valeurs de l'un ou l'autre opérande, ou doivent être rejetées par le compilateur si aucun type approprié n'existe
La définition des types d'anneaux semblerait doubler le nombre de types entiers, mais simplifierait grandement l'écriture de code portable. L'utilisation des mêmes types non signés pour les nombres et les sonneries réduit le nombre de types, mais conduit à des règles compliquées qui rendent presque impossible l'écriture de code portable efficace.
la source
On peut dire que Tcl a été développé dans ce sens. La langue entière peut être décrite en seulement 12 règles sur une seule page de manuel . C'est remarquablement simple et cohérent.
Le créateur de Tcl a déclaré que les objectifs suivants étaient les suivants:
Extrait de " History of Tcl " - http://www.tcl.tk/about/history.html
la source
Si une langue est fixée dans sa conception à cause de KISS, elle ne peut pas grandir. Une langue qui ne peut pas grandir mourra.
Dans la vidéo suivante, Guy Steele explique intelligemment qu'un langage de programmation doit se développer et pourquoi. Si vous appliquez KISS, alors comment une langue peut-elle grandir car une fois publiée, son ensemble d'outils est fixe et ne peut jamais changer.
C'est une vidéo d'une heure mais qui mérite d'être regardée. Si vous ne savez pas qui est Guy Steele, vous devriez vraiment le faire lorsque vous parlez de conception de langage.
J'ai choisi cette vidéo comme réponse parce que je pense qu'appliquer KISS à la conception de langage en général est une erreur, et j'espère que voir un discours d'une personne réputée de la conception de langage vous aidera à élargir votre compréhension de l'avenir de la conception de langage.
Depuis que vous êtes venu ici pour en savoir plus sur la conception de langage et que je vous ai donné une raison de ne pas utiliser KISS, il est juste que je souligne quelque chose que je trouve utile dans la conception de langage. Dimensions cognitives des notations
ÉDITER
Quand j'ai écrit la réponse ci-dessus, elle était basée sur le raisonnement suivant: si un moteur ne peut être maintenu qu'avec un ensemble d'outils fixe, ma reformulation de ce sens en ce qui concerne la conception du langage est qu'un langage ne peut pas changer une fois publié. Les commentaires indiquent que ce n'était pas ce que l'on voulait dire. Permettez-moi donc de présenter cette réponse modifiée qui sera plus conforme à la nouvelle entente.
Si l'on jette un œil aux dimensions cognitives des notations, on apprend qu'il existe de nombreuses dimensions concurrentes associées à la conception du langage que la simple simplicité et si vous vous concentrez trop sur l'une, vous en souffrirez dans d'autres. Avec la question de se concentrer fortement sur la simplicité (KISS), et soutenu par des personnes remarquables du design linguistique, j'ai soumis le discours de Guy Steele pour montrer qu'essayer de garder un design uniquement simple aura un impact sur d'autres dimensions. Plus important encore, j'essaie de faire comprendre que vous devez examiner de nombreuses dimensions et peser le pour et le contre, pas seulement la simplicité.
la source
Voici une grande citation du Hardcore Visual Basic de Bruce McKinney , qui à son tour met les mots dans la bouche des concepteurs de BASIC, Kemeny et Kurtz . Souligne le mien.
la source
C'est une bonne chose que vous ayez clarifié ce que vous entendez par "simple", car dans mon esprit, un langage de programmation simple est un langage avec une syntaxe minimale et peu de fonctionnalités (Scheme, Forth, ML), qui ne se traduit pas directement dans votre définition. Je pense que vous cherchez vraiment la conception de langages avec RAD (développement rapide d'applications) à l'esprit, et il y en a pas mal. Voir ce fil StackOverflow, par exemple: /programming/66227/what-is-the-best-multi-platform-rad-language
la source
Je suis surpris que personne n'ait encore mentionné C, même s'il met la simplicité au premier plan de plusieurs façons importantes, souvent d'une manière si radicale que les programmeurs ne parviennent pas à apprécier la simplicité:
Il n'y a pas de magie cachée. Si vous écrivez
a + b
en C, vous avez la garantie qu'il sera compilé en une seule instruction assembleur au maximum.Même dans des langages relativement simples comme Java, une simple instruction comme
a + b
peut prendre plusieurs microsecondes (si les variables sont des chaînes). D'autres langages ajoutent beaucoup, beaucoup plus à cela avec l'exemple extrême de C ++ oùa + b
peut être surchargé pour faire apparaître les éléphants roses. Ce n'est pas le cas en C: s'il ne s'agit pas d'un appel de fonction, cela ne prendra pas plus de quelques nanosecondes. Cette prévisibilité des performances est l'une des principales caractéristiques de C, et c'est certainement une forme de simplicité.Les types de données sont aussi simples que possible tout en décrivant toutes les structures de données intéressantes que vous pourriez vouloir créer en mémoire: il n'y a que les types fondamentaux qu'un processeur peut gérer + agrégation (
struct
) + répétition (tableaux) + références (pointeurs) ).Il est vrai que les différents langages basés sur lisp sont beaucoup plus simples que C à cet égard. Cependant, ils n'essaient pas de permettre au programmeur de manipuler librement la mémoire comme le fait C.
Orthogonalité des fonctionnalités: vous pouvez combiner librement les fonctionnalités et elles fonctionneront ensemble comme prévu. De nombreux langages échouent en permettant à certaines constructions d'apparaître uniquement dans des contextes définis.
Prenons par exemple les tableaux de longueur variable en C et C ++: C autorise les longueurs d'exécution partout tandis que les demandes les plus libérales pour étendre la norme C ++ ne les autorisent que dans certains contextes comme les tableaux automatiques et même là seulement dans la première dimension. Cela permet à C de gérer de véritables tableaux multidimensionnels avec des tailles connues uniquement au moment de l'exécution, tandis que les programmeurs C ++ sont réduits à écrire
data[k + (j + i*lineLength)*lineCount]
encore et encore.Un autre exemple de ceci est le pointeur: un pointeur de données en C ce n'est rien de plus ou moins qu'une simple variable contenant une adresse mémoire d'une autre variable. Puisque le pointeur est lui-même une variable, le double pointeur est une chose bien définie. C'est-à-dire, étant donné ce qui est
int
et ceint*
qu'il est, il est clair ce quiint**
doit être. Comparez cela aux références C ++ où vous n'avez absolument aucune idée de ce quiint&&
est donné le sens deint
etint&
!)Il est vrai que c'est précisément cette simplicité qui a valu à C tant de haine: la simplicité du langage permet aux programmeurs plus de liberté que bon pour eux, conduisant à beaucoup de problèmes avec un comportement indéfini et des pointeurs mal gérés. Surtout la simplicité de l'orthogonalité qui permet à un programmeur de définir une variable telle qu'elle
int (*array[m])(struct foo* (*arg)[n])
est du type qui tend à donner des maux de tête aux lecteurs car des choses vraiment complexes peuvent être exprimées sous une forme très concise par une combinaison libérale de quelques fonctionnalités simples . C'est le type de simplicité auquel C excelle, et qui lui donne la réputation d'être un langage difficile à utiliser.De plus, la simplicité du langage oblige le programmeur à écrire beaucoup plus de code que les langages plus riches en fonctionnalités, fournissant un terrain plus fertile pour que les bogues prospèrent. Néanmoins, il reste le langage de haut niveau le plus simple possible si votre objectif principal est de programmer un vrai ordinateur et non une machine virtuelle.
la source
Java Wikipedia - bien que cela ne soit pas explicitement indiqué dans Wikipedia, la simplification est mentionnée à plusieurs reprises et était un objectif de conception original, car le seul langage sérieux capable OO (terme utilisé de manière lâche) à cette époque était le C ++, qui, comme nous le savons tous, est puissant mais a plus de quelques pièges pour les imprudents.
La machine virtuelle Java était conçue comme un moyen de simplifier le développement multiplateforme et «Écrire une fois, exécuter n'importe où» est devenu un mantra Java pendant quelques années - encore une fois, l'intention était que le cadre était simple à déployer.
Je crois que C # tombe dans cette catégorie de simplification du langage.
la source
Hm ... c'est en fait une question difficile à répondre "positivement", parce que quand je pense à la simplicité dans la conception du langage de programmation (et ce qui est "plus facile" à travailler), je pense immédiatement à:
Il y a un certain nombre de langues qui font bien ces choses - mais ce qui me vient à l'esprit est une langue qui ne fait pas bien les choses «en tant que langage de programmation»: PHP.
[Avertissement - J'ai écrit PHP et PHP est toujours mon «go to language» pour les projets Web simples. Ceci est une critique de l'amour ...]
Premièrement, PHP fonctionne bien pour l'environnement qu'il exécute généralement sur les serveurs Web. Il est facile à installer, à entretenir, etc.
Là où j'ai du mal avec PHP: lorsque vous voulez faire quelque chose d '"inhabituel" - quelque chose que vous ne faites généralement pas régulièrement (dans le cas où je pense qu'il consomme un service Web SOAP - pas quelque chose que j'ai beaucoup fait avec PHP), vous êtes confronté à deux options:
1) Diverses extensions open source de PHP. Le modèle d'objet PHP est suffisamment lâche lorsque la conception de l'interface n'est pas non plus très cohérente d'une bibliothèque à l'autre, d'un développeur à l'autre. Lorsque vous êtes confronté à un ensemble de codes où quelqu'un a utilisé une bibliothèque dont vous n'avez jamais entendu parler, vous passez beaucoup de temps à comprendre `` ce que ça peut faire '' car le langage permet une création d'API / bibliothèque lâche.
2) Les fonctions "intégrées" - dont il y en a beaucoup . Je suis passé par quelques trous de lapin de trouver une autre bibliothèque ou d'implémenter un peu de fonctionnalité pour tomber plus tard sur
impossiblyfound_basefunction()
À mon avis, la simplicité est la cohérence.
la source
Maintenant, l'approche KISS des langages de programmation est une notion amusante, du moins si vous considérez les langages de programmation comme une couche d'abstraction du jeu d'instructions d'un processeur, etc. Si vous ne définissez pas "KISS" de plus près. Je dis juste ici, qu'un char à bœufs est KISS appliqué à une voiture à son maximum.
Maintenant, une autre interprétation de KISS pourrait être quelque chose comme "intelligemment fait sans ornements inutiles et pas trop compliqué". En particulier, on pourrait dire qu'il ne devrait pas y avoir trop de cas spécifiques pour des choses similaires, etc. .
Pour la programmation, il existe 2 modèles abstraits assez connus:
Ce qui est amusant, c'est que si la machine de turing est assez simple dans sa configuration, ce n'est pas un système facile à manipuler et je ne pense pas qu'elle soit qualifiée de "smart KISS". Mais Lambda Calculus a plus à voir avec les langages de programmation que nous connaissons - et avec les fonctionnalités pionnières de Lisp et Scheme du calcul lambda, il a fait son chemin dans de nombreux langages.
Lisp et Scheme sont VRAIMENT simples, au moins en termes de syntaxe. La syntaxe est un problème majeur avec les langages de programmation (c'est probablement pourquoi ils sont réinventés tout le temps). Dans le cas de C ++, il est presque impossible pour le cerveau humain de prédire comment certaines lignes source sont interprétées par le compilateur.)
Les lisps réduisent complètement la complexité syntaxique en introduisant une forme commune pour les commandes:
Cela peut être un appel de méthode, tel que
ainsi qu'une branche if, une boucle, etc.
(tout le code ici est agnostique pseudo-lisp / dialecte)
La forme
peut également être interprété comme une liste
Et c'est la base de la simplicité et de la beauté de Lisps. Parce que les listes imbriquées (comme dans l'
if
exemple de déclaration) constituent des arbres et ceux-ci peuvent être facilement compris à la fois par la machine et par l'homme devant la machine.Une autre caractéristique de Lisps sont les macros, je n'entrerai pas dans les moindres détails ici, mais puisqu'il n'y a pas de différence syntaxique entre les appels de fonction normaux et "Syntaxe (œuf pour les boucles, déclaration de variable, etc., tout ce que l'analyseur doit gérer dans d'autres langages de programmation) vous pouvez créer votre propre syntaxe. Les macros sont essentiellement des manipulations de l’ arbre qui constitue votre programme.
Je pense que Lisp a un BAISER à la programmation. Le fait que vous puissiez manipuler la syntaxe à l'aide de macros a conduit à un phénomène que Lisp a évolué de manière assez dynamique. Besoin d'une nouvelle fonctionnalité de langue comme - disons l'orientation de l'objet - il suffit d'écrire un système OOP avec des macros!
Alors que C a été prolongé 2 fois du rond-point avec des fonctionnalités OOP (C ++, Obj. C) Lisp a été prolongé plusieurs fois, il y a finalement eu un gagnant.
C'est une autre bizarrerie à propos de Lisp, il évolue (voir Clojure et Clojurescript pour une nouvelle Mutation intéressante de lisp).
Pour ses propriétés KISS, Lisps est privilégié comme langue d'enseignement par certains. Comme Fogus décrit dans son plan d'une langue éducative ( http://blog.fogus.me/2013/01/21/enfield-a-programming-language-designed-for-pedagogy/ )
la source