<img src="/assets/crab_marigold_dalle_monet.webp" title="a painting of a crab made out of marigold flowers in the style of claude monet" alt="une crabe peint avec des grandes touches de jaune, orange, et des traces de rouge se répose sur un champs des fleurs violettes et encore jaunes sous un ciel bleu clair et blanc" style="width: 80%; display: block; margin-left: auto; margin-right: auto; border-radius: 8px; height: auto;" />

*« a painting of a crab made out of marigold flowers in the style of claude monet » fait avec [DALL·E](https://labs.openai.com/s/cUf8bKRUb4UcfcN3uJ0WLJlr)*

Quand j'ai dit à mes amis en informatique que j'ai commencé à écrire [Marigold](/marigold), un langage spécifique aux flux des données, quelques-uns étaient enthousiastes, d'autres perplexes. Écrire un nouveau langage de programmation pourrait sembler fastidieux : des technologies existantes partagées et maintenues par des communautés de développeurs sont déjà plus riches en fonctionnalités, mieux documentées et testées, et déjà connues par d'autres ingénieurs. Du coup, quel serait l'intérêt d'en écrire un nouveau ?

Des langages plus ou moins spécifiques sont créés pour simplifier moult domaines : n'importe quel langage de programmation pourrait être cité comme exemple.[^1] Si un langage existait qui faisait déjà le travail de SQL, ou Go, ou Rust, ces langages n'auraient jamais été écrits ni adoptés : les nouveaux langages sont écrits par besoin, car n'importe quel langage existant n'est approprié. La question est alors si Marigold répond à un besoin assez important pour mériter d'être développé ?

Souvent, les besoins sont commerciaux. Dans le domaine des logs et de l'observabilité, chez Datadog, le [langage de recherche des evenements](https://docs.datadoghq.com/fr/logs/explorer/search_syntax/) ([version archivée](https://web.archive.org/web/20221114064137/https://docs.datadoghq.com/fr/logs/explorer/search_syntax/)) facilite des requêtes qui seraient sinon complexes à écrire, avec divers homologues dans l'industrie, dont [LogQL](https://grafana.com/docs/loki/latest/logql/) de Grafana et [SPL](https://docs.splunk.com/Documentation/Splunk/latest/SearchReference/SQLtoSplunk) de Splunk. Bien que Datadog et ses concurrents auraient pu demander aux clients de faire des requêtes en JSON ou similaire, ils ont estimé qu'il était approprié d'écrire un langage adapté à leurs produits et leurs infrastructures.

Mais l'élan de Marigold n'était pas commercial. C'était technique. J'aime écrire en Rust, mais je trouve que l'écosystème async est toujours jeune. Les packages ne sont pas forcement stable ni facile à composer, et c'est difficile même pour des ingénieurs experimentés en Rust de raisonner comment de gérer les complexités des lifetimes et des types en async.

Par exemple, voici un bout de code qui vient de la documentation de [`csv-async`](https://docs.rs/csv-async/1.2.4/csv_async/index.html), un bon package pour opérer sur les fichiers CSV :

{%CODE_SNIPPET unfortunately_today_sometimes_async_rust_is_rough.rs}

Le code fonctionne bien, mais il est long. Plusieurs implémentations doit être écrites pour soutenir differents packages (tokio, serde, etc.).

Souvent en Rust, le coût pour écrire un projet qui lit et transforme des données en async ne vaut pas la peine. Cependant, les packages pour faire des serveurs en Rust async sont bien stables et performants, ce qui facilite la création des applications plus évolutives et rapides. À temps, l'écosysteme et le système de types de Rust async les rattraperont.

Mais pour l'instant, ils ne sont pas si mûr. Les grands projets en Rust ont la tendance d'éviter async si possible. Autres langages comme Go sont plus souvent selectionnés pour des projets très asynchrones. L'objectif de Marigold est de montrer qu'on peut utiliser l'efficacité de Rust async dans les pipelines des données sans la complexité qui fait hésiter autant d'ingénieurs.

Voici l'équivalent du bout de code de `csv-async` écrit en Marigold :

{%CODE_SNIPPET sometimes_domain_specific_languages_are_nicer.marigold}

Bien plus est internalisé dans la langue. En Marigold, [Serde](https://serde.rs/) est requis et compilé dès qu'on peut lire et écrire des fichiers (et pas sinon). Les implémentations spécifiques aux [tokio](tokio.rs) et [async-std](https://async.rs/), deux packages « runtime » qui gèrent le fonctionnement des programmes async Rust, ne sont pas réécrites dans chaque programme. D'ajouter la compression nécessite la modification de qu'une seule ligne de code. Marigold gère aussi le modèle de parallélisation (ou simultanéité, parmi le runtime disponible) qui [évite une classe d'erreur](/blog/2022/preventing_deadlocks_in_marigold) qui existe en Rust async. Marigold peut être utilisé pour faire une application, ou peut être [intégré](/marigold#marigold-in-rust) dans une application Rust existante.

Marigold est censé minimiser la complexité des opérations async en limitant ce qui est possible : Rust est un langage de programmation général et du coup très polyvalent. Marigold, en tant que langage spécifique aux flux des données, rend facile des opérations sur des flux (et uniquement ces opérations). La grammaire est dédiée aux transformations des flux, la dé•sérialisation est intégrée dans la déclaration des structs et enums, et les types sont adaptés aux particularités des programmes async.

Écrire un langage de programmation pourrait rendre facile un pattern de programmation qui serait sinon complexe. Cela :

- centralise le travail d'optimisation de son domaine pour bénéficier tous les programmes qui sont y écrits,
- évite des anti-patterns et bugs qui pourraient sinon se produire,
- produit des abstractions consistentes qui facilitent la compréhension, et
- diminue la quantité de code nécessaire à écrire, à tester, et à maintenir.

C'est loin d'être la seule façon de faciliter le travail d'un programmeur, mais cela mérite sa place dans la boîte à outils.

[^1]: Sauf les langages [exotiques](https://fr.wikipedia.org/wiki/Langage_de_programmation_exotique) (les langues qui n'étaient pas conçues d'être pratiques).