(source : pexels.com)Souvent, nous entendons, apprenons, et même utilisons des termes ou des phrases que nous ne comprenons pas complètement. Je trouve cela assez courant au sein de la communauté du développement logiciel, qu’il s’agisse des API Web RESTful, de la méthodologie Agile, de l’apprentissage automatique ou d’un autre terme. Ce n’est pas nécessairement une mauvaise chose, mais il est important de comprendre quand vous connaissez vraiment quelque chose et quand vous en connaissez juste le nom.
Pour moi, la programmation de systèmes est un de ces termes. Je voudrais essayer d’expliquer, en utilisant un langage simple, ce que cela signifie.
Avant de comprendre ce que la programmation de systèmes implique, nous devons d’abord comprendre ce qu’est un système. Les logiciels ont tendance à tomber dans l’un des deux camps, le logiciel système et le logiciel d’application.
Le logiciel système est un logiciel informatique conçu pour fournir une plate-forme à d’autres logiciels. Les exemples de logiciels système comprennent les systèmes d’exploitation, les logiciels de calcul scientifique, les moteurs de jeux, l’automatisation industrielle et les applications de logiciels en tant que service.
… Un tel logiciel n’est pas considéré comme un logiciel système lorsqu’il peut être désinstallé habituellement sans affecter le fonctionnement des autres logiciels.
– wikipedia.org
Le logiciel système est une plate-forme composée de programmes et de services du système d’exploitation (SE), y compris les paramètres et les préférences, les bibliothèques de fichiers et les fonctions utilisées pour les applications système. Le logiciel système comprend également les pilotes de périphériques qui font fonctionner le matériel informatique et les périphériques de base.
– techopedia.com
Le logiciel système fait référence aux fichiers et aux programmes qui constituent le système d’exploitation de votre ordinateur. Les fichiers système comprennent des bibliothèques de fonctions, des services système, des pilotes pour les imprimantes et autres matériels, des préférences système et d’autres fichiers de configuration. Les programmes qui font partie du logiciel système incluent les assembleurs, les compilateurs, les outils de gestion de fichiers, les utilitaires système et les débogueurs.
– techterms.com
La définition de Wikipédia est très vague sur ce qui est considéré comme un logiciel système tant qu’il fournit des services à d’autres applications. Cependant, les deux autres définitions se concentrent purement sur le système d’exploitation – pilotes, noyaux, bibliothèques et fonctions (pensez aux fichiers d’en-tête du noyau/libc et aux objets partagés). Cela implique une relation étroite avec le matériel. Si nous regardons un autre article de Wikipedia sur la programmation de systèmes, nous voyons:
La programmation de systèmes exige un grand degré de conscience du matériel.
L’article continue en impliquant qu’une partie essentielle de la programmation de systèmes est le besoin que les choses soient très rapides. Cela fait sens pourquoi nous aurions besoin de connaître beaucoup de choses sur le matériel. Il est également logique que la vitesse (performance) serait une partie essentielle de la programmation de systèmes si elle est une plate-forme à d’autres logiciels.
Si la partie la plus centrale de votre application (la « plate-forme » du logiciel système) est lente, alors toute l’application est lente. Pour de nombreuses applications, en particulier à l’échelle, ce serait un deal-breaker.
System Software in a Nutshell
Les citations ci-dessus et d’autres ressources m’ont conduit aux critères suivants pour définir le logiciel système:
- Fournit une plate-forme pour d’autres logiciels à construire sur.
- S’interface directement ou étroitement avec le matériel informatique afin d’obtenir les performances nécessaires et d’exposer des abstractions (en tant que partie de la plate-forme).
Qu’est-ce qu’un logiciel système et qu’est-ce qu’il n’est pas
Exemples de ce qu’est un logiciel système :
- Noyaux de systèmes d’exploitation
- Pilotes
- Hyperviseurs bare metal (par ex.g. Hyper-V et VM Ware ESXi)
- Compilateurs (qui produisent des binaires natifs) et débogueurs
Exemples de ce qui n’est pas un logiciel système :
- GUI Application de chat (Slack, Discord, etc)
- Application JavaScript basée sur le Web
- API de service Web
Vous remarquerez que si les API de service Web fournissent un service à d’autres logiciels, elles n’interagissent pas (typiquement) avec le matériel afin d’exposer des abstractions sur celui-ci. Cependant, il existe des applications qui se situent dans une zone grise intermédiaire. Celles qui me viennent à l’esprit sont les applications de calcul haute performance et les logiciels embarqués.
Les applications de calcul haute performance (HPC), telles que le trading en temps réel sur les bourses, n’exposent généralement pas de plateforme, mais il est courant pour elles d’écrire du code qui s’interface directement avec le matériel. Par exemple, elles contournent la pile réseau offerte par le noyau et implémentent leur propre pile réseau en communiquant directement avec les cartes réseau. De cette façon, nous pouvons voir comment les logiciels HPC partagent de nombreuses similitudes avec les logiciels systèmes, en interagissant directement avec le matériel afin de fournir les gains de performance nécessaires.
Le développement de logiciels embarqués partage également de nombreuses similitudes avec les logiciels systèmes en ce sens que le code est écrit pour s’interfacer directement avec le matériel. Cependant, toute abstraction fournie est généralement consommée par le même logiciel et ne pourrait pas être considérée comme une plate-forme.
Il est important de noter les applications qui partagent des similitudes avec notre définition du logiciel système puisque vous verrez probablement ces applications/emplois décrits dans ces termes (logiciel système, ingénieurs système, etc.)
Programmation de systèmes (+ langages)
Ayant défini les systèmes, nous pouvons maintenant définir la programmation de systèmes comme l’acte de construire des logiciels de systèmes en utilisant des langages de programmation de systèmes. Assez simple, n’est-ce pas ?
Bien il y a une chose sur laquelle nous avons sauté, les langages. Les gens parlent souvent des langages de programmation système d’une manière telle que « X est génial, il est rapide, compilé et c’est un langage de programmation système. » Mais tout le monde est-il sur la même longueur d’onde quant à ce qu’est un langage de programmation système ?
Vu nos définitions des systèmes, je définirais les critères d’un langage de programmation système comme suit :
- Compilé en binaire natif
- Peut être construit sans dépendance à d’autres logiciels (y compris un noyau)
- Caractéristiques de performance similaires à d’autres langages de programmation système
Disclaimer : C’est ma définition. Puisqu’il n’y a pas de critères établis, je tire une définition de ce qui a du sens pour moi étant donné le contexte dans lequel j’ai défini le logiciel système.
Compilation en binaire natif
Si un langage ne peut pas compiler en un exécutable directement interprétable par le CPU, alors il s’exécute, par définition, sur une plateforme (par exemple JVM, Ruby VM, Python VM, etc). Il peut y avoir quelques arguments à faire ici, mais pour la simplicité, je pense que c’est un critère approprié.
Pas de dépendances
L’argument est similaire à la compilation vers un binaire natif. Si le langage nécessite toujours la présence d’un autre logiciel pour s’exécuter, alors il fonctionne sur une plateforme. Un exemple de ceci est Go et sa bibliothèque standard incluse. Il a besoin du support du système d’exploitation pour effectuer des actions de base telles que l’allocation de mémoire, la création de threads (pour l’exécution des goroutines), pour son poller réseau intégré, et d’autres actions. Bien qu’il soit possible de réimplémenter ces fonctions de base, cela crée une barrière à l’utilisation dans ce contexte et il est facile d’imaginer pourquoi tous les langages, même ceux qui compilent en binaires statiques, ne sont pas destinés à être des langages de programmation système.
Caractéristiques de performance similaires
Celle-ci est un peu une échappatoire. Cependant, il s’agit de dire que dans le système des langages typiquement classés comme langages de programmation système, il ne devrait pas y avoir de grandes (ordre de grandeur) différences dans les caractéristiques de performance. Par caractéristiques, je fais explicitement référence à la vitesse d’exécution et à l’efficacité de la mémoire.
L’étalon-or de la comparaison est le C et/ou le C++, comme cela est souvent représenté dans les benchmarks comparatifs, qui mesurent la vitesse d’exécution en combien d’ordres de grandeur les langages sont plus lents que le C/C++.
Nommer quelques-uns
Les langages qui viennent immédiatement à l’esprit, étant donné la définition ci-dessus, sont le C et le C++. Mais il existe également des langages plus récents tels que Rust et Nim qui remplissent également cette niche. En fait, il existe déjà un système d’exploitation écrit entièrement en Rust (RedoxOS) et un noyau en Nim (nimkernel).
Parlons de Go
Je faisais précédemment allusion au fait que Go pourrait ne pas entrer dans la famille des « langages de programmation de systèmes ». Cependant, tout comme toutes les applications ne correspondent pas parfaitement aux logiciels d’application et aux logiciels système, les langages non plus.
Souvent, les gens appelleront Go un langage de programmation système et même golang.org est cité comme:
Go est un langage polyvalent conçu avec la programmation système à l’esprit.
Cependant, même cela n’est pas une affirmation catégorique que Go est un langage de programmation système, simplement qu’il est conçu avec cela à l’esprit. Je trouve qu’il se situe plutôt au milieu.
Alors que Go compile en binaires natifs, contient des concepts de bas niveau utiles (pointeurs bruts/non sûrs, types natifs tels que bytes et int32, et support de l’assemblage en ligne), et il est relativement performant ; il a encore quelques défis à surmonter. Go est livré avec un runtime et un garbage collector.
Un runtime signifie que le bootstrapping/overriding du runtime sera nécessaire pour fonctionner dans des environnements sans noyau. Cela va plus loin dans l’implémentation interne du langage, qui pourrait changer dans les futures versions. Les changements nécessitent un travail de bootstrapping supplémentaire au fur et à mesure de l’évolution du langage.
Un garbage collector (GC) signifie soit que Go est restreint dans quels domaines d’application il peut être utilisé, soit que le GC doit être désactivé et remplacé par une gestion manuelle de la mémoire. Dans le cas où le GC ne peut pas être remplacé, le domaine du temps réel (défini par des opérations qui doivent se terminer dans des limites de temps données et/ou la performance est mesurée en nano-secondes) ne pourrait pas risquer les temps de pause non déterministes d’un GC.
Les logiciels de systèmes distribués
Avec le discours croissant sur les systèmes distribués, et les applications comme Kubernetes devenant très populaires, nous obtenons d’entendre une flopée de nouveau vocabulaire que (si nous sommes honnêtes) la plupart d’entre nous ne comprennent pas complètement.
Jusqu’à présent, j’ai vu les termes programmation de systèmes et ingénieurs de systèmes utilisés dans des contextes où ce qu’ils voulaient vraiment dire était programmation de systèmes distribués et ingénieurs de systèmes distribués.
Nous avons défini les logiciels de systèmes, les langages de systèmes et la programmation de systèmes dans ce post. Cependant, lorsque nous parlons de systèmes distribués, la signification de système change. Et bien que je ne vais pas plonger dans les différences spécifiques ici (principalement parce que je dois encore mieux les saisir moi-même), il est important que nous fassions ces distinctions mentales et que nous utilisions un discours plus exact lorsque nous le pouvons pour éviter toute confusion à ceux qui apprennent encore cet espace.