Votre code parle le langage métier ? Il est temps de créer un DSL en Java
\n\nImaginez : vous n'écrivez plus de ternes if-else et for, mais un code qui se lit comme une instruction pour un collègue. Vous n'y croyez pas ? À tort. Les langages dédiés (DSL) en Java ne sont pas de la magie, mais un outil pragmatique qui transforme une logique complexe en constructions élégantes.
Dans cet article, nous allons voir comment créer un DSL en Java qui rendra votre code plus propre et sa compréhension plus facile pour les analystes métier. Vous découvrirez la différence entre un DSL interne et un DSL externe, comment construire une fluent API et quand écrire votre propre parseur. C'est parti !
\n\nQu'est-ce qu'un DSL et pourquoi en tant que développeur Java ?
\n\nUn DSL (Domain-Specific Language) est un langage créé pour résoudre des problèmes dans un domaine spécifique. Contrairement à un langage de programmation généraliste (Java, Python), un DSL est étroitement spécialisé. Exemples concrets : SQL pour les bases de données, les expressions régulières pour le traitement de chaînes, HTML pour le web.
\n\nEn Java, un DSL est utilisé pour :
\n- \n
- Améliorer la lisibilité du code — la logique métier devient déclarative ; \n
- Réduire la barrière à l'entrée — les analystes peuvent modifier les règles sans connaissances approfondies de Java ; \n
- Diminuer le nombre d'erreurs — une syntaxe limitée empêche les bêtises ; \n
- Accélérer le développement — au lieu de milliers de lignes de code, une dizaine de commandes compréhensibles. \n
Important : créer un DSL en Java ne nécessite pas d'écrire un compilateur. Le plus souvent, nous utilisons des DSL internes — des surcouches de la syntaxe standard de Java.
\n\nDSL interne vs DSL externe : que choisir ?
\n\nDSL internes (Embedded DSL)
\nCe sont des DSL qui vivent à l'intérieur de Java. Vous utilisez des méthodes, des chaînes d'appels, des lambdas et la surcharge d'opérateurs (via des méthodes). Exemple : Java Stream API est un DSL interne pour le traitement de collections.
\n\nList<String> result = orders.stream()\n .filter(o -> o.getAmount() > 1000)\n .map(Order::getCustomerName)\n .collect(Collectors.toList());\n\nAvantages : pas besoin d'écrire un parseur, intégration étroite avec Java, débogage facile. Inconvénients : la syntaxe est limitée par les possibilités de Java.
\n\nDSL externes (External DSL)
\nCe sont des langages séparés avec leur propre syntaxe. Vous écrivez un parseur (par exemple avec ANTLR ou JavaCC) et un interpréteur. Exemple : SQL est un DSL externe que vous envoyez à la base de données.
\n\nAvantages : liberté totale de syntaxe, possibilité de faire très élégant. Inconvénients : nécessité d'écrire et de maintenir un parseur, débogage plus complexe.
\n\nPour la plupart des tâches, un DSL interne suffit. Les DSL externes se justifient lorsque le langage sera utilisé par de nombreuses personnes (comme SQL) ou lorsque la syntaxe est fondamentalement importante.
\n\nPratique : créons un DSL interne en Java pour un système de monitoring
\n\nSupposons que nous construisons un système de monitoring de serveurs. Au lieu d'écrire :
\n\nAlertRule rule = new AlertRule();\nrule.setMetric("cpu_usage");\nrule.setOperator(GREATER_THAN);\nrule.setThreshold(90.0);\nrule.setDuration(5, TimeUnit.MINUTES);\nrule.setAction(new SendEmailAction("admin@example.com"));\n\nNous voulons écrire :
\n\nAlertRule rule = AlertRuleBuilder\n .whenMetric("cpu_usage")\n .isGreaterThan(90.0)\n .forDuration(5, TimeUnit.MINUTES)\n .thenSendEmail("admin@example.com")\n .build();\n\nÉlégant, n'est-ce pas ? Implémentons cette fluent API.
\n\nÉtape 1 : Créons la classe AlertRule
\n\npublic class AlertRule {\n private String metric;\n private String operator;\n private double threshold;\n private long duration;\n private TimeUnit timeUnit;\n private String actionType;\n private String actionTarget;\n\n // Getters et setters omis par souci de concision\n}\n\n